图像处理

来源:互联网 发布:老鹰vs骑士数据 编辑:程序博客网 时间:2024/06/04 18:34

Dither的原理


讲抖动算法,一般都会提到图案法。

图案法 (patterning) 是指灰度可以用一定比例的黑白点组成的区域表示,从而达到整体图象的灰度感。黑白点的位置选择称为图案化。

先岔开说说分辨率,计算机显示器,打印机,扫描仪等设备的一个重要指标就是分辨率,单位是 dpi(dot per inch) ,即每英寸点数,点数越多,分辨率就越高,图象就越清晰。让我们来计算一下,计算机显示器的分辨率有多高。设显示器为 15 英寸 ( 指对角线长度 ) ,最多显示 1280 × 1024 个点。因为宽高比为 4 : 3 ,所以宽有 12 英寸 ,高有 9 英寸 ,则该显示器的水平分辨率为 106dpi ,垂直分辨率为 113.8dpi 。一般的激光打印机的分辨率有 300dpi × 300dpi , 600dpi × 600dpi , 720dpi × 720dpi 。所以打出来的图象要比计算机显示出来的清晰的多。扫描仪的分辨率要高一些,数码相机的分辨率更高。

言归正传,前面讲了,图案化使用图案来表示象素的灰度,那么我们来做一道计算题。假设有一幅 240 × 180 × 8bit 的灰度图,当用分辨率为 300dpi × 300dpi 的激光打印机将其打印到 12.8 × 9.6 英寸 的纸上时,每个象素的图案有多大?

这道题很简单,这张纸最多可以打 (300 × 12.8) × (300 × 9.6)=3840 × 2880 个点,所以每个象素可以用 (3840/240) × (2880/180)=16 × 16 个点大小的图案来表示,即一个象素 256 个点。如果这 16 × 16 的方块中一个黑点也没有,就可以表示灰度 256 ;有一个黑点,就表示灰度 255 ;依次类推,当都是黑点时,表示灰度 0 。这样, 16 × 16 的方块可以表示 257 级灰度,比要求的 8bit 共 256 级灰度还多了一个。所以上面的那幅图的灰度级别完全能够打印出来。

这里有一个图案构成的问题,即黑点打在哪里?比如说,只有一个黑点时,我们可以打在正中央,也可以打 16 × 16 的左上角。图案可以是规则的,也可以是不规则的。一般情况下,有规则的图案比随即图案能够避免点的丛集,但有时会导致图象中有明显的线条。  

如下图所示, 2 × 2 的图案可以表示 5 级灰度,

 

  当图象中有一片灰度为的 1 的区域时,如下所示,有明显的水平和垂直线条。

 

如果想存储 256 级灰度的图案,就需要 256 × 16 × 16 的二值点阵,占用的空间还是相当可观的。有一个更好的办法是:只存储一个整数矩阵,称为标准图案,其中的每个值从 0 到 255 。图象的实际灰度和阵列中的每个值比较,当该值大于等于灰度时,对应点打一黑点。下面举一个 25 级灰度的例子加以说明。

 

上图,左边为标准图案,右边为灰度为 15 的图案,共有 10 个黑点, 15 个白点。其实道理很简单,灰度为 0 时全是黑点,灰度每增加 1 ,减少一个黑点。要注意的是, 5 × 5 的图案可以表示 26 种灰度,当灰度是 25 才是全白点,而不是灰度为 24 时。下面介绍一种设计标准图案的算法,是由 Limb 在 1969 年提出的。

先以一个2×2的矩阵开始:设

 
通过递归关系有:



其中Mn和Un均为2n×2n的方阵,Un的所有元素都是1。根据这个算法,可以得到


 

为16级灰度的标准图案。


M3(8×8阵)比较特殊,称为Bayer抖动表。M4是一个16×16的矩阵。 
根据上面的算法,如果利用M3一个象素要用8×8的图案表示,则一幅N×N的图将变成8N×8N大小。如果利用M4,就更不得了,变成16N×16N了。能不能在保持原图大小的情况下利用图案化技术呢?一种很自然的想法是:如果用M2阵,则将原图中每8×8个点中取一点,即重新采样,然后再应用图案化技术,就能够保持原图大
小。实际上,这种方法并不可行。首先,你不知道这8×8个点中找哪一点比较合适,另外,8×8的间隔实在太大了,生成的图象和原图肯定相差很大,就象下图最右边的那幅图一样。


我们可以采用这样的做法:假设原图是256级灰度,利用Bayer抖动表,做如下处理

if (g[y][x]>>2) > bayer[y&7][x&7] then 打一白点 else 打一黑点
其中,x,y代表原图的象素坐标,g[y][x]代表该点灰度。首先将灰度右移两位,变成64级,然后将x,y做模8运算,找到Bayer表中的对应点,两者做比较,根据上面给出的判据做处理。
我们可以看到,模8运算使得原图分成了一个个8×8的小块,每个小块和8×8的Bayer表相对应。小块中的每个点都参与了比较,这样就避免了上面提到的选点和块划分过大的问题。模8运算实质上是引入了随机成分,这就是我们下面要讲到的抖动技术。

上图就是利用了这个算法,使用M3(Bayer抖动表)阵得到的;下图是使用M4阵得到的,可见两者的差别并不是很大,所以一般用Bayer表就可以了。

 

让我们考虑更坏的情况:即使使用了图案化技术,仍然得不到要求的灰度级别。举例说明:假设有一幅600×450×8bit的灰度图,当用分辨率为300dpi×300dpi的激光打印机将其打印到8×6英寸的纸上时,每个象素可以用(2400/600)×(1800/450)=4×4个点大小的图案来表示,最多能表示17级灰度,无法满足256级灰度的要求。可有两种解决方案:(1)减小图象尺寸,由600×450变为150×113;(2)降低图象灰度级,由256级变成16级。这两种方案都不理想。这时,我们就可以采用“抖动法”(dithering)的技术来解决这个问题。其实刚才给出的算法就是一种抖动算法,称为规则抖动(regular dithering)。规则抖动的优点是算法简单;缺点是图案化有时很明显,这是因为取模运算虽然引入了随机成分,但还是有规律的。另外,点之间进行比较时,只要比标准图案上点的值大就打白点,这种做法并不理想,因为,如果当标准图案点的灰度值本身就很小,而图象中点的灰度只比它大一点儿时,图象中的点更接近黑色,而不是白色。一种更好的方法是将这个误差传播到邻近的象素。


下面介绍的Floyd-Steinberg算法就采用了这种方案。
假设灰度级别的范围从b(black)到w(white),中间值t为(b+w)/2,对应256级灰度,b=0,w=255,t=127.5。设原图中象素的灰度为g,误差值为e,则新图中对应象素的值用如下的方法得到:
if g > t then
打白点
e=g-w
else
打黑点
e=g-b


3/8 × e 加到右边的象素
3/8 × e 加到下边的象素
1/4 × e 加到右下方的象素
算法的意思很明白:以256级灰度为例,假设一个点的灰度为130,在灰度图中应该是一个灰点。由于一般图象中灰度是连续变化的,相邻象素的灰度值很可能与本象素非常接近,所以该点及周围应该是一片灰色区域。在新图中,130大于128,所以打了白点,但130离真正的白点255还差的比较远,误差e=130-255=-125比较大。将3/8×(-125)加到相邻象素后,使得相邻象素的值接近0而打黑点。下一次,e又变成正的,使得相邻象素的相邻象素打白点,这样一白一黑一白,表现出来刚好就是灰色。如果不传递误差,就是一片白色了。再举个例子,如果一个点的灰度为250,在灰度图中应该是一个白点,该点及周围应该是一片白色区域。在新图中,虽然e=-5也是负的,但其值很小,对相邻象素的影响不大,所以还是能够打出一片白色区域来。这样就验证了算法的正确性。

其它的情况你可以自己推敲。下图是利用Floyd-Steinberg算法抖动生成的图。

 

#技术
原创粉丝点击