《Single Image Haze Removal Using Dark Channel Prior》
这篇文章是何大神于09发表在cvpr上的传统图像处理方向的文章,直到现在其效果任然不输于深度网络。
论文连接:https://ieeexplore.ieee.org/document/5567108/
代码连接:见文章末
在本文中,我们提出了一个简单但有效的图像先验暗通道,以去除单一输入图像的雾霾。暗通道先验是一种无雾霾户外图像的统计数据。它是基于一个关键的观察—— 在无雾的户外图像中的大多数局部斑块包含一些在至少一个颜色通道中强度非常低的像素。 利用此先验的雾霾成像模型,我们可以直接估计雾霾的厚度,恢复一个高质量的无雾霾图像。对各种户外雾霾图像的研究结果表明了所提出的先验的能力。此外,一个高质量的深度图也可以获得作为去除雾霾的副产品。
雾霾、雾和烟雾是大气吸收和散射产生的现象。摄像机从场景点接收到的辐照度沿着视线被衰减。
雾霾去除在计算机视觉上的应用:
然而,由于雾霾是一个未知的深度信息,因此雾霾去除是一个具有挑战性的问题。如果输入只是一个雾霾图像,则该问题是欠约束的。因此,许多方法被提出通过使用多个图像或附加信息。基于偏振的方法通过拍摄两幅或多张不同偏振程度的图像来消除雾霾效应。在中,从不同天气条件下同一场景的多个图像中获得更多的约束。基于深度的方法需要从用户输入或已知的3D模型的粗略深度信息。
近年来,单图像雾霾去除取得了重大进展。
与任何使用强假设的方法一样,我们的方法也有它自己的局限性。当场景对象在一个大的局部区域上与空气相似,并且没有在对象上投射阴影时,暗通道先验可能无效。 虽然我们的方法对大多数户外雾霾图像都很有效,但在一些极端情况下可能会失败。
在计算机视觉和计算机图形学中,广泛用于描述雾霾图像形成的模型如下:
其中I是观测到的强度,J是场景辐射,A是全球大气光,t是描述未散射到达相机的部分的介质透射。去除雾霾的目标是从I中恢复J、A和t。
方程(1)右侧的第一项J(x)t(x)称为直接衰减,第二项A(1−t(x))称为空气光。直接衰减描述了场景辐射及其在介质中的衰减,而空气光是由先前的散射光产生的,并导致场景颜色的变化。当大气均匀时,传输t可以表示为:
其中,β为大气的散射系数。这表明场景亮度随场景深度d呈指数衰减。
几何上,雾霾成像方程(1)表示在RGB颜色空间中,向量A、I(x)和J(x)是共面的,它们的端点是共线的,传输t为两个线段之比:
其中,c∈{r,g,b}是颜色通道索引。
暗通道先验是基于以下对无雾霾户外图像的观察:在大多数非天空斑块中,至少有一种颜色通道在某些像素处的强度非常低。换句话说,这样一个补丁的最小强度应该有一个非常低的值。在形式上,对于图像J,我们进行了定义:
其中 J c J^c Jc是 J J J的颜色通道, Ω ( x ) Ω(x) Ω(x)是一个以 x x x为中心的局部补丁。我们的观察表明,除了天空区域外,如果J是一个无雾霾的户外图像,那么 J d a r k J^{dark} Jdark的强度较低,且趋于零。我们称 J d a r k J^{dark} Jdark为 J J J的暗通道,我们称上述统计观察或知识为暗通道。
(自认为暗通道可以理解为某目标像素的指定领域内,综合考量RGB通道的最低像素值)
暗通道中的低强度主要是由于三个因素:a)阴影。 例如,城市景观图像中汽车、建筑物和窗户内部的阴影,或景观图像中树叶、树木和岩石的阴影;b)丰富多彩的物体或表面。 例如,任何颜色通道中缺乏颜色的物体(例如,绿草/树/植物、红色或黄色的花/叶和蓝色水面)将导致黑暗通道中的低值;c)深色物体或表面。 例如,深色的树干和石头。由于自然的户外图像通常是充满了阴影和丰富多彩的,这些图像的黑暗通道真的是黑暗的!
使用黑暗通道预先去除雾霾
这里首先可以假设大气光A已知;在局部范围内(patch) Ω ( x ) Ω(x) Ω(x)是恒定的。我们将patch的传输表示为 t ′ ( x ) t'(x) t′(x)。最小化公式(1):
变形:
然后,我们对上述公式取三个颜色通道之间的最小运算,得到:
根据暗通道公式,无雾霾的辐射场J应该趋向于0:
由于A总为正常数,所以:
将(10)带入(8)有:
正如我们之前提到的,黑暗通道先验对天空区域并不是一个好的先验。幸运的是,天空的颜色通常与雾霾图像中的大气光A非常相似,我们有:
由于天空是无限的,并且趋向于零传输,方程(11)可以优雅地处理天空区域和非天空区域。我们不需要事先分开天空区域。
此外,雾霾的存在是人类感知深度的基本线索。这种现象被称为空中透视现象。如果我们彻底去除雾霾,图像可能会看起来不自然,深度的感觉可能会消失。
因此,我们可以通过在方程中引入一个常数参数ω(0<ω≤1)来为遥远的物体保持非常少量的雾霾
用t(x)表示精确的传输图。将t(x)和t˜(x)以它们的向量形式重写为t和˜t,我们最小化以下代价函数:
其中L为Levin提出的马丁拉普拉斯矩阵,λ为正则化参数。第一项是光滑项,第二项是数据项。
通过求解以下稀疏线性系统,可以得到最优t:
其中U是一个与L大小相同的单位矩阵。这里,我们在λ上设置一个小值(在我们的实验中是 1 0 − 4 10^{−4} 10−4),使t受到˜t的软约束。
利用传输图,我们可以根据公式(1)恢复场景亮度。但是,当传输t(x)接近于零时,直接衰减项J(x)t(x)可以非常接近于零。直接恢复的场景辐射J容易产生噪声。因此,我们将传输t(x)限制在一个下界t0,这意味着在非常密集的雾霾区域保留了少量的雾霾。最终场景亮度J(x)恢复:
t0的典型值是0.1。由于场景的亮度通常不如大气光明亮,去除雾霾后的图像看起来很暗淡。因此,我们增加了J(x)的曝光率来进行显示。
我们可以利用暗通道来改进大气光的估计。我们首先选择暗通道中最亮的0.1%的像素。这些像素是最模糊不透明的。在这些像素中,选择输入图像I中强度最高的像素作为大气光。
代码参考:https://blog.csdn.net/wsp_1138886114/article/details/95012769
import cv2
import numpy as np
def zmMinFilterGray(src, r=7):
'''最小值滤波,r是滤波器半径'''
return cv2.erode(src, np.ones((2 * r + 1, 2 * r + 1)))
def guidedfilter(I, p, r, eps):
height, width = I.shape
m_I = cv2.boxFilter(I, -1, (r, r))
m_p = cv2.boxFilter(p, -1, (r, r))
m_Ip = cv2.boxFilter(I * p, -1, (r, r))
cov_Ip = m_Ip - m_I * m_p
m_II = cv2.boxFilter(I * I, -1, (r, r))
var_I = m_II - m_I * m_I
a = cov_Ip / (var_I + eps)
b = m_p - a * m_I
m_a = cv2.boxFilter(a, -1, (r, r))
m_b = cv2.boxFilter(b, -1, (r, r))
return m_a * I + m_b
def Defog(m, r, eps, w, maxV1): # 输入rgb图像,值范围[0,1]
'''计算大气遮罩图像V1和光照值A, V1 = 1-t/A'''
V1 = np.min(m, 2) # 得到暗通道图像
Dark_Channel = zmMinFilterGray(V1, 7)
cv2.imshow('20190708_Dark',Dark_Channel) # 查看暗通道
cv2.waitKey(0)
cv2.destroyAllWindows()
V1 = guidedfilter(V1, Dark_Channel, r, eps) # 使用引导滤波优化
bins = 2000
ht = np.histogram(V1, bins) # 计算大气光照A
d = np.cumsum(ht[0]) / float(V1.size)
for lmax in range(bins - 1, 0, -1):
if d[lmax] <= 0.999:
break
A = np.mean(m, 2)[V1 >= ht[1][lmax]].max()
V1 = np.minimum(V1 * w, maxV1) # 对值范围进行限制
return V1, A
def deHaze(m, r=81, eps=0.001, w=0.95, maxV1=0.80, bGamma=False):
Y = np.zeros(m.shape)
Mask_img, A = Defog(m, r, eps, w, maxV1) # 得到遮罩图像和大气光照
for k in range(3):
Y[:,:,k] = (m[:,:,k] - Mask_img)/(1-Mask_img/A) # 颜色校正
Y = np.clip(Y, 0, 1)
if bGamma:
Y = Y ** (np.log(0.5) / np.log(Y.mean())) # gamma校正,默认不进行该操作
return Y
if __name__ == '__main__':
m = deHaze(cv2.imread('fog1.jpg') / 255.0) * 255
cv2.imwrite('1.jpg', m)