3.7 直方图均衡化
本节将介绍一种实用性极高的直方图修正技术——直方图均衡化。
3.7.1 理论基础
直方图均衡化又称为灰度均衡化,是指通过某种灰度映射使输入图像转换为在每一灰度级上都有近似相同的像素点数的输出图像(即输出的直方图是均匀的)。在经过均衡化处理后的图像中,像素将占有尽可能多的灰度级并且分布均匀。因此,这样的图像将具有较高的对比度和较大的动态范围。
为了便于分析,让读者首先考虑灰度范围为0~1且连续的情况。此时图像的归一化直方图即为概率密度函数(PDF)。
由概率密度函数的性质,有以下关系。
设转换前图像的概率密度函数为pr(r),转换后图像的概率密度函数为ps(s),转换函数(灰度映射关系)为s=f(r)。由概率论知识可得下式。
这样,如果想使转换后图像的概率密度函数:ps(S)=1,0≤S≤1(即直方图为均匀的),则必须满足下式。
等式两边对r积分,可得下式。
式(3-11)被称为图像的累积分布函数(CDF)。
式(3-11)是在灰度取值在[0, 1]范围内的情况下推导出来的,对于[0, 255]的情况,只要乘以最大灰度值Dmax(对于灰度图就是255)即可。此时灰度均衡的转换公式如下。
其中,DB为转换后的灰度值,DA为转换前的灰度值。
而对于离散灰度级,相应的转换公式应如下。
式中Hi为第i级灰度的像素个数,A0为图像的面积,即像素总数。
式(3-13)中的变换函数f是一个单调增加的函数,这保证了在输出图像中不会出现灰度反转的情况(变换后相对灰度不变),从而能够防止在变换中改变图像的实质,以至于影响对图像的识别和判读。
这里还需要说明一点,对于式(3-13)的离散变换,通常无法再像连续变换时那样可以得到严格的均匀概率密度函数(ps(S)=1,0≤S≤1)。但无论如何,式(3-13)的应用有展开输入图像直方图的一般趋势,可使得均衡化过的图像灰度级具有更大的范围,从而得到近似均匀的直方图。
3.7.2 MATLAB编程实现
MATLAB图像处理工具箱提供了用于直方图均衡化的函数histeq(),调用语法如下。
[J, T] = histeq(I)
参数说明:
• I是原始图像。
返回值:
• J是经过直方图均衡化的输出图像;
• T是变换矩阵。
图像易受光照、视角、方位、噪声等的影响。在这些因素的作用下,同一类图像的不同变形体之间的差距有时大于该类图像与另一类图像之间的差距,这就给图像识别/分类带来了困扰。图像归一化就是将图像转换成唯一的标准形式以抵抗各种变换,从而可消除同类图像不同变形体之间的外观差异。
当图像归一化用于消除灰度因素(光照等)造成的图像外观变化时,称为(图像)灰度归一化。例3.1为读者展示了如何利用直方图均衡化来实现图像的灰度归一化。
【例3.1】利用直方图均衡化技术实现图像的灰度归一化。
下面的程序在读入了图像pout.tif后,分别对其进行了增加对比度、减小对比度、线性增加亮度和线性减小亮度的处理,得到了原图像的4个灰度变化版本;接着又分别对这4幅图像进行了直方图均衡化处理并显示了它们在处理前、后的直方图。
I = imread('pout.tif'); %读入原图像 I = im2double(I); % 对于对比度变大的图像 I1 = 2 * I -55/255; subplot(4,4,1); imshow(I1); subplot(4,4,2); imhist(I1); subplot(4,4,3); imshow(histeq(I1)); subplot(4,4,4); imhist(histeq(I1)); % 对于对比度变小的图像 I2 = 0.5 * I + 55/255; subplot(4,4,5); imshow(I2); subplot(4,4,6); imhist(I2); subplot(4,4,7); imshow(histeq(I2)); subplot(4,4,8); imhist(histeq(I2)); % 对于线性增加亮度的图像 I3 = I + 55/255; subplot(4,4,9); imshow(I3); subplot(4,4,10); imhist(I3); subplot(4,4,11); imshow(histeq(I3)); subplot(4,4,12); imhist(histeq(I3)); % 对于线性减小亮度的图像 I4 = I -55/255; subplot(4,4,13); imshow(I4); subplot(4,4,14); imhist(I4); subplot(4,4,15); imshow(histeq(I4)); subplot(4,4,16); imhist(histeq(I4));
上述程序的运行的结果如图3.18所示。
图3.18 不同亮度、对比度图像的直方图均衡化效果
图3.18 不同亮度、对比度图像的直方图均衡化效果(续)
从图3.18中可以发现,将直方图均衡化算法应用于左侧的亮度、对比度不同的各个图像后,得到了右侧直方图大致相同的图像,这体现了直方图均衡化作为强大自适应性的增强工具的作用。当原始图像的直方图不同而图像结构性内容相同时,直方图均衡化所得到的结果在视觉上几乎是完全一致的。这对于在进行图像分析和比较之前将图像转化为统一的形式是十分有益的。
从灰度直方图的意义上说,如果一幅图像的直方图非零范围占有所有可能的灰度级并且在这些灰度级上均匀分布,那么这幅图像的对比度较高,而且灰度色调较为丰富,从而易于进行判读。直方图均衡化算法恰恰能满足这一要求。
本书后面将要介绍的很多图像处理方法都是以归一化为目的的,比如第4章几何变换就是研究一种几何失真的归一化处理。
3.7.3 Visual C++实现
利用Visual C++实现图像的灰度直方图均衡化的代码如下。
/************************************************** BOOL CImgProcess::Histeq(CImgProcess * pTo) 功能: 图像的灰度直方图均衡化方法 参数: CImgProcess * pTo 输出CImgProcess对象的指针 返回值: BOOL类型,true为成功,false为失败 ***************************************************/ BOOL CImgProcess::Histeq(CImgProcess * pTo) { // 首先检查图像是否是8位灰度图像 if (m_pBMIH->biBitCount! =8) return false; BYTE gray; // 临时变量,存储当前光标像素的灰度值 int target; // 临时变量,存储当前光标像素的目标值 double pdHist[256]; //临时变量,存储灰度直方图 double dTemp; // 临时变量,存储累加的直方图数据 this->GenHist(pdHist); for (int i=0; i<m_pBMIH->biHeight; i++) { for (int j=0; j<m_pBMIH->biWidth; j++) { dTemp = 0; gray = GetGray(j, i); for (BYTE k=0; k<gray; k++) { dTemp+=*(pdHist + k); }; target = 255 * dTemp; if (target < 0) target = 0; if (target > 255) target = 255; // 写入目标图像 pTo->SetPixel(j, i, RGB(target, target, target)); } }; return true; }
利用Histeq()函数实现直方图均衡化的完整示例被封装在DIPDemo工程中的视图类函数CDIPDemoView::OnPointEqua(),其中调用Histeq()函数的代码片断如下所示:
// 输出的临时对象 CImgProcess imgOutput = imgInput; // 直方图均衡化 imgInput.Histeq(&imgOutput); // 将结果返回给文档类 pDoc->m_Image = imgOutput;
读者可以通过光盘中示例程序DIPDemo中的菜单命令“点运算→直方图均衡化”来观察处理效果。