Sign in to follow this  

LogLUV conversion now working

This topic is 1839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I wrote a small program to test the conversion from HDR RGB to LogLUV. It takes a HDR image (.EXR) and then converts the floating point RGB pixel value to an 32-bit LogLUV value. It then converts it back to floating point RGB and saves the image to a new EXR file.

 

For some reason, I know not why, it is not working.

 

[source]

#include <iostream>
#include <FreeImage.h>
#include <glm/glm.hpp>

using namespace glm;

FIBITMAP* LoadImage(const char* filename)
{
    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
    fif = FreeImage_GetFileType(filename);
    if(fif == FIF_UNKNOWN)
    {
        fif = FreeImage_GetFIFFromFilename(filename);
    }
    if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif))
    {
        return FreeImage_Load(fif, filename);
    }
    return NULL;
}

// M matrix, for encoding
const mat3 M(
    0.2209, 0.3390, 0.4184,
    0.1138, 0.6780, 0.7319,
    0.0102, 0.1130, 0.2969
);

// Inverse M matrix, for decoding
const mat3 InverseM(
    6.0014, -2.7008, -1.7996,
    -1.3320,  3.1029, -5.7721,
    0.3008, -1.0882,  5.6268
);

vec4 LogLuvEncode(vec3 vRGB)
{
    vec4 vResult;
    vec3 Xp_Y_XYZp = vRGB * M;
    Xp_Y_XYZp = glm::max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));
    vResult.x = Xp_Y_XYZp.x / Xp_Y_XYZp.z;
    vResult.y = Xp_Y_XYZp.y / Xp_Y_XYZp.z;
    float Le = 2 * glm::log2(Xp_Y_XYZp.y) + 127;
    vResult.w = glm::fract(Le);
    vResult.z = (Le - (glm::floor(vResult.w*255.0f))/255.0f)/255.0f;
    return vResult;
}

vec3 LogLuvDecode(vec4 vLogLuv)
{
    float Le = vLogLuv.z * 255 + vLogLuv.w;
    vec3 Xp_Y_XYZp;
    Xp_Y_XYZp.y = glm::exp2((Le - 127) / 2);
    Xp_Y_XYZp.z = Xp_Y_XYZp.y / vLogLuv.y;
    Xp_Y_XYZp.x = vLogLuv.x * Xp_Y_XYZp.z;
    vec3 vRGB = Xp_Y_XYZp * InverseM;
    return glm::max(vRGB, 0);
}

int main()
{
    FIBITMAP* dib = LoadImage("in.exr");

    int width = FreeImage_GetWidth(dib);
    int height = FreeImage_GetHeight(dib);

    FIBITMAP* dib2 = FreeImage_AllocateT(FIT_RGBF, width, height);

    for(int y = 0; y < height; y++)
    {
        FIRGBF* InputPixel = (FIRGBF*)FreeImage_GetScanLine(dib, y);
        FIRGBF* OutputPixel = (FIRGBF*)FreeImage_GetScanLine(dib2, y);

        for(int x = 0; x < width; x++)
        {
            vec3 input(InputPixel[x].red, InputPixel[x].green, InputPixel[x].blue);

            vec4 enc = LogLuvEncode(input);

            BYTE r = enc.r * 255.0;
            BYTE g = enc.g * 255.0;
            BYTE b = enc.b * 255.0;
            BYTE a = enc.a * 255.0;

            vec3 dec = LogLuvDecode(vec4(r,g,b,a) / 255.0);

            OutputPixel[x].red = dec.r;
            OutputPixel[x].green = dec.g;
            OutputPixel[x].blue = dec.b;
        }
    }

    FreeImage_Save(FIF_EXR, dib2, "out.exr");
}

[/source]

 

This doesn't work.

 

[source]

#include <iostream>
#include <FreeImage.h>
#include <glm/glm.hpp>

using namespace glm;

FIBITMAP* LoadImage(const char* filename)
{
    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
    fif = FreeImage_GetFileType(filename);
    if(fif == FIF_UNKNOWN)
    {
        fif = FreeImage_GetFIFFromFilename(filename);
    }
    if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif))
    {
        return FreeImage_Load(fif, filename);
    }
    return NULL;
}

// M matrix, for encoding
const mat3 M(
    0.2209, 0.3390, 0.4184,
    0.1138, 0.6780, 0.7319,
    0.0102, 0.1130, 0.2969
);

// Inverse M matrix, for decoding
const mat3 InverseM(
    6.0014, -2.7008, -1.7996,
    -1.3320,  3.1029, -5.7721,
    0.3008, -1.0882,  5.6268
);

vec4 LogLuvEncode(vec3 vRGB)
{
    vec4 vResult;
    vec3 Xp_Y_XYZp = vRGB * M;
    Xp_Y_XYZp = glm::max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));
    vResult.x = Xp_Y_XYZp.x / Xp_Y_XYZp.z;
    vResult.y = Xp_Y_XYZp.y / Xp_Y_XYZp.z;
    float Le = 2 * glm::log2(Xp_Y_XYZp.y) + 127;
    vResult.w = glm::fract(Le);
    vResult.z = (Le - (glm::floor(vResult.w*255.0f))/255.0f)/255.0f;
    return vResult;
}

vec3 LogLuvDecode(vec4 vLogLuv)
{
    float Le = vLogLuv.z * 255 + vLogLuv.w;
    vec3 Xp_Y_XYZp;
    Xp_Y_XYZp.y = glm::exp2((Le - 127) / 2);
    Xp_Y_XYZp.z = Xp_Y_XYZp.y / vLogLuv.y;
    Xp_Y_XYZp.x = vLogLuv.x * Xp_Y_XYZp.z;
    vec3 vRGB = Xp_Y_XYZp * InverseM;
    return glm::max(vRGB, 0);
}

int main()
{
    FIBITMAP* dib = LoadImage("in.exr");

    int width = FreeImage_GetWidth(dib);
    int height = FreeImage_GetHeight(dib);

    FIBITMAP* dib2 = FreeImage_AllocateT(FIT_RGBF, width, height);

    for(int y = 0; y < height; y++)
    {
        FIRGBF* InputPixel = (FIRGBF*)FreeImage_GetScanLine(dib, y);
        FIRGBF* OutputPixel = (FIRGBF*)FreeImage_GetScanLine(dib2, y);

        for(int x = 0; x < width; x++)
        {
            vec3 input(InputPixel[x].red, InputPixel[x].green, InputPixel[x].blue);

            vec4 enc = LogLuvEncode(input);

            vec3 dec = LogLuvDecode(enc);

            OutputPixel[x].red = dec.r;
            OutputPixel[x].green = dec.g;
            OutputPixel[x].blue = dec.b;
        }
    }

    FreeImage_Save(FIF_EXR, dib2, "out.exr");
}

[/source]

 

However, this does.

Edited by Chris_F

Share this post


Link to post
Share on other sites

Did you checked the matrix order? (row major, column major). Your matrix constructor should have the same order than the HLSL Matrix constructor because the code you are usin, originally was HLSL. The same with the vector-matrix multiplication.

Share this post


Link to post
Share on other sites

Thanks, that was the problem. This isn't the first time matrix order has done this to me. rolleyes.gif

Share this post


Link to post
Share on other sites
Sign in to follow this