很多时候,灰度图片的灰度级较大,而像素值的分布比较集中,这就导致灰度级的利用率过低,从而导致图片的对比度很小,人眼的感官体验很不好,因此我们通常需要对原始的图像数据进行拉伸调整,增加图片的对比度以适应人眼观察。当前很多红外摄像机拍摄的图像为灰度图,通常使用8、14或者16个比特位取保存一个像素值,那么其灰度级分别为255、16383、65535,灰度级表示了像素值的取值范围,其值越大,可表达的细节越细腻。通常情况下,相机拍摄的灰度图片,其实际的像素取值范围,并不会均匀地分布在灰度级范围之内,而是集中在一小段范围内,比如图1所示,一张16位的红外图像,其像素值的取值集中在[12560,13584]范围之内,其灰度级利用率仅为1.6%,图片偏暗,对比度很低,因此完全看不清图片里边的内容。为了可以看清图片的内容,就必须对原始的灰度图片进行灰度拉伸,所谓灰度拉伸就是对图片灰度进行调整,将原始像素值重新映射到灰度级范围之内,从而改变图片的亮度和对比度。
如上文所说的那样,如果灰度图像的像素值分布在较小的范围,而灰度级又比较大,灰度级的利用率太低,势必会造成图像的对比度的严重下降。为了增加图像的对比度,就要想办法对像素值的分布进行调整,使得灰度级能得到充分的利用,一个最为简单的方法,就是采用线性拉伸,将小范围的像素分布,映射到整个灰度级范围。假如灰度图像的位深是16位,即期灰度级是65535,像素值范围是[12560,13584],为了调整对比度,可以将像素值重新映射到[0,65535]的范围之内。线性拉伸的计算公式如下所示:
I M G d s t = I M G s r c − M I N M A X − M I N × M IMG_{dst}=\frac{IMG_{src}-MIN}{MAX-MIN}\times M IMGdst=MAX−MINIMGsrc−MIN×M
上式中, I M G s r c IMG_{src} IMGsrc表示原始图片像素数据, I M G d s t IMG_{dst} IMGdst是经过线性拉伸后的像素值, M I N MIN MIN表示原始像素数据的最小值, M A X MAX MAX表示原始像素值数据的最大值, M M M表示灰度图像的灰度等级,一般是255、16383、65535,分别对应像素的位深8位、14位、16位。
以下图2为一幅16位灰度图的,经过线性拉伸前后的视觉效果对比(左边位原始图,右边是经过线性拉伸的图)。通过对比图发现,经过线性拉伸后之后,图像从黑漆漆的一片,变成了可以看得见的图像,且其中的内容层次分明。
上文示例的图片,使用线性拉伸的算法进行处理,就可以取得良好的视觉效果,但是并非所有的图片都适用,只有那些像素值分布比较集中,且不存在少量像素值偏移均值太多的灰度图,才可以使用线性拉伸处理。如果灰度图像存在坏点,或者存在少数像素值偏离均值很多,导致像素值的分布范围很大,那么采用线性拉伸算法进行处理,视觉效果改善很小。上文提到,图像的对比度很低,是因为像素分布过于集中,灰度级利用率过低导致的。其实还有另一种情况,即使是像素利用率很高,但仍然视觉效果很差。导致这种结果的原因是,存在少量的像素点,其像素值散布很大,而这些少量的像素点,其实是“无效”的。也就是说,这些像素点由于数量很少,它们对于视觉的贡献是很小的,却占用了大量的灰度空间,而大量的像素值还拥挤在狭小的灰度空间内,实际上有效的灰度级利用率还是很小。比如一种比较极端的情况:一张16位的灰度图,其99.9%的像素值分布在[10000,15000]这样小的范围内,而有0.1%的像素是极暗的0值或者极亮的值65535,远远偏离了大部队的位置,如果采用上文通过求最大最小值的方法进行拉伸,最后图像的对比度不会有任何的改善。
为了改进线性拉伸算法的缺陷,需要对上下偏离中心值很大的像素进行截断。换句话说,这些散布较大的像素值,数量很少,它们对于视觉的贡献是可有可无的,所以把它们截掉之后对视觉的影响可以忽略不记。如图3所示,是一张16位灰度图的像素值分布图(直方图),可以看到大部分像素分布在[a,b]之间,占比99.8%,而少量的点散布在[0,a]和[b,65535]之间,占比0.2%。只要将像素值从a点和b点截断,只将像素区间[a,b]映射到0到65535之间,即可获得很好的对比度提升。
(1)首先,统计灰度图片的直方图hist,hist为一个一维数组,直方图的数量即数组的长度跟灰度等级一致,如果灰度等级是255,则直方图数量为256,如果灰度等级是65535,则直方图数量为65536;
(2)其次,从下标i=0,1,2,…开始对直方图hist[0:i]进行累计求和得到累计直方图acc_hist,acc_hist=sum(hist[0:i]),当acc_hist/num_pixels>pcnt时,此时的索引值i就是下截止值a;继续对直方图进行累计,当acc_hist/num_pixels>1-pcnt时,此时的i就是上截止值b。
(3)获得上下截止值a和b之后,对原图的像素值进行截断,凡是像素值小于a的都截断为a,凡是像素值大于b的都截断为b。像素值截断之后,开始利用上文提到的线性拉伸方法对图片数据进行拉伸处理,其计算公式为:
I M G c l i p = c l i p ( I M G s r c ) , r a n g e ( a , b ) IMG_{clip}=clip(IMG_{src}), range(a,b) IMGclip=clip(IMGsrc),range(a,b)
I M G d s t = I M G c l i p − a b − a × M IMG_{dst}=\frac{IMG_{clip}-a}{b-a}\times M IMGdst=b−aIMGclip−a×M
下图4展示的灰度图使用线性拉伸算法以及使用线性截断拉伸算法处理的效果对比图。由此可知,线性截断拉伸算法的适应性更强,可以适应各种类型的灰度图像,特别是图像中存在坏点(盲元)的情况下,线性截断拉伸算法可以很好地剔除异常值,从而实现良好的对比度增强。
本文所描述的线性截断拉伸算法实现代码如下:
线性截断拉伸算法python代码
线性截断拉伸算法matlab代码
线性拉伸算法对于某些灰度图像,其对比度增强效果良好,但是适应性不强,如果图像中存在坏点或者存在少量像素值散布较大的情况,该方法失效。线性截断拉伸算法是线性拉伸算法的改进,可以克服线性拉伸算法的缺陷,具有剔除异常点的功能,适应性强,能较好地处理各种灰度图像。