如何使用3d查找表并将其像素值映射到图像?

问题描述 投票:1回答:2

我正在尝试将png颜色表应用于图像,但无法匹配从png到目标图像的像素。

颜色表是64 ^ 3的png

根据我对bigt图像中每个像素的理解,需要在颜色表中使用类似的值。这似乎将颜色限制为262144 = 64 x 64 x 64.但我不确定这是我得到的效果,结果是一个完全黑色的图像,这意味着没有价值,或非常奇怪的外观颜色。

这是我的代码


// The table is 64 x 64 x 64
float size = 64.0;

// This is the original image
// This function returns a pixel value inside a 3d space
//  and the `rgb` method will return a vector with the rgb values
vec3 source_image = sample(src_i, samplerCoord(src_i)).rgb;
// Here I take the pixel value of the image for the red channel
//  and multiply it by 64.0, then divide by 255.0 for the 8-bit image
float x = floor(floor(source_image.r * size)/255.0);
// The same thing for the green value on the y axis
float y = floor(floor(source_image.g * size)/255.0);

// Match a value from the image in the color table
vec3 color = sample(src_l, vec2(x, y)).rgb;

src_i.r = color.r;
src_i.g = color.g;
// The blue should be on the z axis, or the nth tile, so I think for this
//   case it will be easier to convert the color table to one long row
src_i.b = floor(floor(source_image.b * size)/255.0);

// The image is black

原始图像

预期结果

如果我乘以255(这似乎是正确的),那么我得到这个结果

float x = floor(source_image.r * 255.0);
float y = floor(source_image.g * 255.0);

如果你能指出数学有什么问题,我真的很感激

opengl image-processing glsl core-image
2个回答
1
投票

查找表不是64 * 64 * 64,而是8 * 8栅格中的64 * 64。由texture2D读取的颜色通道在[0,1]范围内,纹理坐标也在[0,1]范围内。

vec2 tiles    = vec2(8.0);
vec2 tileSize = vec2(64.0);

vec3 imageColor = texture(src_i, samplerCoord(src_i)).rgb;

图块的索引被编码为蓝色通道。有64个图块,第一个图块的索引为0,最后一个图块的索引为63.这意味着[0,1]范围内的蓝色通道必须映射到范围[0,63]:

float index = imageColor.b * (tiles.x * tiles.y - 1.0);

形成该线性瓦片索引,必须计算2维瓦片索引在[0,8]范围内:

vec2 tileIndex;
tileIndex.y = floor(index / tiles.x);
tileIndex.x = floor(index - tileIndex.y * tiles.x);

纹理缩小功能(GL_TEXTURE_MIN_FILTER)和纹理放大功能(GL_TEXTURE_MAG_FILTER应设置为GL_LINEAR。这会导致每个图块上的颜色可以进行线性插值。 每个图块都有64x64纹素。左下纹素的相对坐标是(0.5 / 64.0,0.5 / 64.0),右上纹素的相对坐标是(63.5 / 64.0,63.5 / 64.0)。 范围[0,1]中的红色和绿色通道必须映射到[0.5 / 64.0,63.5 / 64.0]范围:

vec2 tileUV = mix(0.5/tileSize, (tileSize-0.5)/tileSize, imageColor.rg);

最后,计算范围[0,1] c中颜色查找表的纹理坐标:

vec2 tableUV = tileIndex / tiles + tileUV / tiles;

解码片段着色器中颜色的最终代码可能如下所示:

vec2 tiles    = vec2(8.0, 8.0);
vec2 tileSize = vec2(64.0);

vec4 imageColor = texture(src_i, samplerCoord(src_i));

float index = imageColor.b * (tiles.x * tiles.y - 1.0);

vec2 tileIndex;
tileIndex.y = floor(index / tiles.x);
tileIndex.x = floor(index - tileIndex.y * tiles.x);

vec2 tileUV = mix(0.5/tileSize, (tileSize-0.5)/tileSize, imageColor.rg);

vec2 tableUV = tileIndex / tiles + tileUV / tiles;

vec3 lookUpColor = texture(src_l, tableUV).rgb;

通过在表的2个瓦片之间进行插值,可以进一步改进该算法。计算蓝色通道下面的图块索引和蓝色通道上方图块的索引:

float index     = imageColor.b * (tiles.x * tiles.y - 1.0);
float index_min = min(62.0, floor(index));
float index_max = index_min + 1.0;

最后使用mix函数在两个图块的颜色之间进行插值:

vec3 lookUpColor_1 = texture(src_l, tableUV_1).rgb;
vec3 lookUpColor_2 = texture(src_l, tableUV_1).rgb;
vec3 lookUpColor   = mix(lookUpColor_1, lookUpColor_2, index-index_min); 

最终代码:

vec2 tiles    = vec2(8.0, 8.0);
vec2 tileSize = vec2(64.0);

vec4 imageColor = texture(src_i, samplerCoord(src_i));

float index     = imageColor.b * (tiles.x * tiles.y - 1.0);
float index_min = min(62.0, floor(index));
float index_max = index_min + 1.0;

vec2 tileIndex_min;
tileIndex_min.y = floor(index_min / tiles.x);
tileIndex_min.x = floor(index_min - tileIndex_min.y * tiles.x);
vec2 tileIndex_max;
tileIndex_max.y = floor(index_max / tiles.x);
tileIndex_max.x = floor(index_max - tileIndex_max.y * tiles.x);

vec2 tileUV = mix(0.5/tileSize, (tileSize-0.5)/tileSize, imageColor.rg);

vec2 tableUV_1 = tileIndex_min / tiles + tileUV / tiles;
vec2 tableUV_2 = tileIndex_max / tiles + tileUV / tiles;

vec3 lookUpColor_1 = texture(src_l, tableUV_1).rgb;
vec3 lookUpColor_2 = texture(src_l, tableUV_2).rgb;
vec3 lookUpColor   = mix(lookUpColor_1, lookUpColor_2, index-index_min); 

查看比较原始图像(左上角)和颜色查找修改图像(右下角)的图像:


0
投票

在颜色表中找到相应位置的计算似乎是关闭的。我认为你必须首先在正确的“红绿色平面”(由输入的蓝色通道确定,考虑到由于地图中8x8布局引起的8步幅)中找到偏移量,然后才能找到将此偏移量添加到xy值的计算中。

但是,我建议你先检查一下内置的CIColorCube filter,因为它确实是你想要实现的。

© www.soinside.com 2019 - 2024. All rights reserved.