生成用于sRGB到CIELAB颜色空间转换的3DLUT(.3dl文件)

时间:2013-06-19 10:25:30

标签: c++ image-processing

我们的API中已经有一个高度优化的类来读取3D Lut(Nuke格式)文件并将变换应用于图像。因此,不是使用复杂的公式逐像素地迭代并将RGB值转换为Lab(RGB-> XYZ-> Lab)值,我认为如果我为RGB生成查找表会更好(或者XYZ到LAB)转换。这可能吗?

我理解3D Lut如何适用于从RGB到RGB的转换,但我对RGB到Lab感到困惑,因为L,a和b具有不同的范围。任何提示?

修改

你能解释一下Lut将如何运作吗? 下面是一个解释:link

例如,以下是我对RGB-gt; RGB变换的3D Lut的理解: 一个示例Nuke 3dl Lut文件:

0    64   128   192   256   320   384   448   512   576   640   704   768   832   896   960  1023 
R, G, B 
0, 0, 0 
0, 0, 64 
0, 0, 128 
0, 0, 192 
0, 0, 256 
.
.
.
0, 64, 0
0, 64, 64
0, 64, 128
.
.

此处,不是为源10位RGB值生成1024 * 1024 * 1024表,而是将每个R,G和B范围量化为17个值,从而生成4913行表。   第一行给出了可能的量化值(我认为这里只有长度和最大值)。现在假设,如果源RGB值是(20,20,190),则输出将是行#4(0,0,192)(使用一些插值技术)。那是对的吗? 这个用于10位源,您可以通过将范围从0更改为255来生成8位的熟悉的源?

同样,您将如何进行sRGB-> Lab转换?

2 个答案:

答案 0 :(得分:1)

另一种方法是使用图形硬件,即“通用GPU计算”。有一些不同的工具,例如OpenGL GLSL,OpenCL,CUDA ......与CPU解决方案相比,您应该获得大约100倍以上的令人难以置信的加速。

最“兼容”的解决方案是使用OpenGL和一个特殊的片段着色器,您可以使用它来执行计算。这意味着:将您的输入图像作为纹理上传到GPU,使用特殊着色器程序在(目标)帧缓冲区中渲染它,该程序将您的RGB数据转换为Lab(或者它也可以使用查找表,但大多数浮动计算在GPU上比表/纹理查找更快,所以我们不会在这里这样做。)

首先,将RGB到Lab转换功能移植到GLSL。它应该适用于浮点数,所以如果你在原始转换中使用了整数值,那就去除它们。 OpenGL使用“钳位”值,即0.01.0之间的浮点值。它看起来像这样:

vec3 rgbToLab(vec3 rgb) {
    vec3 lab = ...;
    return lab;
}

然后,编写着色器的其余部分,它将获取(RGB)纹理的像素,调用转换函数并将像素写入颜色输出变量(不要忘记alpha通道):

uniform sampler2D texture;
varying vec2 texCoord;

void main() {
    vec3 rgb = texture2D(texture, texCoord).rgb;
    gl_FragColor = vec4(lab, 1.0);
}

相应的顶点着色器应在左下方写入texCoord(0,0),在整个屏幕(帧缓冲区)的目标四元组右上角写入(1,1)

最后,通过在与图像大小相同的帧缓冲区上渲染,在应用程序中使用此着色器程序。渲染填充整个区域的四边形(不设置任何变换,只需从2D顶点(-1,-1)渲染四边形到(1,1))。将统一值texture设置为您作为纹理上载的RGB图像。然后,从设备中读回帧缓冲区,希望在Lab色彩空间中包含您的图像。

答案 1 :(得分:0)

假设您的源颜色空间是三个字节(RGB,每个8位),并且两个颜色空间分别存储在名称为SourceColorTargetColor的结构中,并且您具有转换函数像这样:

TargetColor convert(SourceColor color) {
    return ...
}

然后你可以创建一个这样的表:

TargetColor table[256][256][256]; // 16M * sizeof(TargetColor) => put on heap!

for (int r, r < 256; ++r)
  for (int g, g < 256; ++g)
    for (int b, b < 256; ++b)
      table[r][g][b] = convert({r, g, b}); // (construct SourceColor from r,g,b)

然后,对于实际的图像转换,使用替代转换函数(我建议您编写一个图像转换类,在其构造函数中使用函数指针/ std::function,因此它很容易交换):< / p>

TargetColor convertUsingTable(SourceColor source) {
    return table[source.r][source.g][source.b];
}

请注意,空间消耗为16M * sizeof(TargetColor)(假设Lab为32位,这将是64MBytes),因此表应该是堆分配的(它可以存储在类中如果你的类将存在于堆中,但最好在构造函数中使用new[]进行分配并将其存储在智能指针中。)