图像的去雾算法原理及实现:
本文主要是实现的是基于暗通道处理的去雾。有部分是看论文直接翻译而来,如有错误,欢迎评论区指出,当然您也可以直接阅读原文。
一、原理
暗通道先验解释:
说明:何凯明博士的论文中统计了5000多副图像的特征,证明了暗通道先验理论的普遍性,因此我们可以粗略的认为是一条定理。
先看什么是暗通道先验:
在绝大多数图像局部区域里,有一些像素总会有至少一个颜色通道具有很低的值,该区域光强度的最小值是个很小的数。暗通道的数学定义,对于任意的输入图像J,其暗通道可以用下式表达:
式中Jc表示彩色图像的每个通道 ,Ω(x)表示以像素X为中心的一个窗口。
这个公式的意义用代码表达也很简单,就是求出每个像素RGB分量中的最小值,存入到一副和原始图像大小相同的灰度图中,然后再对这幅灰度图进行最小值滤波,滤波的半径由窗口大小决定,一般有WindowSize = 2 * Radius + 1;
暗通道先验的理论指出:
这个可以自己去试一下的。
有了这个先验,接着就需要进行一些数学方面的推导来最终解决问题。
在计算机视觉中,下述方程所描述的雾图形成模型被广泛使用:
其中,I(X)就是我们现在已经有的图像(待去雾的图像),J(x)是我们要恢复出的无雾的图像,A是全球大气光成分, t(x)为透射率。现在的已知条件就是I(X),要求目标值J(x),显然,这是个有无数解的方程,因此,就需要一些先验了。
将其稍作处理,变形为:
上标C表示R/G/B三个通道的意思。
首先假设在每一个窗口内透射率t(x)为常数,定义他为
,并且A值已经给定,然后两边求两次最小值运算,得到下式:
J是待求的无雾的图像,根据前述的暗原色先验理论有:
可得:
则透射率
的预估值:
在现实生活中,即使是晴天白云,空气中也存在着一些颗粒,因此,看远处的物体还是能感觉到雾的影响,另外,雾的存在让人类感到景深的存在,有必要在去雾的时候保留一定程度的雾,这可以通过在上式中引入一个在[0,1] 之间的因子作为修正:
所有的测试结果依赖于: ω=0.95
1.求暗通道
//计算暗通道
//J^{dark}(x)=min( min( J^c(y) ) )
Mat DarkChannelPrior(Mat img)
{
Mat dark = Mat::zeros(img.rows, img.cols, CV_32FC1);//新建一个所有元素为0的单通道的矩阵
for (int i = 0; i<img.rows; i++)
{
for (int j = 0; j<img.cols; j++)
{
dark.at<float>(i, j) = min(
min(img.at<Vec<float, 3>>(i, j)[0], img.at<Vec<float, 3>>(i, j)[1]),
min(img.at<Vec<float, 3>>(i, j)[0], img.at<Vec<float, 3>>(i, j)[2])
);//就是两个最小值的过程
}
}
erode(dark, dark_out1, Mat::ones(_PriorSize, _PriorSize, CV_32FC1));
//这个函数叫腐蚀 做的是窗口大小的模板运算 ,对应的是最小值滤波,即 黑色图像中的一块块的东西
return dark_out1;//这里dark_out1用的是全局变量,因为在其它地方也要用到
}
2.A值计算:
上述推论中是假设全球达气光A值时已知的,在实际中,我们可以借助于暗通道图来从有雾图像中获取该值。
具体步骤如下:
1) 从暗通道图中按照亮度的大小取前0.1%的像素。
2) 在这些位置中,在原始有雾图像I中寻找对应的具有最高亮度的点的值,作为A值。
3.计算预估的透射率图
在
式中,每个通道的数据都需要除以对应的A值,即归一化,对对比度低的图像可以获得很好的去雾高对比度图。但是/A操作可能会导致t的值小于0,这种情况就可以把t的值直接设置为0来解决。
针对上面说的,要值得一提的是,严格的来说是要对原始图像的每个通道进行归一化后,再取每个通道R/G/B值的最小值得到中间图,然后对这个中间图进行指定半径的最小值滤波后,通过
式得到粗糙的透射率图。那么这样就需要增加不少计算,我在实际中发现如果直接用前面的暗通道图/A进行操作,两者的效果区别不明显,因此,可用这种简便的方式。
到这一步,我们就可以进行无雾图像的恢复了。由式可知: J = ( I - A)/t + A
现在I,A,t都已经求得了,因此,完全可以进行J的计算。
当投射图t 的值很小时,会导致J的值偏大,从而使淂图像整体向白场过度,因此一般可设置一阈值T0,当t值小于T0时,令t=T0,本文中所有效果图均以T0=0.1为标准计算。
因此,最终的恢复公式如下:
去雾的效果:
原图:
去雾后:
二、各参数对去雾结果的影响
第一:窗口的大小。这个对结果来说是个关键的参数,窗口越大,其包含暗通道的概率越大,暗通道也就越黑。建议是窗口大小在11-51之间,即半径在5-25之间。
第二:ω也有着明显的意义,其值越小,去雾效果越不明显。
三、代码
小博的环境是vs2017+opencv3.40:
实现代码: https://download.csdn.net/download/m0_37407756/33494088