Sign in to follow this  
Chris_F

LogLUV conversion now working

Recommended Posts

Chris_F    3030

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
Marcel Stockli    167

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

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