如果还不了解去雾的具体过程,可以看何凯明博士的论文,英语不好的同学看这篇论文的 翻译版本
代码如下:
import cv2
import numpy as np
img=cv2.imread("img1.png")
window_size=15
kernal=(window_size-1)//2
padding=kernal
# 求取暗通道:
# 建立一个灰度图,长宽和原图一致(不算 padding)
dst=np.array([255]*(img.shape[0]+kernal*2)*(img.shape[1]+kernal*2),np.uint8)
dst=dst.reshape(img.shape[0]+kernal*2,img.shape[1]+kernal*2)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
dst[i+padding,j+padding]=min(img[i,j])
# 在每一个位置 x 上,求在 15 * 15 大小的范围内的最小值,将此最小值最为灰度图中该点的像素。
dark=np.zeros(img.shape,np.uint8)
for i in range(padding,img.shape[0]+padding):
for j in range(padding,img.shape[1]+padding):
temp =dst[i - padding:i + padding, j - padding:j + padding]
min_value=np.min(temp)
dark[i - padding, j - padding] = min_value
# 求 A 值:
# 找出暗通道图像中 强度最大的前 0.1%,并将值保存起来。
pxs=list(np.sort(dark.reshape((1,-1))[0]))
pxs.reverse()
s=set(pxs[0:int(len(pxs)*0.001)])
# 在暗通道上找到这些像素的位置:
Ar=0
Ag=0
Ab=0
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if min(img[i,j]) in s:
Ab=max(Ab,img[i,j][0])
Ag=max(Ag,img[i,j][1])
Ar=max(Ar,img[i,j][2])
A=np.array([min(220,Ab),min(220,Ag),min(220,Ar)])
# 求透射率:
tarr=np.array([255]*(img.shape[0]+kernal*2)*(img.shape[1]+kernal*2),np.float64)
tarr=tarr.reshape((-1,img.shape[1]+kernal*2))
for i in range(img.shape[0]):
for j in range(img.shape[1]):
tarr[i+padding,j+padding]=min(img[i,j]/A)
tchannel=np.zeros((img.shape[0],img.shape[1]),np.float64)
w=0.95
for i in range(padding,img.shape[0]+padding):
for j in range(padding,img.shape[1]+padding):
temp=tarr[i-padding:i+padding,j-padding:j+padding]
min_value=np.min(temp)
tchannel[i-padding][j-padding]=1-w*min_value
result=np.zeros(img.shape,np.uint8)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
result[i,j]=np.uint8(((img[i,j]-A)/max(tchannel[i,j],0.1))+ A)
cv2.imshow("origen",img)
cv2.imshow("tchannel",tchannel)
cv2.imshow("dark channel",dark)
cv2.imshow("resut",result)
cv2.waitKey(0)
numpy 还是比较方便的,代码比较简洁。
流程的话比较简单,首先要求暗通道,我先建立一个灰度图,大小和原图一致,然后遍历原图像素,取三个通道中的最小值作为灰度图的像素值,然后选定了一个15*15大小的窗口,窗口中心位置的像素替换为在这个窗口范围内的最小值,得到了暗通道。然后求A值,有其他论文使用的是原图中强度最大的作为A值,何博士的论文中采用的是在暗通道中寻找强度在前0.1% 的像素所在的位置,在原图的这些位置中的最大值作为 A值,这样得到的A值不一定就是整张图片中强度最大的。然后就是求透射率,方法和暗通道类似,不同的是每一个像素都要除以A值然后在进行运算。最后根据论文上的公式直接计算出结果图,本以为会一切顺利,但是确出现了一些色斑,请教了做过的同学,他们说就是会有,使用导向图滤波可以有效消除这些色斑,还没尝试。
下面是一些测试的结果:
图像一
可以看到结果图中色斑还是比较明显的。
图像二:
上面这些图像都有一些色斑,有同学说是因为某一点的值大于255了,但是我测试了一下并没有,我继续测试其他图片希望能找到一些原因,直到我看到这个图片的效果,我有了一个假设:
这张图片是我测试图片中效果最差的,不过也是因为这一张图片,我觉得可能是透射图不够精细造成的问题,这也和我之前请教其他同学得到的答复基本一致。何博士的论文中也提到了更加精细化的方法,但是可能会很慢,直到导向图滤波论文发表。目前我还没有具体的实现导向图滤波。