Single Image Haze Removal Using Dark Channel Prior(暗通道先验)
去雾算法都会依赖于很强的先验以及假设,并结合相应的物理模型,完成去雾过程。本文作者何凯明及其团队通过大量的无雾图像和有雾图像,归纳总结出无雾图像在其对应的暗通道图像上具有极低的强度值(趋近于0),并结合如下公式:

求出透射率参数以及全球大气光值,进而轻松的求取无雾图像J。
1、暗通道先验是什么?
暗通道先验是基于户外的的无雾图像总结归纳的,发现的一个普遍存在的现象就是:在大多数的非天空的图像块中,至少有一个图像通道的一些像素值是非常低且接近于0的。作者使用J_dark来表示暗通道图像,具体的计算公式如下所示:

上述公式可以知道,对于无雾图像y,求取其三通道对应像素为的最小值,并使用一个固定大小(15*15)的块去取其中最小的值即为当前像素的暗通道值。
下图很明显的展示了有雾与无雾图像的暗通道图像的差异:对于有雾图像(不考虑天空),暗通道图像偏白,也就是其强度值比较高,而对于无雾图像,暗通道图像整体偏黑,也就是其强度值比较低。

按照暗通道的定义就可以很清楚的知道:

上述公式就是本文的精髓暗通道先验,就是这么一个普普通通的经验总结,但是没有人想到。
作者在发现这个先验以后,还去做了很多的验证工作,其中就包括:
(1)随机选取5000张landscape+cityscape场景的数据,在剪裁掉天空部分后,resize到最长边为500的图像,使用15*15的核区域去计算暗通道图像,统计其强度概率分布图、累积概率强度分布图、图像的强度分布图

得出的结论是:
1、We can see that about 75 percent of the pixels in the dark channels have zero values, and the intensity of 90 percent of the pixels is below 25
2、most dark channels have very low average intensity, showing that only a small portion of outdoor haze-free images deviate from our prior
2、使用暗通道先验进行去雾
2.1 估计透射参数t
假设全球大气光值A是一个常量,利用公式(1)进行归一化操作可得:

接着假设t在一个固定大小的块中是恒定值,并且在公式(7)的两边同时求取暗通道值:

对于无雾图像来说J趋近于0的:

因此可以得出:

通过上述几个公式联合求解可得:

这里有一个特殊的点是:作者之前在讲解暗通道先验的时候排除了天空的干扰问题,但是通过公式(11)可以知道,对于有雾的天空而言,I和大气光参数A基本一致,因此:

对于天空来说t->0,说明对于天空来说,因为距离无限远,反射率基本等于0是完全合理的。因此作者很优雅的处理了暗通道中的非天空数据,不用特意将天空数据裁剪完成后方才进行暗通道计算。
实际环境下,无论天气如何晴朗,都会存在一些颗粒和雾气,这种现象称为aerial perspective,如果我们直接移除雾气,会让去雾后的图像看起来非常不自然,因此需要保留一定的雾气,而这就导致反射率需要加一些补偿值:

2.2 估计大气光值A
作者依托于Tan的理论:有雾图像中最亮的像素点是最不透明的,这主要针对是阴霾而没有阳光的天气,在这种情况下,大气光是照明的唯一来源,因此每个通道的颜色场景亮度为:

同时公式(1)可以改写为:
当图像中的像素处于无线远的位置时,最亮点的像素时最haze-opaque的,可近似为A。但是实际经验告诉我们不能忽略阳光,因此在考虑阳光照射的情况下,公式(18),(19)就需要改写为:


因此,图像中最亮的像素点可以比大气光值A大,可能会出现在白色的小汽车或者白色建筑物上
依据暗通道先验,有雾图像的暗通道图表征其雾浓度,因此可以通过有雾图像的暗通道图来检测物浓度最大的区域,进而去提升大气光值的估计。
最终的方法是:首先获取图像的暗通道图,接着获取暗通道图中top 0.1%的的最亮像素点,然后选取暗通道图最亮像素点所对应的原始图像强度值最大的值作为大气光值。
2.3 图像重建
在得到大气光值A以及相应的透射率参数t以后,可以利用22式进行求解并获取相应的无雾图像。

2.4 番外篇
由于透射参数t的求解比较粗暴,导致得到的t图比较粗糙,为了进行细腻处理,作者使用soft matting进行图像的refine,下图是对比:

Soft matting的效果明显比直接求出的t值好很多,但是有一个致命的缺点是速度比较慢,因此在2010年何凯明使用引导滤波(guided filter)进行加速。
3 代码实现
3.1暗通道图求解
暗通道图就是对图像的RGB三通道求取最小值,然后在用一个核去取最小值,当然简便的方法是构造一个核,直接使用腐蚀操作进行实现。
def cal_Dark_Channel(im, width = 15):im_dark = np.min(im, axis = 2)border = int((width - 1) / 2)im_dark_1 = cv2.copyMakeBorder(im_dark, border, border, border, border, cv2.BORDER_DEFAULT)res = np.zeros(np.shape(im_dark))for i in range(res.shape[0]):for j in range(res.shape[1]):res[i][j] = np.min(im_dark_1[i: i + width, j: j + width]) return res
3.2 求解大气光值A
#计算A参数, im为暗通道图像, img为原图def cal_Light_A(im, img):s_dict = {}for i in range(im.shape[0]):for j in range(im.shape[1]):s_dict[(i, j)] = im[i][j]s_dict = sorted(s_dict.items(), key = lambda x: x[1]) A = np.zeros((3, ))num = int(im.shape[0] * im.shape[1] * 0.001)for i in range(len(s_dict) - 1, len(s_dict) - num - 1, -1):X_Y = s_dict[i][0]A = np.maximum(A, img[X_Y[0], X_Y[1], :])return A
3.3 反射率参数t
def cal_trans(A, img, w = 0.95):dark = cal_Dark_Channel(img / A)t = np.maximum(1 - w * dark, 0)return t
3.4 使用引导滤波进行优化t
def Guided_filtering(t, img_gray, width, sigma = 0.0001):mean_I = np.zeros(np.shape(img_gray))cv2.boxFilter(img_gray, -1, (width, width), mean_I, (-1, -1), True, cv2.BORDER_DEFAULT)mean_t = np.zeros(np.shape(t))cv2.boxFilter(t, -1, (width, width), mean_t, (-1, -1), True, cv2.BORDER_DEFAULT)corr_I = np.zeros(np.shape(img_gray))cv2.boxFilter(img_gray * img_gray, -1, (width, width), corr_I, (-1, -1), True, cv2.BORDER_DEFAULT)corr_IT = np.zeros(np.shape(t))cv2.boxFilter(img_gray * t, -1, (width, width), corr_IT, (-1, -1), True, cv2.BORDER_DEFAULT)var_I = corr_I - mean_I * mean_Icov_IT = corr_IT - mean_I * mean_ta = cov_IT / (var_I + sigma) b = mean_t - a * mean_Imean_a = np.zeros(np.shape(a))mean_b = np.zeros(np.shape(b))cv2.boxFilter(a, -1, (width, width), mean_a, (-1, -1), True, cv2.BORDER_DEFAULT)cv2.boxFilter(b, -1, (width, width), mean_b, (-1, -1), True, cv2.BORDER_DEFAULT)return mean_a * img_gray + mean_b
3.5 图像恢复
def harz_Rec(A, img, t, t0 = 0.1):img_o = np.zeros(np.shape(img))img_o[:, :, 0] = (img[:, :, 0] - A[0]) / (np.maximum(t, t0)) + A[0]img_o[:, :, 1] = (img[:, :, 1] - A[1]) / (np.maximum(t, t0)) + A[1]img_o[:, :, 2] = (img[:, :, 2] - A[2]) / (np.maximum(t, t0)) + A[2]return img_o
参考文献
走出寂静岭!暗通道先验的python实现
https://github.com/vaeahc/Dark_Channel_Prior/blob/master/Dark_Channel_Prior.py
相关文章:
Single Image Haze Removal Using Dark Channel Prior(暗通道先验)
去雾算法都会依赖于很强的先验以及假设,并结合相应的物理模型,完成去雾过程。本文作者何凯明及其团队通过大量的无雾图像和有雾图像,归纳总结出无雾图像在其对应的暗通道图像上具有极低的强度值(趋近于0),并…...
力扣382.链表随机节点(java利用数组随机返回节点值)
Problem: 382. 链表随机节点 文章目录 思路解题方法复杂度Code 思路 注意链表与数组的特性,对于随机访问读取的操作利用数组可以较方便实现,所以我们可以将链表中的节点值先存入到数组中最后再取出随机生成节点位置的值。 解题方法 1.生成List集合与Rand…...
在jupyter中使用R
如果想在Jupyter Notebook中使用R语言,以下几个步骤操作可行: 1、启动Anaconda Prompt 2、进入R的安装位置,切换到R的安装位置:D:\Program Files\R\R-3.4.3\bin,启动R,具体代码操作步骤如下,在…...
2023(第四届)江西开放数据创新应用大赛等你来挑战!
邀请函 这是一个友好的邀请。无论你是数据领域的专家、学生还是爱好者,我们都欢迎你加入这个平台。这不仅仅是一场比赛,更是一个交流、学习和展示自己的机会。 丰厚奖金:我们为参赛者准备了总计15W的奖金池,期待你的才华在这里得…...
2023-mac rz sz 安装
之前安装过一次,没问题,这次按照之前教程装了就不管上传下载都会卡住; step1: brew install lrzsz step2:在/usr/local/bin 路径下配置两个sh,之前从网上找到的直接用都不对,下面这个是调试过的正式可用的 iterm2…...
使用Matplotlib绘画3D图时运行不出结果,也不报错,图片是空白 !!
1.问题: 我使用如下代码运用matplotlib中的Axes3D绘画3D图,但是运行出来的结果是空白。 import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D #导入3D包 fig plt.figure() #窗口 #ax Axes3D(fig) # X, Y …...
Matlab函数——find
介绍 当你需要返回某个数组中符合指定条件的所有元素的索引时,可以使用 MATLAB 中的 find 函数。 find 函数语法: indices find(X) indices find(X, k) indices find(X, k, first) indices find(X, k, last) 其中,X 是一个数组…...
mac安装python3
文章目录 1. 安装1.1 brew安装(失败)2. 下载安装包 2. 查看版本3. 配置 1. 安装 1.1 brew安装(失败) brew install python3下载完成后报错:Error: python3.10: unknown or unsupported macOS version: :dunno 解决&a…...
【星海出品】VUE(一)
Windows安装nvm控制器 Windows里找都PowerShell。右击点击管理员运行。 1.安装choco Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString(https://chocolatey.org/install.ps1))2.安装NVM choco install nvm 3.查看可…...
Stable Diffusion 的提示词使用技巧
推荐Stable Diffusion自动纹理工具: DreamTexture.js自动纹理化开发包 什么是提示语? 提示语是人工智能中的一个重要组成部分,尤其是自然语言处理 (NLP)。在AI自人工智能中,想要获得好的效果,简…...
Hook函数
在嵌入式系统中,hook函数(也被称为钩子函数)是一种特殊类型的函数,它会在特定的事件发生时被操作系统内部调用。例如,在实时操作系统(RTOS)中,如果删除了一个任务,就会调…...
USB简介系列-01
文章目录 USB简介一、电气USB简介 通用串行总线(USB)是由Compaq,Intel,Microsoft和NEC开发的规范,后来惠普,朗讯和飞利浦加入。这些公司成立了 USB Implementers Forum, Inc 作为一家非营利性公司,以发布规范并组织 USB 的进一步开发。 USB-IF的目的是为当时使用的PC…...
算法小白的心得笔记:比较小数点后五位,而不会受到浮点数精度问题的影响。
epsilon 来比较浮点数 double epsilon 1e-6; // for 6 decimal places for (const auto &ratio : colorRatio) {std::cout << "__" << inum << "__" << ratio << " ";if ((inum - 1) % 10 0){std::cout &l…...
11月起,33个省份纳入数电票开票试点范围内,发票无纸化已是大势所趋!
10月底,北京、贵州、山东(不含青岛市)、湖南、宁夏5个地区相继发布开展数电票试点工作的通知,至此,全国已有33个省份纳入数电票开票试点范围内。根据上述5地区发布的相关公告,11月1日将正式推行“数电票”开…...
NLP之Bert多分类实现案例(数据获取与处理)
文章目录 1. 代码解读1.1 代码展示1.2 流程介绍1.3 debug的方式逐行介绍 3. 知识点 1. 代码解读 1.1 代码展示 import json import numpy as np from tqdm import tqdmbert_model "bert-base-chinese"from transformers import AutoTokenizertokenizer AutoToken…...
matlab中的mapminmax函数初步理解和应用
matlab中的mapminmax函数初步认识 一、mapminmax 顾名思义:映射最大最小 二、语法及举例 2.1 语法1 [Y,PS] mapminmax(X) 将矩阵X映射形成矩阵Y, Y中每行中的最小值对应-1,最大值对应1。PS是一个包含映射信息的结构体。 举例: clc cle…...
svc和ingress的关系
在Kubernetes中,SVC有三种类型,分别是ClusterIP、NodePort和LoadBalancer。而Ingress则是一种服务类型的扩展,它主要用于处理HTTP和HTTPS流量,并提供了对集群内部服务的路由和负载均衡功能。 下面简要介绍SVC的三种类型和Ingress…...
可以使用以下代码对数据库查询结果进行分组统计
public static void GroupAndStatistic(string connectionString, string query) {// 创建一个SQLSugar实例var db new SQLSugarClient(connectionString);// 使用QueryHelper类执行查询var dataTable db.Query<DataRow>().From(query).ExecuteDataTable();// 使用LINQ…...
win10提示mfc100u.dll丢失的解决方法,快速解决dll问题
在计算机使用过程中,我们经常会遇到一些错误提示,其中之一就是“mfc100u.dll丢失”。那么,mfc100u.dll是什么?mfc100u.dll是Microsoft Visual C Redistributable文件之一,它包含了用于MFC (Microsoft Foundation Class…...
zookeeper:启动原理
主类: QuorumPeerMain, 其中调用了main对象的initializeAndRun方法, 首先定义了QuorumPeerConfig对象,然后调用了parse方法,parse方法代码如下: 其中调用的parseProperties方法的代码如下: 可以看到&am…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
