【修订版】本文已整理到我的个人博客,订正了原文的几处错误:讲均衡目标时引错了配图,另有拼写和公式记号的问题。CSDN 这一版保留原样,之后的勘误与更新只在博客进行:Histogram Processing : 直方图处理 | Finn's blog
直方图均衡
一副图像的直方图,表示了其灰度分布的特性。对于数字图像来说,假设灰度值k出现了次,那么其概率密度函数如下所示。
这个式子,表示了像素的灰度值为k概率。其中,M与N为图像的尺寸。
对于一幅动态范围较窄的图像,其归一化灰度直方图如下所示。
对于此类图像,使用灰度拉伸,也能使其的动态范围得到改善,增强图像对比度。但是,灰度拉伸从本质上来讲,是很暧昧的,灰度拉伸没有什么明确的目的,只是依靠某个函数的做了灰度变换,使得图像的在灰度直方图的分布范围扩大。灰度拉伸对于结果没有严格的要求,因此根据变换函数的不同,灰度拉伸有无数种结果。
与灰度拉伸不同的是,直方图均衡的目的就比较明确,使用某个特殊的函数,使原图像的灰度分布平均化。为了将其平均化,这里需要用到累积分布函数(Probability Density Function)的概念。
所谓的平均化,直方图均衡的目的是将一幅图的累积分布的曲线(下图左),变为下图右的分布形式。
(左)原图的累积分布曲线 (右)理想化直方图均衡后的累积分布曲线
从右图中可以看出,为了保证直方图均衡后的累积分布曲线是一条倾角为45°的直线,那么,变换后的函数的概率密度函数应与输入值无关,且保持一个常量。输入r与输出s有如下关系,
将变换关系
带入上式子,可得
将其带入输入r与输出s关系,可得到
到此,已经可以看出,输出的概率密度函数,与s的取值无关。很明显,这个分布是绝对平均的。
但是,事实上,上面的式子均是在连续的情况下的。在数字图像的领域,我们必须将其离散化,才能使用。离散的情况下,其累计分布函数如下所示。
至此,直方图均衡就完成了。
为了验证结果,其直方图均衡后的图像与灰度直方图如下所示。
结果就是这样了。但是,呃!!!!问题来了,这是直方图均衡么?这跟灰度拉升有何区别,而且其均衡后的图像的直方图也不是一个很平均的值,和我们的构想有很大区别。这个结果真的没问么?为了回答这个问题,将其原图像的累积分布函数与直方均衡后的累积分布函数画出来,如下。
(左)原图的累积分布曲线 (右)直方图均衡后的累积分布曲线
从累积分布曲线中,我们可以看到,直方图均衡后的曲线,确实跟我们设想的理想曲线很接近!由于我们证明的时候,是在连续的情况下去思考的,所以,将其离散之后,多少是有不理想的情况发生的。均衡后的累积分布曲线确实是一个不错的结果。这样看来,我们才能看清楚直方图均衡的本质。若不是这样,还真不知道直方均衡与灰度拉伸的区别。
为此,直方图均衡成功,Matlab代码如下。
close all; clear all; %% -------------Histogram Equalization----------------- close all; clear all; f = imread('washed_out_pollen_image.tif'); f = mat2gray(f,[0 255]); [M,N] = size(f); g = zeros(M,N); r = imhist(f)/(M*N); %(500*500 is size of image) s = zeros(256,1); for k = 1:1:256 for j = 1:1:k s(k,1) = s(k,1) + r(j); end end for x = 1:1:M %(500*500 is size of image) for y = 1:1:N g(x,y) = s(uint8(f(x,y)*255)+1,1); end end figure(); subplot(2,2,1); imshow(f); xlabel('a).Original Image'); subplot(2,2,2); h = imhist(f)/(M*N); bar(0:1/255:1,h); axis([0 1 0 0.1]),grid; %axis square; xlabel('b).The Histogram of a'); ylabel('Number of pixels'); subplot(2,2,3); imshow(g); xlabel('c).Histogram Equalization'); subplot(2,2,4); h = imhist(g)/(M*N); bar(0:1/255:1,h); axis([0 1 0 0.1]),grid; %axis square; xlabel('d).The Histogram of c'); ylabel('Number of pixels'); figure(); x=0:1/255:1; plot(x,s); axis([0,1,0,1]),grid; axis square; xlabel('intensity level of r'); ylabel('P_{r}(r)'); r = imhist(g)/(M*N); s = zeros(256,1); for k = 1:1:256 for j = 1:1:k s(k,1) = s(k,1) + r(j); end end figure(); x=0:1/255:1; plot(x,s); axis([0,1,0,1]),grid; axis square; xlabel('intensity level of s'); ylabel('P_{s}(s)');(作者注:其实,直方图均衡有直接的函数,这里只是想按照自己理解的方法去做个均衡出来看看,所以高级一点的库函数基本没有,都用循环来的)
直方图匹配
前面,我们说了直方图的均衡,直方均衡可以得到一个灰度直方图分布平均的图像。但是有一些问题,直方图均衡的结果是唯一的。这是其优点,也是其缺点。优点在于,无需多余的参数,就可以实现对比度的增强。缺点在于,没有参数,对于结果无法调整。举个栗子(输入法君卖萌了╭(╯3╰)╮),一幅很黑的图像,使用直方图均衡的话,这幅图像的直方均衡结果,将使得图像偏白。使用《Digital Image Processing》 Rafael C. Gonzalez / Richard E. Woods 的例子来说,看下图。
如上图所示,直方均衡的结果不是很理想。由直方均衡的结果看来,我们能看到,其实对比原图,原图一些细节已经显露出来了,只要稍加修改,就可以得到很理想的增强结果。为此,直觉告诉我们(不要吐槽这句话,有时候直觉就是那么简单。\(≧▽≦)/),只需要将原图的灰度直方图稍微左移一些即可。但是,直方均衡却是不可调整的,为此,就有了直方图匹配。
对于原图像,其概率分布函数是
其输出也就是直方均衡的结果。为了实现直方图匹配,我们还需要一个函数,也就是我们所期待的概率分布函数。这个概率分布函数的概率分布函数如下所示。
其中,z代表了期望的分布。我们假设如下关系成立。
也就是,我们所期待的直方图分布的概率分布函数与原图像的直方图概率分布函数相等。那么,我们可以利用G()的反函数,我们也就可以得到我们所期待的直方图。
上面的描述可能太过拖沓,我们采用简洁一点的描述。
一. 将原图进行直方图均衡。
二. 假设我们期待的分布,直方均衡的结果与原图直方图均衡的结果一致。利用反函数,还原成我们期待的分布。
所实现的直方图均衡结果如下所示。
根据直方图匹配的结果,我们可以看出,所得出的结果和我们所期待的分布很接近。其结果也和我们的初衷一样,使得原图的直方图稍微左移了一些。所得到的结果比起直方均衡要好得多。
其Matlab代码如下。
%% -------------Histogram Matching----------------- close all; clear all; f = imread('mars_moon_phobos.tif'); f = mat2gray(f,[0 255]); [M,N] = size(f); g = zeros(M,N); r = imhist(f)/(M*N); s = zeros(256,1); for k = 1:1:256 for j = 1:1:k s(k,1) = s(k,1) + r(j); end end for x = 1:1:M for y = 1:1:N g(x,y) = s(uint8(f(x,y)*255)+1,1); end end figure(); subplot(2,2,1); imshow(f); xlabel('a).Original Image'); subplot(2,2,2); h = imhist(f)/(M*N); bar(0:1/255:1,h); axis([0 1 0 0.1]),grid; xlabel('b).The Histogram of a'); subplot(2,2,3); imshow(g); xlabel('c).Histogram Equalization'); subplot(2,2,4); h = imhist(g)/(M*N); bar(0:1/255:1,h); axis([0 1 0 0.1]),grid; xlabel('d).The Histogram of c'); %---------------pz----------------------- r = r'; p = [0:r(1,1)/15:r(1,1) 17*r(1,2:241)]; %p = [0:r(1,1)/15:r(1,1) r(1,2:241)]; %p = [0:55:255 , 255:-25:24 , 24:-0.14:0 , 0:1:15 , 15:-0.285:0]; p = (p/sum(p)); p = p'; r = r'; G = zeros(256,1); for k = 1:1:256 for j = 1:1:k G(k,1) = G(k,1) + p(j); end end G_Negatives = zeros(256,1); Flag = 0; for k = 1:1:256 for j = 1:1:256 if(uint8(G(j,1)*255) == k) G_Negatives(k,1) = (j-1)/255; Flag = 1; end end if(Flag == 0) if(k == 1) G_Negatives(k,1) = 0; else G_Negatives(k,1) = G_Negatives(k-1,1); end end Flag = 0; end z = zeros(M,N); for x = 1:1:M for y = 1:1:N z(x,y) = G_Negatives(uint8(g(x,y)*255)+1,1); end end figure(); subplot(2,2,1); imshow(z); xlabel('a).Histogram Matching'); subplot(2,2,2); h = imhist(z)/(M*N); bar(0:1/255:1,h); axis([0 1 0 .1]),grid; xlabel('b).The Histogram of a'); subplot(2,2,3); x=0:1/255:1; plot(x,p); axis([0,1,0,.1]),grid; xlabel('c).Specifieds Histogram (Normalized)'); subplot(2,2,4); x=0:1/255:1; plot(x,G,x,G_Negatives); axis([0,1,0,1]),grid; axis square; xlabel('Input intensity level'); ylabel('Onput intensity level');博客地址:zhoufan900428-CSDN博客