按照图像处理--GIF和静态图的叠加和图像处理--GIF和静态图叠加(二)的思路,已经可以实现GIF和静态图的叠加了,但是我们已经知道,GIF最高支持8位256色,那么如果原图是真彩色的,则在生成最终效果图时,就涉及到真彩色到256的降色。真彩色是24位的,有2^24种颜色,每个像素用3个字节标识一个颜色,R、G、B各占一个字节,而256色每个像素只用一个字节从调色板中索引一种颜色,调色板最多有256种颜色。将2^24种颜色降为256种颜色,降色的过程被成为色彩量化。可想而知,色彩空间的减小必然造成大量的色彩丢失,进而造成一些像素找不到原来的颜色值,那么对于这种像素点,就需要给它找一个和原来颜色最接近的新颜色,记录新颜色在256色调色板中的索引。
256的调色板有两种,标准调色板和由当前图片得到的自定义调色板。后者的意思是,使用将被量化的图片定制出一个调色板,这个调色板由将被量化图片中使用频率最高的256种颜色组成,这样可以在量化时,使尽可能多的像素在调色板中准确的找到和量化前该像素颜色值完全一样的颜色,结果就是量化后色彩丢失最少。
所以,一个好的色彩量化过程分两步:1、根据图片定制调色板;2、遍历像素,对于每一个像素,从调色板中找最接近的颜色,记录该颜色索引。
那么如何定制一个调色板呢?
最简单的方式也最容易想到:
1、创建一个链表,每一个节点记录颜色的RGB值,以及该颜色在原图像素矩阵中出现的次数Count。
2、遍历原图(真彩色)的像素矩阵,对于每一个像素,如果它的颜色在链表中存在,则把该节点中Count加1,如果它的颜色在链表中不存在,则新建该颜色节点。
3、遍历完后,按照Count对链表堆排序,得到前256个节点。这256个节点中的RGB值就是定制的调色板了。
这种方式好简单,但实在是太坑爹了...顺序访问的效率可想而知。
于是有了第二种方法:八叉树方式建立调色板。
比如颜色A,它的RGB为F361A4,在三维色彩空间,使用坐标R:F3、G:61、B:A4可以唯一确定这个颜色。怎么样才能将颜色空间从三维映射到一维呢?因为这样就是线性的了。方法还是有的,对于每一个颜色值,将RGB分量的每一个Bit位,可以按照下面的公式操作Result = R | (G<<1) | (B<<1) ,则Result可以看作是一个长度为8的数组,每个元素值在0~8之间,得到如下表格:
R | 0xF3 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 |
G | 0x61 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
B | 0xA4 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
Result | 5 | 3 | 7 | 1 | 0 | 4 | 1 | 3 |
八叉树最多有8层,每一层有8个节点,那么一个满八叉树的叶子节点就有8^8共2^24个节点。这些恰好是真彩色的颜色总数,也就是说一个满八叉树的叶子节点可以一一对应到真彩色的每一种颜色。经过上面颜色空间三维到一维的映射,Result值就可以通过这棵树找到属于自己的叶子节点,也就是自己的颜色。而树的插入、查找速度都是很快的,所以用八叉树作为数据结果建立调色板,是一种不错的选择。
在实际操作生成256色调色板的过程中,先被读入的256种颜色作为初始化颜色建立起树,然后一旦有新的颜色出现时,就要进行颜色归并,保证任何时刻都不会超过256种颜色。这样可以降低开销。
问题是超过256时怎么归并呢?只有合理归并,才能更好的保证图片质量,下面是几个归并条件:
( 1) 深度最大的子树首先选择。在色彩八叉树中, 深度为8 的叶子结点表示了色彩空间中
一个准确颜色, 非叶结点代表了色彩空间的子空间, 非叶结点深度与其代表颜色区间大小成
反比, 与其表示的颜色准确度成正比, 在最大深度子树上归并, 相当于在最小颜色子空间上
做归并, 所代表的色度空间越小, 归并的颜色越相近, 代表色失真度越小, 色彩近似优化程
度越高。
( 2) 深度相同频度最小先归约。按频度序列思想, 在多个深度相同的同层可归约点中, 应
先归并当前代表最少色素数目的结点。这样使得使用频率低的用较接近的代表色填充, 而频
率高结点未被归并, 则用最接近的色彩填充, 这样, 最大区域将填上最小误差的色彩, 以保
持原始图像上细微差别。
( 3) 取被归并子树均值作代表色, 将所有被归并结点色彩与频度求和取均值作为代表色,
使代表色尽可能靠近频度高的色彩, 增强代表色的逼真度。
参考论文《基于八叉树结构的色彩量化算法》
经过上面的处理,就可以得到定制后的调色板,使用该调色板进行量化,可以得到比较好的效果。
量化就比较简单了,按照三维空间两点之间距离的方式,对于原图中的每一个像素点M(R、G、B),遍历调色板中的256种颜色,对于调色板颜色N(r、g、b),机选MN的距离d,找到可以使距离d最小的N,则记录N的索引即可。如果d为0,则说明,该颜色在量化中没有被去掉,可想而知,这个颜色在原图中出现的频率是很高的。
下面贴几张图比较下使用调准调色板和定制调色板量化效果:
原图:
标准调色板量化后:
定制调色板量化后:
最后说明一下:如果直接使用GDI+读入真彩色图,再保存成256色图gif,效果是这样的:
可以看到效果还不错,但是整体上有种“浮雕”的感觉,有很多颗粒,称为抖动。因为GDI+使用了标准调色板+误差扩散,误差扩散下一次再说吧。