generate color lookup table from origin image and result images
颜色查找表(Color LookUp Table)用蓝色作为索引, 用来分块, 每个小块的蓝色是固定的, 其中x轴是红色, y轴是绿色
在这里我们以18bit色作为样例说明, 使用18bit色深主要是出于存储空间考虑, 18bit = 2^18 = 262144
就是通常说的26万色, 这26万色可以分解成2^18 = (2^9) ^ 2 = 512 * 512
, 所以通常CLUT也是一个512 x 512的图片
从图片大小来看宽高512的总像素数是262144, 假设我们的图片是24位色--也就是每个通道用8bit, 总共3byte, 那么最后图片大小是262144 * 3 = 786432
也就是768KB.
同样的如果使用24位色的话就需要使用宽高4096的图片, 算下来最后图片大小有48MB
虽然图片精度下降了一些, 但是带来的空间节省却是巨大的, 把48MB的图片加载进GPU也肯定比768KB耗时更长
RGB每个通道使用6bit来表示颜色, 每个通道的集合应该是[0, 255]
, 但是2^6 = 64
, 范围就是[0, 64]
所以最后的结果需要乘4来变换到[0, 255]
这是一个8x8的查找表, 总共有64个block, 所以范围是[0, 64]
, 又因为每个block中蓝色是固定的, 所以蓝色可以完全表示
其中每个block中从左到右是红色, 取值范围是[0, 64]
, 从上到下是绿色取值范围是[0, 64]
, 这样所有的颜色就都可以表示了
img = np.zeros((512, 512, 3), dtype=np.uint8)
for by in range(8): # block y索引
for bx in range(8): # block x索引
for g in range(64): # block内 y索引
for r in range(64): # block内 x索引
x = r + bx * 64 # 整张图的 x坐标
y = g + by * 64 # 整张图的 y坐标
img[y][x][0] = int(r * 255.0 / 63.0 + 0.5)
img[y][x][1] = int(g * 255.0 / 63.0 + 0.5)
img[y][x][2] = int((bx + by * 8.0) * 255.0 / 63.0 + 0.5)
# 每个点的(r, g, b)计算方法, 可以看出每个块内的蓝色都是一定的
我们有了查找表之后要得到色彩C 对应查找表内的颜色 需使用如下方法:
- 分离色彩C的RGB通道为(Cr, Cg, Cb)
- 通过Cb计算block的位置,
y = Cb // 4 // 8
x = Cb % 8
- block位置确定之后就在里面通过Cr, Cb计算具体的点P
- 取出点P的RGB通道(Pr, Pg, Pb)
- 目标的RGB值就是(Pr, Pg, Pb)
因为这就是一个查表过程, 所以得到新滤镜的方法就很简单了
- 准备一张完整的查找表图片, 这里称为identity
- 然后用滤镜软件处理identity, 得到一张新的图片D
D就是我们新的查找表了, 因为本质上我们是用原集合(identity), 经过函数f(滤镜软件x)得到了新的集合, 所以就可以直接使用D了
因为identity包含了所有可能的颜色, 并且都在对应的位置上, 所以目标查找表B上面的位置都是正确的, 只要取出对应的RGB通道就是滤镜后的效果了
其实颜色查找表是很聪明的一个构造方法, 把原色彩的RGB分别作为坐标轴, 对应像素的内容才是真正的值