作者辛苦原创,转载请注明出处,本人水平有限,疏漏在所难免,欢迎指正。
一.用法
灰度均衡化虽然能增大对比度、丰富灰度级数。但是为覆盖整个灰度区间的操作,且不受控制,即只能扩展到整个灰度区间,不能根据我们的实际需要作出相应调整。
而灰度规定化可以弥补这个缺憾,能让我们通过灰度变换得到我们想要的灰度分布区间。在Matlab中没有直接实现灰度规定化的函数。但是我们可以通过imhist和histeq两个函数的结合使用来实现。示例程序如下:
I_M =
imread('pout.tif');
I =
imread('tire.tif');
I_M_imhist = imhist(I_M);%产生规定化模板
J = histeq(I,I_M_imhist);%直方图规定化
imhist(I); %显示变换前的直方图
imhist(I_M);%产生规定化模板
imhist(J);% 规定化变换后的直方图
二.原理
直方图规定化首先也得求灰度图像的灰度级数的概率密度和累计分布函数,得到原始图像和模板图像的灰度累计分布函数直方图后(这里的模板的灰度级数N和原始图像的灰度级数M我们只讨论M>=N的情况),有两种方式将模板灰度分布特征映射到原始图像中。一是单映射规则(SML),二是组映射规则(GML)。
1.单映射规则(SML)
单映射规则具体操作步骤如下:对一原始图像的每个灰度级数i的灰度累计分布函数(nor_I_hist(i))与模板图像灰度级数灰度累计分布函数值(nor_M_hist(i))作差值后取绝对值运算,比较运算得到的结果,差值绝对值的最小值对应的最小位置便是原始图像映射到模板图像的灰度值。
例:
设一幅原始图像和模板图像的灰度级数、灰度直方图、累计分布函数直方图呈如下分布:
表1-1
表中为灰度值为0的灰度级单映射时,分别用其累计分布函数直方图0.19与模板的累计分布函数直方图作差,发现差值绝对值的最小值在模板图像灰度级的3、4灰度级处,取最小位置处为3,故原始图像灰度级为0的位置单映射后的灰度值为3。其余灰度级同理。
2.组映射规则(GML)
组映射也是先求出原始图像和模板图像的累计分布函数直方图。在此基础上,与单映射相反,组映射是用模板图像中每个灰度级的累计分布函数(灰度直方图概率密度为0的灰度级除外)依次与原始图像的所有累计分布函数值作差,在所有差值中找出绝对值最小值所对应的原始图像灰度级,将该灰度级与上一次映射灰度级之间的原始图像灰度级都映射为模板图像中与之差值绝对值最小的灰度级。例如,对于表1-1的灰度图像,若采用组映射方法,则应从模板图像灰度级数为3的位置开始运算映射,即用0.2分别与原始图像的累计分布函数直方图作差,发现在0.19处有绝对值最小值,于是就将原始图像灰度值为0映射为3,下一步则接着从灰度级为5的位置开始映射,即0.8分别与原始图像的累积分布直方图作差,发现在0.81出有最小值,对应原始图像中灰度级数为3的位置,于是原始图像中灰度级1~3都映射为5。其余同理。
三.代码示例
阐述完上述原理后,我们通过基于Matlab的编程来进一步验证我们方法的正确性。
1.实现单映射(SML)代码示例:
I = imread('pout.tif');
M = imread('tire.tif');
I_out = I;
I_hist = imhist(I);
M_hist = imhist(M);%概率密度函数,即灰度直方图
nor_I_hist = cumsum(I_hist)/numel(I);
nor_M_hist = cumsum(M_hist)/numel(M);%累积分布函数
%累积分布函数归一化
[m_I,n_I] = size(nor_I_hist);
[m_M,n_M] = size(nor_M_hist);
imp=ones(m_M,1);
for i=1:m_I
for
j=1:m_M
imp(j) =abs( nor_I_hist(i) -nor_M_hist(j));%作差值绝对
%值运算
end
nn
= find(imp==min(imp));%找到最小值所在灰度级
ori
= find(I==i-1);
L = length(ori);%测量nummin的长度,若大于1,则说明有概率密度
%为0的位置,则取最后位。
I_out(ori) =
nn(L);%将模板灰度映射到原始图像中
end
%显示原始图像、模板图像、变换后图像的灰度直方图
subplot(2,3,1),imhist(I),title('hist of
orignal image')
subplot(2,3,2),imhist(M),title('hist of
template image')
subplot(2,3,3),imhist(I_out),title('hist of
output image')
subplot(2,3,4),imshow(I),title('orignal
image')
subplot(2,3,5),imshow(M),title('template
image')
subplot(2,3,6),imshow(I_out),title('output
image')
SML结果
1.组映射(GML)代码示例:
I =
imread('tire.tif');
M =
imread('pout.tif');
[m,n] = size(I);
I_out = im2uint8(zeros(m,n));
I_hist = imhist(I);
M_hist = imhist(M);
nor_I_hist = cumsum(I_hist)/numel(I);
nor_M_hist = cumsum(M_hist)/numel(M);
[M_m,M_n] = size(M_hist);
[I_m,I_n] = size(I_hist);
tick = 1;
IM = zeros(I_m,1);
for i = 1:M_m%
if M_hist(i) == 0%剔除掉直方图概率密度为0的灰度级
continue;
else
for
j = 1:I_m
IM(j) =abs(nor_M_hist(i)-nor_I_hist(j));
end
nummin = find(IM == min(IM));%找到差值最小的灰度值位置,便是原
%始图像及其之前的灰度值都映射为新的灰度值i
L= length(nummin);%测量nummin的长度,若大于1,则说明有概率密度
%为0的位置,则取最后位。
for
k=tick:nummin(L)%从上一次映射灰度级到本次灰度级之间的灰度级
matchgray
= find(I==k-1);
I_out(matchgray)
= i-1;%赋值到原始图像中
end
tick = nummin(L);
end
end
%显示原始图像、模板图像、变换后图像的灰度直方图
subplot(2,3,1),imhist(I),title('hist of
orignal image')
subplot(2,3,2),imhist(M),title('hist of
template image')
subplot(2,3,3),imhist(I_out),title('hist of
output image')
subplot(2,3,4),imshow(I),title('orignal
image')
subplot(2,3,5),imshow(M),title('template
image')
subplot(2,3,6),imshow(I_out),title('output
image')
GML结果
3.单映射法(SML)和组映射法(GML)的比较
首先,我们使用表1-1分别在单映射和组映射下得到的结果来量化误差,列于表3-1中。
表3-1
对单映射来说,我们可以用映射时产生的累积分布函数差值来量化映射误差,具体为:|0.44-0.20|+||+|(0.89-0.44)-(0.8-0.2)|+|(1.00-0.89)-(1-0.8)|=0.48
对组映射来说,则为:|0.2-0.19|+|(0.81-0.19)-(0.8-0.2)|+|(1.0-0.8)-(1-0.81)|=0.04
从量化数据误差来看,组映射的误差明显要小于单映射。在此基础上,为验证结论的普遍性,我们用期望误差来说明,当把某个模板图像tem(i)灰度映射到原始图像ORI(i)时,对于单映射法,由于是采用一原始灰度与所有模板灰度值分别作差得到作差绝对值最小值位置,故最大可能误差为u/2,其中u表示最小差值绝对值处的模板灰度直方图;对于组映射法,则是用一模板灰度值分别与所有原始灰度图像作差,则最大可能误差为s/2,其中s表示最小值差值处的原始图像灰度直方图。由于根据前面所述,我们讨论的都是模板灰度级数N小于等于原始图像灰度级数M的情况,故必有s/(2*M),因此组映射的期望误差必小于单映射误差,需要提及的是,上述Matlab代码是通过组映射实现的灰度规定化。