我们的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转换?
答案 0 :(得分:1)
另一种方法是使用图形硬件,即“通用GPU计算”。有一些不同的工具,例如OpenGL GLSL,OpenCL,CUDA ......与CPU解决方案相比,您应该获得大约100倍以上的令人难以置信的加速。
最“兼容”的解决方案是使用OpenGL和一个特殊的片段着色器,您可以使用它来执行计算。这意味着:将您的输入图像作为纹理上传到GPU,使用特殊着色器程序在(目标)帧缓冲区中渲染它,该程序将您的RGB数据转换为Lab(或者它也可以使用查找表,但大多数浮动计算在GPU上比表/纹理查找更快,所以我们不会在这里这样做。)
首先,将RGB到Lab转换功能移植到GLSL。它应该适用于浮点数,所以如果你在原始转换中使用了整数值,那就去除它们。 OpenGL使用“钳位”值,即0.0
和1.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位),并且两个颜色空间分别存储在名称为SourceColor
和TargetColor
的结构中,并且您具有转换函数像这样:
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[]
进行分配并将其存储在智能指针中。)