图像直方图相关总结

来源:互联网 发布:淘宝厨房用品 编辑:程序博客网 时间:2024/06/03 22:08

主要讨论直方图均衡化直方图规定化(匹配)局部直方图限制对比度自适应直方图均衡化(CLAHE)基于直方图统计的图像增强


1. 直方图均衡化

基本思想是:尽可能的使每个灰度级的像素数量相等


图1-1. 直方图均衡化的效果(截自《数字图像处理》)

从上图可以看到,直方图均衡化的作用是:使图像灰度级跨越更宽的灰度级范围,从而提高图像对比度

直方图均衡化的另一个优势是:不需要额外参数,整个过程是自动的

直方图均衡化的缺点是:拉伸后有些灰度级可能不被映射到,造成图像观感上的颗粒感

算法步骤:

1)计算图像灰度直方图,并进行归一化(除以总像素数)

2)计算归一化直方图的累积直方图 fHist[ L-1 ]

3)对原始图灰度S,变换后的灰度D = fHist[S] * (L-1)

代码:

void equalizeHist(byte* pBuffer, byte* out, int height, int width){//假定为8位图像int hist[256] = { 0 };for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){byte* pNow = pBuffer + i * width + j;hist[int(*pNow)]++;}}float fHist[256] = { 0 };float len = height*width;for (int i = 0; i < 256; i++)fHist[i] = hist[i] / len;for (int i = 1; i < 256; i++)fHist[i] = fHist[i - 1] + fHist[i];for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){byte* pNow = pBuffer + i * width + j;out[i*width+j]= int(fHist[int(*pNow)] * 255 + 0.5);}}}


2. 直方图规定化(匹配)

直方图均衡化是把直方图变换为均匀分布的形状,直方图匹配是将其变换为指定的形状,因此可以将直方图均衡看做直方图规定化的特例

算法的基本思路是,以直方图均衡化为桥梁,同时将原始直方图和目标直方图做均衡,这样从理论上看,两个均衡化的直方图是一样的(当然实际情况肯定有差别)。不妨假设原始图的均衡化直方图为 SHist[ L-1 ], 目标图的均衡化直方图为 DHist[ L-1 ]。对原始直方图中第 i 级,查找DLhist中与SHist[ i ]最接近的那一级作为 i 的映射灰度

在直方图比较这一块的算法实现有单映射规则SML组映射规则GML两种方法:


图2-1. SML和GML映射规则(截自直方图规定化之SML和GML映射)

代码:

void matchHist(Mat src, Mat dst, Mat& out){/*计算各自的累积直方图*/int srcHist[256] = { 0 };int dstHist[256] = { 0 };for (int i = 0; i < src.rows; i++){byte* ptr = src.ptr<byte>(i);for (int j = 0; j < src.cols; j++)srcHist[int(ptr[j])]++;}for (int i = 0; i < dst.rows; i++){byte* ptr = dst.ptr<byte>(i);for (int j = 0; j < dst.cols; j++)dstHist[int(ptr[j])]++;}float fSrcHist[256] = { 0 };float fDstHist[256] = { 0 };for (int i = 0; i < 256; i++){fSrcHist[i] = srcHist[i] / float(src.rows*src.cols);fDstHist[i] = dstHist[i] / float(dst.rows*dst.cols);}for (int i = 1; i < 256; i++){fSrcHist[i] = fSrcHist[i - 1] + fSrcHist[i];fDstHist[i] = fDstHist[i - 1] + fDstHist[i];}/*各级灰度值差*/float distance[256][256] = { 0 };for (int i = 0; i < 256; i++){for (int j = 0; j < 256; j++)distance[i][j] = fabs(fSrcHist[j] - fDstHist[i]);}#if 1/*SML映射*/int mapping[256] = { 0 };for (int i = 0; i < 256; i++){int minDst = 0;float minValue = distance[0][i];for (int j = 1; j < 256; j++){if (minValue > distance[j][i]){minValue = distance[j][i];minDst = j;}}mapping[i] = minDst;}#else/*GML映射*/int lastStart = 0, lastEnd = 0, start = 0, end = 0;for (int i = 0; i < 256; i++){float minValue = distance[i][0];for (int j = 0; j < 256; j++){if (minValue > distance[i][j]){end = j;minValue = distance[i][j];}}if (start != lastStart || end != lastEnd){for (int j = start; j <= end; j++)mapping[j] = i;lastStart = start;lastEnd = end;start = lastEnd + 1;}}#endiffor (int i = 0; i < src.rows; i++){byte* ptr = src.ptr<byte>(i);byte* ptr1 = out.ptr<byte>(i);for (int j = 0; j < src.cols; j++)ptr1[j] = mapping[int(ptr[j])];}}

3. 局部直方图

有时需要突出图像中小范围的细节,但前面的直方图均衡以及基本的灰度变换方法一文提到的灰度变换方法都是基于全局的灰度分布


局部直方图处理大致有3种实现方法:

1)将原始图片划分成不重叠的子块,在每个子块内做直方图处理(如直方图均衡)

操作简单,但输出图像会有块效应


2)类似模板卷积的方式,以待处理的点为中心,取其邻域为子块,在子块内做直方图处理,处理结果仅映射到该点

可以消除块效应,但需要对每个点计算一次直方图处理,效率很低


3)前两种方法的结合版,不再逐像素移动,步长小于子块宽度以确保两个相邻子块有重叠;每个子块做直方图映射后的结果赋值给子块内所有点,这样每个点会有多次赋值,最终的取值为这些赋值的均值


图3-1对比了全局直方图均衡和局部直方图均衡(方法2,子块尺寸为11*11)


图3-1. 原始图(左),全局直方图均衡(中),局部直方图均衡(右)


4. 限制对比度自适应直方图均衡化(CLAHE)

CLAHE在局部直方图均衡化(又称自适应直方图均衡化AHE)的基础上,对每个子块直方图做了限制,很好的控制了AHE带来的噪声,还可以用来做去雾。

这里对CLAHE做了较为详细的说明


下面的算法步骤参考OpenCV的CLAHE模块(opencv\sources\modules\imgproc\src\clahe.cpp)

step1. 扩展图像边界,使其能够刚好切分为若干子块

   假设每个子块面积为tileSizeTotal

   子块系数 lutScale = 255.0 / tileSizeTotal

   对预设的limit做处理:limit = MAX(1, limit * tileSizeTotal / 256)

step2. 对每个子块,计算直方图

step3. 对每个子块直方图的每个灰度级,使用预设的limit值做限定,同时统计整个直方图超过limit的像素数

step4. 计算每个子块的lut累积直方图tileLut

   tileLut[i] = sum[i] * lutScale

   sum[i] 是累积直方图,lutScale确保tileLut取值在[0, 255]

step5. 遍历原始图像每个点,考虑该点所在子块及右、下、右下一共4个子块的tileLut,以原始灰度值为索引得到4个值,然后做双线性插值得该点变换   后的灰度值

   双线性插值的方式避免了为每个像素点做以其为中心的直方图计算


图4-1 对比了全局直方图均衡、AHE和CLAHE的效果,可以看到,CLAHE对噪点的控制是最好的


图4-1. a.原图;b.全局直方图均衡化;c. AHE(30个子块);d.CLAHE(limit:0.272, 30子块)


5. 基于直方图统计的图像增强

令归一化的直方图为 p(r) ,这样像素的均值为,由此可得到 r 关于均值 m 的 n 阶矩,如果取n=2,则得到灰度方差

在实际计算中,常用取样均值和取样方差来省去直方图的计算:

案例:

假设现在需要增强图像暗区域;对每个点,计算其邻域窗口的灰度均值和方差,将两者分别与全局的灰度均值和方差比较,如果局部均值小于指定阈值与全局均值之积,那么则认为该点处于暗区域,再判断局部方差与全局方差的关系,如果局部方差落在某个范围内(),则说明该点的对比度较低,那么可以对其乘以某个值以突出特征,低阈值的设置是为了避免增强实际恒定的区域


6.参考

[1] 《数字图像处理》 冈萨雷斯

[2] 江巨浪等, 保持图像亮度的局部直方图均衡算法

0 0