Tre*_*or 13 algorithm image-processing gif
我是第一次玩计算机图形编程.我想将RGB(24位)图像转换为索引调色板(8位)图像(如GIF).我最初的想法是使用k-means(k = 256).
如何为给定图像选择最佳调色板?这对我来说是一次学习经历,所以我更喜欢源代码的概述型答案.
编辑:抖动目前是偏离主题的.我只是提到"简单"的颜色转换,心理视觉/感知模型; 色彩空间目前也是偏离主题的,虽然在色彩空间之间移动是让我在第一时间思考这个问题的原因:)
人们提供的参考链接很好,这个问题有几个解决方案,但是由于我最近一直在研究这个问题(完全不了解其他人如何解决它),我用简单的英语提供了我的方法:
首先,认识到(人类感知的)颜色是三维的.这基本上是因为人眼有3种不同的受体:红色,绿色和蓝色.同样,您的显示器具有红色,绿色和蓝色像素元素.可以使用其他表示,例如色调,饱和度,亮度(HSL),但基本上所有表示都是三维的.
这意味着RGB颜色空间是一个立方体,具有红色,绿色和蓝色轴.从24位源图像,此立方体在每个轴上具有256个离散级别.将图像缩小到8位的简单方法是简单地降低每轴的电平.例如,通过获取红色和绿色值的高3位以及蓝色值的高2位,可以轻松创建8x8x4立方体调色板,其中8个级别用于红色和绿色,4个级别用于蓝色.这很容易实现,但有几个缺点.在生成的256色调色板中,根本不会使用许多条目.如果图像具有使用非常微妙的颜色偏移的细节,则当颜色捕捉到相同的调色板条目时,这些偏移将消失.
自适应调色板方法不仅要考虑图像中的平均/共同颜色,还要考虑颜色空间的哪些区域具有最大的方差.也就是说,具有数千个浅绿色调的图像需要与具有完全相同的浅绿色的数千个像素的图像不同的调色板,因为后者理想地使用该颜色的单个调色板条目.
为此,我采用了一种方法,产生256个桶,每个桶包含完全相同数量的不同值.因此,如果原始图像包含256000个不同的24位颜色,则该算法产生256个桶,每个桶包含1000个原始值.这是通过使用存在的不同值的中值(不是均值)对颜色空间进行二进制空间划分来实现的.
在英语中,这意味着我们首先将整个颜色立方体划分为半数像素,其中红色值小于中值,而半数大于中值红色值.然后,将每个结果的一半除以绿色值,然后除以蓝色,依此类推.每个分割需要一个比特来指示像素的较低或较高的一半.在8次分裂之后,方差实际上被分成了颜色空间中256个同等重要的聚类.
在伪代码中:
// count distinct 24-bit colors from the source image
// to minimize resources, an array of arrays is used
paletteRoot = {colors: [ [color0,count],[color1,count], ...]} // root node has all values
for (i=0; i<8; i++) {
colorPlane = i%3 // red,green,blue,red,green,blue,red,green
nodes = leafNodes(paletteRoot) // on first pass, this is just the root itself
for (node in nodes) {
node.colors.sort(colorPlane) // sort by red, green, or blue
node.lo = { colors: node.colors[0..node.colors.length/2] }
node.hi = { colors: node.colors[node.colors.length/2..node.colors.length] }
delete node.colors // free up space! otherwise will explode memory
node.splitColor = node.hi.colors[0] // remember the median color used to partition
node.colorPlane = colorPlane // remember which color this node split on
}
}
Run Code Online (Sandbox Code Playgroud)
您现在有256个叶子节点,每个叶子节点包含与原始图像相同数量的不同颜色,在颜色立方体中空间聚类.要为每个节点分配单一颜色,请使用颜色计数查找加权平均值.加权是一种改进感知颜色匹配的优化,但并不重要.确保独立平均每个颜色通道.结果非常好.请注意,蓝色被划分为红色和绿色一次是有意的,因为眼睛中的蓝色受体对红色和绿色的细微变化不太敏感.
还有其他优化可能.通过使用HSL,您可以将更高的量化放在亮度维度而不是蓝色.此外,上述算法将略微降低整体动态范围(因为它最终平均颜色值),因此动态扩展生成的调色板是另一种可能性.
编辑: 更新为支持 256 种颜色的调色板
如果您需要最简单的方法,那么我建议基于直方图的方法:
计算R/G/B通道的直方图
定义 4 个强度范围
对于强度范围内的每个通道
将直方图分成 4 个相等的部分
对于每个直方图部分
提取该部分的最频繁值
现在您将拥有 4*4^3=256 种颜色的调色板。将像素分配给调色板颜色时,只需计算像素的平均强度即可查看必须使用的强度区域。之后,只需将 64 种颜色的强度区域之一映射到像素值即可。
祝你好运。