基于暗通道的图像去雾算法简单实现

如果还不了解去雾的具体过程,可以看何凯明博士的论文,英语不好的同学看这篇论文的 翻译版本

代码如下:

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了,但是我测试了一下并没有,我继续测试其他图片希望能找到一些原因,直到我看到这个图片的效果,我有了一个假设:

这张图片是我测试图片中效果最差的,不过也是因为这一张图片,我觉得可能是透射图不够精细造成的问题,这也和我之前请教其他同学得到的答复基本一致。何博士的论文中也提到了更加精细化的方法,但是可能会很慢,直到导向图滤波论文发表。目前我还没有具体的实现导向图滤波。

发布了45 篇原创文章 · 获赞 21 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_38863413/article/details/97053720