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.