算法
经典算法
下面以一幅3*2像素的简单图片(图C)为例,来说明灰度直方图均衡化的算法。
(图C)
图C的直方图:
百分位(Percentile)这一项。一般软件的百分位是 当前色阶的像素数量÷总像素数量,而Photoshop不同,Photoshop显示的是 当前色阶与前面色阶的所有像素数量÷总像素数量。因此图C色阶为100时的百分位就是(3+2)/6=5/6=83.33%,这个百分位其实就是我们要求的灰度值(范围0~1),把它转换成0~255的范围,要再乘255。
求出每个色阶的百分位之后,再乘255,就可以求出与其对应的灰度值来。
色阶 | 数量 | 出现频率 | 百分位 | 255*百分位 |
50 | 3 | 3/6 | 3/6=50% | 255*50%=128 |
100 | 2 | 2/6 | (3+2)/6=83.33% | 255*83.33%=212 |
200 | 1 | 1/6 | (3+2+1)/6=100% | 255*100%=255 |
色阶->255*百分位
Photoshop的算法
经过经典算法均衡化的图片,最亮的像素值总是255,因为最后一级色阶(255)的百分位一定是100%。而最暗的是由色阶0的数量决定的,像素值不一定是0。
Photoshop通过对比度拉伸的方法使最暗的像素值变为0,其它像素也相应变暗,最亮的像素保持255不变。对比度拉伸后的效果可能会比经典算法稍显偏暗。
对比度拉伸的算法,类似于使用色阶调整命令把黑场设成Min时的效果,Min是指像素数量不为0的第一个色阶。
C = (Level - Min) * Scale = (Level - Min) * 255 / (255-Min)
图C均衡化之后的灰度值分别是128、212、255,为了精确,我们使用保留2位小数的形式(127.50、212.42、255.00)来进行对比度拉伸的计算。
|
经典算法和Photoshop算法的直方图比较。
彩色算法
彩色的直方图均衡化其实就是对图像某个或多个颜色通道进行灰度直方图均衡化运算,常见的有以下几种方法:
- 统计所有RGB颜色通道的直方图的数据并做均衡化运算,然后根据均衡化所得的映射表分别替换R、G、B通道颜色值。
- 分别统计R、G、B颜色通道的直方图的数据并做均衡化运算,然后根据R、G、B的映射表分别替换R、G、B通道颜色值。
- 用亮度公式或求RGB的平均值的方式计算亮度通道,然后统计亮度通道的直方图的数据并做均衡化运算,然后根据映射表分别替换R、G、B通道颜色值。
Photoshop用的是第一种方法。
总结
直方图均衡化是灰度变换的一个重要应用,它高效且易于实现,广泛应用于图像增强处理中。图像的像素灰度变化是随机的,直方图的图形高低不齐,直方图均衡化就是用一定的算法使直方图大致平和。
均衡化处理后的图象只能是近似均匀分布。均衡化图象的动态范围扩大了,但其本质是扩大了量化间隔,而量化级别反而减少了,因此,原来灰度不同的象素经处理后可能变的相同,形成了一片的相同灰度的区域,各区域之间有明显的边界,从而出现了伪轮廓。
如果原始图像对比度本来就很高,如果再均衡化则灰度调和,对比度降低。在泛白缓和的图像中,均衡化会合并一些象素灰度,从而增大对比度。均衡化后的图片如果再对其均衡化,则图像不会有任何变化。
灰度直方图均衡化的算法,简单地说,就是把直方图的每个灰度级进行归一化处理,求每种灰度的累积分布,得到一个映射的灰度映射表,然后根据相应的灰度值来修正原图中的每个像素。
经典的直方图均衡化算法可能存在以下一些不足:
- 输出图像的实际灰度变化范围很难达到图像格式所允许的最大灰度变化范围。
- 输出图像的灰度分布直方图虽然接近均匀分布, 但其值与理想值1/n仍有可能存在较大的差异, 并非是最佳值。
- 输出图像的灰度级有可能被过多地合并。由于灰度的吞噬也易造成图像信息的丢失。
为此人们提出了许多改进的直方图均衡算法,详细内容请参阅本文末尾提供的参考资料。
基于上述编程思想,用MATLAB实现的算法如下:
%直方图均衡化
I0 = imread('lena.jpg');
I = rgb2gray(I0) %二值化
[height,width]=size(I);
figure
subplot(221)
imshow(I)%显示原始图像
subplot(222)
imhist(I)%显示原始图像直方图
%根据像素灰度统计;
NumPixel = zeros(1,256);%统计各灰度数目,共256个灰度级(初始化数目为0)
for i = 1:height
for j = 1:width
NumPixel(I(i,j)+1)=NumPixel(I(i,j)+1)+1;%对应灰度值像素点数量加一
end
end
%计算灰度分布密度
ProbPixel = zeros(1,256);
for i = 1:256
ProbPixel(i) = NumPixel(i)/(height*width*1.0);
end
%计算累计直方图分布(“离散求累积和,连续求积分”)
for i = 1:256
if i == 1
Cumupixel(i) = ProbPixel(i);
else
Cumupixel(i)=Cumupixel(i-1)+ProbPixel(i);
end
end
%累计分布取整
for i = 1:256
Cumupixel(i) = uint8(255.0*Cumupixel(i)+0.5);
end
%对灰度值进行映射(均衡化)
for i = 1:height
for j = 1:width
I(i,j)=Cumupixel(I(i,j));
end
end
subplot(223)
imshow(I)%显示直方图均衡化后的图像
subplot(224)
imhist(I)%显示直方图均衡化后的图像的直方图
实现效果如下: