Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现

He 提出暗通道去雾方法进行了详细的描述,该方法以大气散射模型为基础,利用暗通道先验原理求出全球大气光成分A和透射率t。先使用了软抠图对透射率图进行优化,但是运算时间过长。后来使用引导滤波精细化透射率图,缩短了一部分运算时间。

暗通道先验:

在绝大多数非天空的局部区域里,某一些像素总会有至少一个RGB颜色通道具有很低的值。换言之,该区域光强度的最小值是个很小的数,值接近于0。

实际生活中造成暗原色中低通道值主要有三个因素:

a)汽车、建筑物和城市中玻璃窗户的阴影,或者是树叶、树与岩石等自然景观的投影;

b)色彩鲜艳的物体或表面,在RGB的三个通道中有些通道的值很低(比如绿色的草地/树/植物,红色或黄色的花朵/叶子,或者蓝色的水面);

c)颜色较暗的物体或者表面,例如灰暗色的树干和石头。总之,自然景物中到处都是阴影或者彩色,这些景物的图像的暗原色总是很灰暗的。

我们给暗通道一个数学定义,对于任意的输入图像J,其暗通道可以用下式表达:

c表示图像R,G,B中的每个通道。

Jc表示彩色图像的某一通道 。

Ω(x)表示以像素X为中心的一个窗口。

 式(5)的意义用代码表达也很简单,求解过程如下:

(1)求出每个像素RGB分量中的最小值,存入一副和原始图像大小相同的灰度图中

(2)对这幅灰度图以15x15的窗口进行最小值滤波,即以每个窗口的最小值代替这个像素点的最小值。滤波的半径由窗口大小决           定(论文采用7),一般有WindowSize = 2 * Radius + 1; 

def darkChannel(src, r=15):
    
    temp = np.min(src,2)
    
    s = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (r,r))

    dst = cv2.erode(temp, s)
    
    return dst

举个栗子:

Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第1张图片Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第2张图片

Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第3张图片Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第4张图片

由上述几幅图像,可以明显的看到暗通道先验理论的普遍性。在作者的论文中,对5000多副无雾图像手动裁剪掉天空区域,重调整图片大小,使得图片长宽不大于500,Ω(x)的大小选取15*15,发现75%的暗通道的像素值都为0,90%的暗通道的像素值都低于25,很好验证暗通道理论的普适性,因此,我们可以认为其实一条定理。

 

大气散射模型(求解A与t(x)):

在计算机视觉和计算机图形中,下述方程所描述的雾图形成模型被广泛使用:

I(X)就是我们现在已经有的图像(待去雾的图像)。

J(x)是我们要恢复的无雾的图像。

A是全球大气光成分, t(x)为透射率。

将式(1)稍作处理,变形为下式(C表示R/G/B三个通道的意思):

首先假设在每一个窗口内透射率t(x)为常数,也就是假设在同一窗口的上的透射率是相同的,定义他为,且A值已经给定,然后对式(7)两边求两次最小值运算得到下式:

Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第5张图片

上式中,J是待求的无雾的图像,根据前述的暗原色先验理论有:

可推导出:

把式(10)带入式(8)中,得到:

这里使用guideFilter引导滤波,优化已经求得的通道图片,所以上式变为t=1-V/A,这里V为透射率图。

引导图应该与原图尽可能相似,取np.min(src,2)

也就是:V = guideFilter(np.min(m,2) , dc, r, eps),这里应该在[0,1]范围内进行,也就是引导图和预估的投射图都必须从[0,255]->[0,1]进行计算。导向滤波的r值应当不小于进行最小值滤波半径r的4倍

即使是晴天白云,空气中也存在着一些颗粒,因此,看远处的物体还是能感觉到雾的影响,另外,雾的存在让人类感到景深的存在,因此,有必要在去雾的时候保留一定程度的雾,这可以通过在式(11)中引入一个在[0,1] 之间的因子,则式(11)修正为:

注:文中所有的测试结果依赖于:  ω=0.95

上述推论中都是假设全球达气光A值时已知的,在实际中,我们可以借助于暗通道图来从有雾图像中获取该值。具体步骤如下:

(1) 从暗通道图中按照亮度的大小取前0.1%的像素。(经过导向滤波这应为投射率图)

(2)在这些位置中,在原始有雾图像I中寻找对应的具有最高亮度的点的值,作为A值。

使用累计灰度直方图来实现求A值

bins = 256  
hist = np.histogram(V, bins)                  #灰度直方图

这里V是待统计数据数组,bins为等分数。返回值有两个:

hist[0]:hist:array,返回数组V中的数据在每个等分区间的个数。

hist[1]:bin_degs,长度为len(hist)+1,为分组的边界。(bin_degs[0], bin_edgs[1])=hist[0]

normHist = hist[0]/float(V.size)              #归一化灰度直方图

概率直方图,灰度值k的像素点个数占的图比例

accumulativeHist = np.cumsum(normHist)    #累计直方图

代表图像组成成分在灰度级的累计概率分布情况,每一个概率值代表小于等于此灰度值的概率。

for k in range(bins-1, 0, -1):
        
        if accumulativeHist[k]<=0.999:             #取前0.1%的像素,并获得该位置k
            break 
        
A  = np.mean(m,2)[V>=hist[1][k]].max()        #在原始有雾的图像I中寻找对应的具有最高亮度的点的值

这里返回的k值就是边界值k。

到这一步,我们就可以进行无雾图像的恢复了。由式(1)可知:  J = ( I - A)/t + A  

现在I,A,t都已经求得了,因此,完全可以进行J的计算。

当投射图t 的值很小时,会导致J的值偏大,从而使淂图像整体向白场过度,因此一般可设置一阈值T0,当t值小于T0时,令t=T0,本文中所有效果图均以T0=0.1为标准计算。

因此,最终的恢复公式如下:

实验结果对比:

Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第6张图片Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第7张图片

Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第8张图片Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第9张图片

Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第10张图片Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第11张图片

Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第12张图片Single Image Haze Removal Using Dark Channel Prior 论文阅读与代码实现_第13张图片

 

你可能感兴趣的:(数字图像处理,Python,OpenCV)