本文为基于何恺明博士的Single Image Haze Removal Using Dark Channel Prior和Guided Image Filtering两篇论文的去雾算法python代码实现。

1 一些基本的定义

1.1 雾图成像模型


I(x)为原图,J(x)为无雾图像,A是大气光成分,为一常数。t(x)为透光率。
其含义就是图像I(x)为事物反射的光经过雾气衰减后加上雾气反射的大气光的结合所成的像。

1.2 暗通道定义

1.3 计算投射图t(x)




这里是一个作者统计了大量图片得出的结论,即无雾图片的暗通道是接近于0的。


实际上,即使在晴天,大气中也不是完全没有任何粒子。所以当我们看远处的物体时,雾仍然存在。 所以,我们可以通过引入一个常量参数w(0<w<1)论文取值为0.95,为远处的物体保留少量的雾。
这样t(x)会比原来大,大气光的权重会小点,使得图片整体更暗?

暗通道先验对于天空区域来说不是一个好的先验。幸运的是,在朦胧的图像I中,天空的颜色通常与大气光A非常相似,即下式趋近1。所以,在这些位置t(x)趋于0。因为天空是无限遥远的,它的传输确实接近于零。所以我们不需要预先分离天空区域。

1.4 导向滤波

详见我的另一篇文章导向滤波与opencv python实现。

2 代码

2.1 获得暗通道

def get_min_channel(img):return np.min(img,axis=2)

最小值滤波器,其实与腐蚀一样:

def min_filter(img,r):kernel = np.ones((2*r-1,2*r-1))return cv2.erode(img,kernel)#最小值滤波器,可用腐蚀替代

2.2 大气光照A计算

通常雾最浓地方的颜色被作为大气光的估计值,可以通过暗通道来确定雾气最浓的地方,即暗通道最亮的区域为雾气最浓的地方,此时,大气光为唯一的光源。
首先选择暗通道中最亮的0.1%像素。这些像素通常是最不透明的。在这些像素中,选择输入图像I中强度最高的像素作为大气光。

def get_A(img_haze,dark_channel,bins_l):hist,bins = np.histogram(dark_channel,bins=bins_l)#得到直方图d = np.cumsum(hist)/float(dark_channel.size)#累加# print(bins)threshold=0for i in range(bins_l-1,0,-1):if d[i]<=0.999:threshold=ibreakA = img_haze[dark_channel>=bins[threshold]].max()#候选区域可视化show  = np.copy(img_haze)show[dark_channel>=bins[threshold]] = 0,0,255cv2.imwrite('./most_haze_opaque_region.jpg',show*255)return A

暗通道最亮的区域如下图红色区域处:

2.3 计算t(x)

def get_t(img_haze,A,t0=0.1,w=0.95):out = get_min_channel(img_haze)out = min_filter(out,r=7)t = 1-w*out/A #需要乘上一系数w,为远处的物体保留少量的雾t = np.clip(t,t0,1)#论文4.4所提到t(x)趋于0容易产生噪声,所以设置一最小值0.1return t

这时候得出来的结果如下图:

因为没有经过导向滤波细化传输,所以效果有点差。

2.4 导向滤波

以还未进行最小值滤波的暗通道图(用暗通道图效果会很差)作为导向图对t(x)进行导向滤波,细化传输。
输入图像必须得先进行归一化后再处理,否则滤波后会有超过255的值

def guided_filter(I,p,win_size,eps):mean_I = cv2.blur(I,(win_size,win_size))mean_p = cv2.blur(p,(win_size,win_size))corr_I = cv2.blur(I*I,(win_size,win_size))corr_Ip = cv2.blur(I*p,(win_size,win_size))var_I = corr_I-mean_I*mean_Icov_Ip = corr_Ip - mean_I*mean_pa = cov_Ip/(var_I+eps)b = mean_p-a*mean_Imean_a = cv2.blur(a,(win_size,win_size))mean_b = cv2.blur(b,(win_size,win_size))q = mean_a*I + mean_breturn q

得到的结果如下图所示:


与原图相比:

可见去雾效果还是不错的。

2.5 评估

PSNR

def PSNR(target,ref):#必须归一化target=target/255.0ref=ref/255.0MSE = np.mean((target-ref)**2)if MSE<1e-10:return 100MAXI=1PSNR = 20*math.log10(MAXI/math.sqrt(MSE))return PSNR

SSIM

from skimage.metrics import structural_similarity as sk_cpt_ssim
ssim = sk_cpt_ssim(J,I*255, win_size=11, data_range=255, multichannel=True)

2.6 完整代码

# -*- coding: utf-8 -*-
# @Time : 2022/10/1 23:08
# @Author : shuoshuo
# @File : main.py
# @Project : 去雾
import cv2
import numpy as np
import matplotlib.pyplot as plt
import math
from skimage.metrics import structural_similarity as sk_cpt_ssimdef guided_filter(I,p,win_size,eps):mean_I = cv2.blur(I,(win_size,win_size))mean_p = cv2.blur(p,(win_size,win_size))corr_I = cv2.blur(I*I,(win_size,win_size))corr_Ip = cv2.blur(I*p,(win_size,win_size))var_I = corr_I-mean_I*mean_Icov_Ip = corr_Ip - mean_I*mean_pa = cov_Ip/(var_I+eps)b = mean_p-a*mean_Imean_a = cv2.blur(a,(win_size,win_size))mean_b = cv2.blur(b,(win_size,win_size))q = mean_a*I + mean_breturn q
def get_min_channel(img):return np.min(img,axis=2)
def min_filter(img,r):kernel = np.ones((2*r-1,2*r-1))return cv2.erode(img,kernel)#最小值滤波器,可用腐蚀替代
def get_A(img_haze,dark_channel,bins_l):hist,bins = np.histogram(dark_channel,bins=bins_l)#得到直方图d = np.cumsum(hist)/float(dark_channel.size)#累加# print(bins)threshold=0for i in range(bins_l-1,0,-1):if d[i]<=0.999:threshold=ibreakA = img_haze[dark_channel>=bins[threshold]].max()#候选区域可视化show  = np.copy(img_haze)show[dark_channel>=bins[threshold]] = 0,0,255cv2.imwrite('./most_haze_opaque_region.jpg',show*255)return A
def get_t(img_haze,A,t0=0.1,w=0.95):out = get_min_channel(img_haze)out = min_filter(out,r=7)t = 1-w*out/A #需要乘上一系数w,为远处的物体保留少量的雾t = np.clip(t,t0,1)#论文4.4所提到t(x)趋于0容易产生噪声,所以设置一最小值0.1return t
def PSNR(target,ref):#必须归一化target=target/255.0ref=ref/255.0MSE = np.mean((target-ref)**2)if MSE<1e-10:return 100MAXI=1PSNR = 20*math.log10(MAXI/math.sqrt(MSE))return PSNRif __name__ == '__main__':I = cv2.imread('test.jpg')/255.0dark_channel = get_min_channel(I)dark_channel_1 = min_filter(dark_channel,r=7)# cv2.imwrite("./dark_channel.jpg", dark_channel_1*255)A = get_A(I,dark_channel_1,bins_l=2000)t = get_t(I,A)t = guided_filter(dark_channel,t,81,0.001)t = t[:,:,np.newaxis].repeat(3,axis=2)#升维至(r,w,3)J = (I-A)/t +AJ = np.clip(J,0,1)J = J*255J =np.uint8(J)cv2.imwrite("./result.jpg",J)#评估PSNR = PSNR(J,I*255)print(f"PSNR:{PSNR}")ssim = sk_cpt_ssim(J,I*255, win_size=11, data_range=255, multichannel=True)print(f"ssim:{ssim}")

3 参考文献

何恺明的两篇论文:
Single Image Haze Removal Using Dark Channel Prior
Guided Image Filtering
论文链接
Dehazing for Image and Video Using Guided Filter

暗通道去雾 python实现相关推荐

  1. Python 还能实现图片去雾?FFA 去雾算法、暗通道去雾算法用起来!(附代码)...

    授权自AI科技大本营(ID:rgznai100) 本文约3600字,建议阅读7分钟. 本文为你介绍FFA去雾算法和暗通道去雾算法搭建. 在过去的几十年中,单图像去雾作为基本的低级视觉任务已引起了计算机 ...

  2. Python 还能实现图片去雾?FFA 去雾算法、暗通道去雾算法用起来! | 附代码

    在过去的几十年中,单图像去雾作为基本的低级视觉任务已引起了计算机视觉社区和人工智能公司的越来越多的关注.其中最为典型的便是北大&北航提出FFA-Net去雾新网络和何凯明博士提出的暗通道去雾算法 ...

  3. Python实现暗通道去雾算法——清晰还原雾天景色

    Python实现暗通道去雾算法--清晰还原雾天景色 在雾天拍摄照片时,画面会变得模糊不清,影响了图片的观感和质量.为了解决这个问题,学术界提出了一种称为"暗通道先验"的方法,这种方 ...

  4. 纯c语言实现的改进暗通道去雾算法测试程序(附赠大量测试图像),基于改进暗通道先验算法的图像去雾...

    邱清辉 摘要:针对普通暗通道先验算法去雾能力的不足,本文提出了一种改进算法,通过采用高斯平滑将原图像分为基础子图和细节子图,基础子图采用暗通道先验算法,细节子图采用gamma变换方法,再采用图像融合进 ...

  5. 半年以来的图像去雾总结-图像去雾(一)暗通道去雾

    图像去雾最好的算法原型最好的莫过于何凯明博士的论文--好好阅读,必有灵感 在接下来的博客中,我会分步介绍各个图像去雾算法的研究和对比,在这里,首先介绍最经典的何凯明博士的暗通道去雾算法了,后面的博客有 ...

  6. 暗通道去雾(何恺明的成名作):简洁与效果并存的传统图像处理算法

    本篇博客主要作用为学习代码段与快应用的使用,内容浅显,还请路过的大佬见谅>_< 暗通道去雾算法(Single image haze removal using dark channel p ...

  7. 何恺明暗通道去雾(阅读笔记)

    何恺明暗通道去雾文章阅读 刘海山,2021年6月24日 文献引文信息: He, K. M., Sun, J. & Tang, X. O. Single Image Haze Removal U ...

  8. 暗通道去雾法-对算法的理解Dark Channel Prior

    暗通道最早是由He提出的,并且也发展得很快,具体的在这里不说,这篇文章,只是谈一下暗通道去雾的实现过程 1.该方法最原始的模型是I=Jt+A(1-t),这个模型在我的其他文章中有详细介绍,这里不详细讲 ...

  9. 暗通道去雾算法代码实现(1) python

    文章目录 前言 一.腐蚀膨胀操作 二.何凯明去雾论文思想的简单描述 1.关于暗通道先验 2.暗通道先验的理论依据: 3.有雾图像的形成模型 4.传输率t的估计 5.大气光的估计 6.使用导向滤波对传输 ...

最新文章

  1. 计算机网络:自顶向下方法(第七版)Wireshark实验指南
  2. golang中的httptest
  3. GPUimage实时滤镜的实现
  4. Linux下的Ubuntu16.04系统配置并使用USB转串口(串口转USB),最终使用python的serial和pyserial包实现串口的打开并读取数据
  5. 用简单的例子说明提升可复用性的设计模式
  6. mybatis 取传进来的参数 mybatis #{ } ${ }区别是啥?
  7. 简述python_简述Python语言经验总结
  8. 大数据要学javaweb吗_大数据是私有财产吗?
  9. mac使用国内镜像安装homebrew
  10. ASCII码对照表 包含二进制、十进制、十六进制
  11. 那人立在侧边 水浒传
  12. Dota2 比赛匹配
  13. 计算机专业博士后 解决北京户口,在职博士后落北京户口可以么?该如何操作
  14. 001Diamond学习002使用
  15. 参赛邀请 | 第二届古汉语自动分析国际评测EvaHan(古汉语机器翻译)开始报名...
  16. 在lomboz eclipse 3.3中配置tomcat7/8 server运行时环境遇到的问题
  17. Linux:进程控制
  18. 攻防世界 super sqli write up
  19. 「巨杉学」开展大数据金融人才培养模式探索课题培训
  20. MATLAB绘制正弦函数与余弦函数的线性组合曲线

热门文章

  1. STM32F103ZET6IAP升级
  2. win10Word文档点击后文件资源管理器卡死转篮圈问题解决
  3. python3学习日记——运算符
  4. 新项目代码导入idea注解报红处理
  5. Linq和Lambda学习
  6. 网联接口,直连接口,资金流入的监管和博弈
  7. php 获取用户登录IP 及 IP归属地
  8. python爬虫基础 - XPATH
  9. 网页配色搭配、页面配色搭配、设计配色搭配
  10. 查询局域网内所有再用ip