CLUT-from-images

generate color lookup table from origin image and result images

颜色查找表(Color LookUp Table)用蓝色作为索引, 用来分块, 每个小块的蓝色是固定的, 其中x轴是红色, y轴是绿色

CLUT原理

在这里我们以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耗时更长

18bit色深

RGB每个通道使用6bit来表示颜色, 每个通道的集合应该是[0, 255], 但是2^6 = 64, 范围就是[0, 64] 所以最后的结果需要乘4来变换到[0, 255]

枚举所有颜色的查找表

这是一个8x8的查找表, 总共有64个block, 所以范围是[0, 64], 又因为每个block中蓝色是固定的, 所以蓝色可以完全表示
其中每个block中从左到右是红色, 取值范围是[0, 64], 从上到下是绿色取值范围是[0, 64], 这样所有的颜色就都可以表示了

查找表

1
2
3
4
5
6
7
8
9
10
11
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 对应查找表内的颜色 需使用如下方法:

  1. 分离色彩C的RGB通道为(Cr, Cg, Cb)
  2. 通过Cb计算block的位置, y = Cb // 4 // 8 x = Cb % 8
  3. block位置确定之后就在里面通过Cr, Cb计算具体的点P
  4. 取出点P的RGB通道(Pr, Pg, Pb)
  5. 目标的RGB值就是(Pr, Pg, Pb)

新查找表生成方法

因为这就是一个查表过程, 所以得到新滤镜的方法就很简单了

  1. 准备一张完整的查找表图片, 这里称为identity
  2. 然后用滤镜软件处理identity, 得到一张新的图片D

D就是我们新的查找表了, 因为本质上我们是用原集合(identity), 经过函数f(滤镜软件x)得到了新的集合, 所以就可以直接使用D了

因为identity包含了所有可能的颜色, 并且都在对应的位置上, 所以目标查找表B上面的位置都是正确的, 只要取出对应的RGB通道就是滤镜后的效果了

总结

其实颜色查找表是很聪明的一个构造方法, 把原色彩的RGB分别作为坐标轴, 对应像素的内容才是真正的值

色彩查找表构造Demo