【fishing-pan:https://blog.csdn.net/u013921430 转载请注明出处】
提到图像增强,第一印象就是直方图均衡与直方图规定化,这是最常见的也是非常有效的全局图像增强方法。在前不久的一次组会讨论中,课题组的一位同学提到了“自适应图像增强”,虽然自己以前也用过,但是一时间忘记了原理,就去复习了一下,其实他使用的方法的全称应该叫自适应直方图均衡,对应的是Matlab 中的adapthisteq 函数;
我在复习的过程中,偶然发现了另一个图像增强的算法,也就是这篇文章中要提到的——自适应对比度增强(Adaptive Contrast Enhancement,ACE),下面就从原理到实现,来好好聊一下这种方法。
自适应对比度增强
在图像处理的方法中,自适应方法是与图像本身信息相关,根据图像对图特征对图像进行处理的一系列方法,这些方法往往具有更好的鲁棒性、普适性。而本文中提到的这种ACE方法由 等人在《Real-Time Adaptive Contrast Enhancement》中提到,原理简单易懂,有兴趣的朋友可以点击链接去阅读。
对于图像中的每一个点,分别计算其局部均值与局部标准差;
上述式子中,
代表坐标为
的点的像素值,
为以点
为中心,窗口大小为
的区域的局部均值,对应的
为局部的方差,
为局部图像的标准差。
在求得局部均值与标准差后,就可以对图像进行增强了,具体的公式如下;
上式中,
为增强后的像素值,
为全局均值(你也可以把它设为某一合理数值),
是一个系数参数,一般取小于1大于0的小数。
再来分析一下,上面式子的含义;如果将每个点的局部均值
构成一张图,其实就是均值滤波的结果,而在《数字图像傅里叶变换的物理意义及简单应用》中,我提到过均值滤波是一种低通滤波,获得的是图像的低频部分,也就是背景部分,
就可以用来量化图像中的一个点是高频还是低频。而在一般情况下,
都是大于1的,所以通过
可以实现对图像的高频部分的放大,进而对图像进行增强。
再来看看参数
,经过上面的过程可以看出,如果
是一个固定参数,比如都取5,通过式子中的局部均值,我们已经能够将图像实现一定程度上的自适应增强了。那么为什么还要在参数G中引入标准差呢?
我们回忆一下对比度增强的初衷,对比度增强是为了让本身对比度不强的图像的对比度变得明显,而对本身对比度很强的图像,是没必要做增强的。那么在同一图像中,我们尤其需要增强对比度不强的部分。而方差表示的是图像的像素值的均匀性,我们可以认为方差越大的局部区域,其像素值越不均匀,对比度越强;反之,方差越小的局部区域,其像素值越均匀,对比度越弱。因此,在参数 中除以了局部标准差,可以让图像中对比度较弱的部分的增强效果更加明显。
其次,如果对整张图像中所有点进行等比例增强,图像中本身就是高频的部分出现过增强的现象,图像看起来十分奇怪。
彩色图像的ACE
在网上看到有人说,对彩色图像增强可以分别对RGB三通道进行增强后进行合并。这个观点是错误的,因为分别对各个通道进行增强,会引起图像色相的变化,图像会变的不是其原来的颜色了。
所以需要将图像转到HSI色彩空间,或者是YCrCb颜色空间。前者只需要对I亮度通道进行增强,而H、S分别代表的色调和饱和度通道不需要变化。后者用Y通道表示亮度,只需要对Y通道进行增强即可。增强之后再合并通道,转换回RGB空间便完成了对彩色图像的增强。
代码
在这里我只提供一个adaptContrastEnhancement函数的代码,完整的代码也很简单,可以点击下载。无C币的可以直接在博客留言,我也会发送到你的邮箱。
//--------------------------
//Adaptive Contrast Enhancement(自适应对比度增强,ACE)
//不用先生,2018.11.08
//
//函数功能:获取图像的局部均值与局部标准差的图
//函数名称:adaptContrastEnhancement
//函数参数:Mat &scr:输入图像,为三通道RGB图像;
//函数参数:Mat &dst:增强后的输出图像,为三通道RGB图像;
//函数参数:int winSize:局部均值的窗口大小,应为单数;
//函数参数:int maxCg:增强幅度的上限;
//返回类型:bool
//--------------------
bool adaptContrastEnhancement(Mat &scr, Mat &dst, int winSize,int maxCg)
{
if (!scr.data) //判断图像是否被正确读取;
{
cerr << "自适应对比度增强函数读入图片有误";
return false;
}
Mat ycc; //转换空间到YCrCb;
cvtColor(scr, ycc, COLOR_RGB2YCrCb);
vector<Mat> channels(3); //分离通道;
split(ycc, channels);
Mat localMeansMatrix(scr.rows , scr.cols , CV_32FC1);
Mat localVarianceMatrix(scr.rows , scr.cols , CV_32FC1);
if (!getVarianceMean(channels[0], localMeansMatrix, localVarianceMatrix, winSize)) //对Y通道进行增强;
{
cerr << "计算图像均值与标准差过程中发生错误";
return false;
}
Mat temp = channels[0].clone();
Scalar mean;
Scalar dev;
meanStdDev(temp, mean, dev);
float meansGlobal = mean.val[0];
Mat enhanceMatrix(scr.rows, scr.cols, CV_8UC1);
for (int i = 0; i < scr.rows; i++) //遍历,对每个点进行自适应调节
{
for (int j = 0; j < scr.cols; j++)
{
if (localVarianceMatrix.at<float>(i, j) >= 0.01)
{
float cg = 0.2*meansGlobal / localVarianceMatrix.at<float>(i, j);
float cgs = cg > maxCg ? maxCg : cg;
cgs = cgs < 1 ? 1 : cgs;
int e = localMeansMatrix.at<float>(i, j) + cgs* (temp.at<uchar>(i, j) - localMeansMatrix.at<float>(i, j));
if (e > 255){ e = 255; }
else if (e < 0){ e = 0; }
enhanceMatrix.at<uchar>(i, j) = e;
}
else
{
enhanceMatrix.at<uchar>(i, j) = temp.at<uchar>(i, j);
}
}
}
channels[0] = enhanceMatrix; //合并通道,转换颜色空间回到RGB
merge(channels, ycc);
cvtColor(ycc, dst, COLOR_YCrCb2RGB);
}
运行结果
可以明显看出,图像中原先对比度不强的部分,如树干、江面、远景。经过增强后,都有了明显的改善,而本身对比度已经明显的区域,就没有太大的改变。
已完。。