Sign in to follow this  
Followers 0
Chris_F

LogLUV conversion now working

4 posts in this topic

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
0

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.

1

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

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0