抖动算法小议3

如果将24Bit的真彩色图片转换为更低量化级别的图片的时候,其实还是使用Floyd-Steinberg算法,但是直接使用这个算法,效果并不好。原因在于,当颜色特别丰富的图片转换成低彩色的时候,即使用了误差传递,也会因为没有选取合适的颜色表示临近的颜色而产生较大的误差。上篇文章中我们说了24Bit的图片转换为15Bit的图片,颜色的选取,我们看到是直接将 r = r & 0xF8。实际上是直接把图像的低三位信息截去,然后把低三位的信息损失作为误差传递到周围的像素。对于15Bit这样的量化级别,这个方法还是可以接受的。但是对于24Bit的图像变为8Bit,这个算法会产生比较大的误差,并不是Floyd-Steinberg算法的问题,而是颜色选取的不合适,造成了即使有误差传递,图片的失真还是比较大。

 

这里介绍三种颜色选取的办法:

 


  • 流行色算法

流行色算法的基本思路是:对彩色图像中所有彩色出现的次数做统计分析,创建一个
数组用于表示颜色和颜色出现频率的统计直方图。按出现频率递减的次序对该直方图数组排序后,直方图中的前256 种颜色就是图像中出现次放最多(频率最大) 的256 种颜色,将它们作为调色板的颜色。该算法用统计直方图来分析颜色出现的频率,因此且称为彩色直方图统计算法。图像中其他的颜色采用在RGB 颜色空间中的最小距离原则映射到与其邻近的256种调色板颜色上。流行色算法实现较简单, 对颜色数量较小的图像可以产生较好的结果,但是该算法存在的主要缺陷是,图像中一些出现频率较低, 但对人眼的视觉效挺明显的信息将丢失。比如,图像中存在的高亮度斑点,由于出现的次数少, 很可能不能被算法选中,将被丢失。

 

  • 中位切分算法

 

中位切分算法的基本思路是:在RGB 彩色空间中, R 、G 、B 三基色对所对应于空间的三个坐标轴,将每坐标轴部量化为0 - 255 。对应于最暗(黑) , 255 对应于最亮,这样就形成了一个边长为256 的彩色立方体。所有可能的颜色都对与立方体内的一个点; 将彩色方体切分成256个小立方体,每个立方体中都包含相同数量的在图像中出现的颜色点;取出每个小立方体的中心点, 则这些点所表示的颜色就是我们所需要的最能代表图像颜色特征的256 种颜色。
中位切分算法是PauJ Heckbert在80 年代初提出来的,现被广泛应用于图像处理领域。该算法的缺点是涉及复杂的排序工作,而且内存开销较大。

 

  • 八叉树算法

1988 年,奥地利的M. Gervautz和W. Purgathofer 发表了一篇题为"A Simple Method for Color Quantization: Octree Quantization" 的论文,提出了种新的采用八义树数据结构的颜色量化算法,一般称为八叉树颜色量化算法。该算法的效率比中位切分算法高而且内存开销小。


八叉树颜色量化算法的基本思路是:将图像中使用的RGB 颜色值分布到层状的八叉树中。八叉树的深度可达九层,即根节点层加上分别表示8位的R、G 、B 值的每一位的八层节点。较低的节点层对应于较不重要的RGB 值的位(右边的位) , 因此, 为了提高效率和节省内存,可以去掉最低部的2 ~ 3 层, 这样不会对结果有太大的影响。叶节点编码存储像素的个数和R 、G 、B 颜色分量的值;而中间的节点组成了从最顶层到叶节点的路径。这是一种高效的存储方式,既可以存储图像中出现的颜色和其出现的次数,也不会浪费内存来存储图像中不出现的颜色。


扫描图像的所有像素, 每遇到种新的颜色就将它放入八叉树中,并创建一个叶节点。图像扫描完后,如果叶子节点的数量大于调色板所需的颜色数时, 就需要将有些叶子节点合并到其上一层节点中, 并将该节点转化成叶节点, 在其中存储颜色且其出现的次数。这样,减少叶节点的数量,直到叶节点的数量等于或小于调色板所需的颜色数。如果叶节点的数量小于或等于调色板所需的颜色数,则可以遍历八叉树,将叶子节点的颜色填入调色饭的颜色表。

 

 

我个人比较推荐八叉树算法,但是还有比八叉树更简单的算法,那就是固定色表的算法。大致思路是:

选取一个比较好的色表为固定色表。然后不管什么图像,每个颜色选取这个色表中值最接近的颜色。这样势必会产生误差,这个误差就可以使用Floyd-Steinberg算法,传递到周围像素,效果也比较好,速度也很快。

 

这个算法的关键就在于如何快速的寻找到色表中最接近的颜色。晕太晚了,下次接着侃……

你可能感兴趣的:(数据结构,算法,工作,存储,图像处理)