1

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

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

编辑:

你能解释一下Lut是如何工作的吗?这里有一个解释:链接

例如,下面是我对 RGB->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 转换?

4

2 回答 2

1

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

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

首先,将您的 RGB 到 Lab 转换功能移植到 GLSL。它应该适用于浮点数,因此如果您在原始转换中使用整数值,请摆脱它们。OpenGL 使用“clamp”值,即介于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 颜色空间中的图像。

于 2013-06-19T11:08:45.000 回答
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在其构造函数中采用函数指针 /,因此它很容易交换):

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

请注意,空间消耗是(假设这将是16M * sizeof(TargetColor)32 位),因此表应该是堆分配的(如果您的类要在堆上运行,它可以存储在类中,但最好在构造函数并将其存储在智能指针中)。Lab64MBytesnew[]

于 2013-06-19T10:49:12.527 回答