opencv-python图像增强二:图像去雾(暗通道去雾)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 一、简介:
- 二、暗通道去雾方案简述:
- 三、算法实现步骤
- 3.1最小值滤波
- 3.2 引导滤波
- 3.3 计算图像全局光强
- 四:整体代码实现
- 五:效果
一、简介:
图像去雾是计算机视觉领域中的一个重要问题,其目的是恢复被雾气遮挡的图像中的真实细节。在自然场景中,雾气会导致图像的对比度下降、颜色失真以及细节模糊。去雾算法的主要目标是在保留图像内容的同时,尽可能地恢复被雾气遮挡的信息。本次使用的算法为暗通道去雾,暗通道去雾算法基于暗通道先验理论,该理论指出在自然场景的任意一点(除天空外),其暗通道图像中的像素值在大部分情况下都接近于0。通过提取暗通道图像,并对其进行去雾处理,可以恢复图像中的真实细节。
二、暗通道去雾方案简述:
在图像去雾处理中,我们采取以下步骤来提升图像质量:
首先,我们从三通道彩色图片中提取每个像素的最小值,并将其拆解为单通道图像。这一步帮助我们识别出图像中最暗的部分。
接着,我们对这个单通道图像进行最小值滤波操作,这一过程有助于进一步提取图像的暗部信息,使得暗部特征更加明显。
然后,为了去除暗部噪声并模糊图像细节,我们对提取出的暗部图像进行引导滤波处理。这一步骤有助于平滑图像,同时保留重要的结构信息。
接下来,我们计算全局光强值A,这个值用于排除天空等过曝区域,确保去雾效果更加自然。
最后,我们对原图像的每个通道分别减去暗通道,以保留暗部细节并校正颜色与亮度。这个过程可以理解为对雾气影响的校正。经过这一步骤处理后,新的图像暗通道接近零,这意味着图像中的雾气已被有效去除,从而得到清晰、无雾的图片。
三、算法实现步骤
3.1最小值滤波
最小值滤波是一种图像处理技术,其工作原理是在图像中每个像素点的邻域内,找出所有像素值中的最小值,并用这个最小值替换掉原始像素点的值。这个过程对于突出图像中的暗部细节非常有用,尤其是在去除图像噪声和增强图像对比度方面。
代码如下:
# 定义一个函数,用于对灰度图像进行最小值滤波
def zmMinFilterGray(src, r=7):# 检查输入图像的形状是否正确if len(src.shape) != 2:raise ValueError("输入图像必须是灰度图像")# 定义结构元素,它是一个由全1组成的矩形核,半径为rstructure_element = np.ones((2 * r + 1, 2 * r + 1))# 使用OpenCV的erode函数对输入图像进行腐蚀操作# 腐蚀操作可以理解为用结构元素覆盖图像的每个像素,并保留覆盖区域的最小值# 这里使用的是全1的结构元素,因此腐蚀操作相当于最小值滤波result = cv2.erode(src, structure_element)# 返回腐蚀操作后的结果return result
3.2 引导滤波
引导滤波(Guided Filter)是一种用于图像滤波的算法,它利用引导图像的内容来对目标图像进行滤波处理,同时保持目标图像的边缘和细节。引导滤波的核心思想是假设引导图像与目标图像在局部区域具有相似的结构,因此可以借助引导图像的特性来对目标图像进行滤波。
代码如下(示例):
def guidedfilter(I, p, r, eps):# 获取图像的高度和宽度height, width = I.shape# 计算引导图像I的局部均值m_I = cv2.boxFilter(I, -1, (r, r))# 计算输入图像p的局部均值m_p = cv2.boxFilter(p, -1, (r, r))# 计算引导图像I和输入图像p的局部乘积的均值m_Ip = cv2.boxFilter(I * p, -1, (r, r))# 计算引导图像I和输入图像p的局部协方差cov_Ip = m_Ip - m_I * m_p# 计算引导图像I自身的局部协方差,即局部方差m_II = cv2.boxFilter(I * I, -1, (r, r))var_I = m_II - m_I * m_I# 估计线性系数aa = cov_Ip / (var_I + eps)# 估计线性系数bb = m_p - a * m_I# 对系数a和b进行全局均值滤波,得到平滑的系数m_a = cv2.boxFilter(a, -1, (r, r))m_b = cv2.boxFilter(b, -1, (r, r))# 计算输出图像,即m_a * I + m_breturn m_a * I + m_b
参数说明:
I: 输入图像,可以是灰度图像或彩色图像。
p: 引导图像,用于指导滤波器。引导图像应与输入图像具有相同的尺寸和类型。
r: 引导滤波器的半径,以像素为单位。较大的半径可以覆盖更多的像素,从而更好地平滑噪声,但可能会模糊边缘。较小的半径则可以更好地保留边缘细节,但去噪效果可能不够理想。
eps: 引导滤波器的正则化参数。较大的值可以更好地平滑噪声,但可能会模糊图像的细节。较小的值则可以更好地保留细节,但去噪效果可能不够理想。
3.3 计算图像全局光强
在暗通道去雾算法中,计算全局光强A的原因如下:
1.恢复无雾图像:去雾的目标是从带雾图像中恢复出无雾图像。为了做到这一点,需要估计场景中光线的原始强度,即在没有大气散射影响下的光强。全局光强A代表了场景中最亮区域的原始光线强度。
2.指导去雾过程:全局光强A是去雾算法中的一个关键参数,它用于指导如何从带雾图像中恢复出无雾图像的颜色和亮度。通过计算A,可以更准确地估计每个像素点在无雾状态下的光线强度。
3.避免颜色失真:如果全局光强A的估计不准确,去雾后的图像可能会出现颜色失真或过曝现象。因此,准确计算A对于保持图像的自然颜色和细节至关重要。
代码如下(示例):
# 定义一个变量,用于设置直方图的桶数
bins = 2000
# 计算暗通道图像V1的直方图
ht = np.histogram(V1, bins)
# 计算累积分布函数d,用于找到累积概率接近0.999的亮度值
d = np.cumsum(ht[0]) / float(V1.size)
# 遍历直方图的每个桶,从最后一个桶开始向前搜索
for lmax in range(bins - 1, 0, -1):# 如果累积分布函数d的值大于或等于0.999,则找到合适的亮度值if d[lmax] <= 0.999:break
# 计算大气光照系数A,即暗通道图像V1中累积概率大于或等于0.999的像素点的最大值
A = np.mean(m, 2)[V1 >= ht[1][lmax]].max()
# 对值范围进行限制,确保V1的值在合理的范围内
V1 = np.minimum(V1 * w, maxV1)
这段代码简单来说就是将图像亮度分为2000个等级,用累积分布函数的概率找到图像中过亮区域像素值所在的范围,计算原图三通道像素值取出其均值所代表的新图像,按照范围取出新图像中的所代表区域的最大值,用来代表天空等区域的像素值,至此暗通道去雾所需要的关键算法就整理完毕了,之后需要的就是将这些算法集成起来构筑为一个完整的暗通道去雾算法。
四:整体代码实现
import cv2
import numpy as npdef zmMinFilterGray(src, r=7):return cv2.erode(src, np.ones((2 * r + 1, 2 * r + 1)))def guidedfilter(I, p, r, eps):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_pm_II = cv2.boxFilter(I * I, -1, (r, r))var_I = m_II - m_I * m_Ia = cov_Ip / (var_I + eps)b = m_p - a * m_Im_a = cv2.boxFilter(a, -1, (r, r))m_b = cv2.boxFilter(b, -1, (r, r))return m_a * I + m_bdef Defog(m, r, eps, w, maxV1): # 输入rgb图像,值范围[0,1]'''计算大气遮罩图像V1和光照值A, V1 = 1-t/A'''V1 = np.min(m, 2)max_values = np.max(m, axis=2)# 得到暗通道图像Dark_Channel = zmMinFilterGray(V1, 7)cv2.imshow('V1', V1)cv2.imshow('20190708_Dark',Dark_Channel) # 查看暗通cv2.waitKey(0)cv2.destroyAllWindows()V1 = guidedfilter(V1, Dark_Channel, r, eps) # 使用引导滤波优化bins = 2000ht = np.histogram(V1, bins)d = np.cumsum(ht[0]) / float(V1.size)for lmax in range(bins - 1, 0, -1):if d[lmax] <= 0.999:breakA = np.mean(m, 2)[V1 >= ht[1][lmax]].max()V1 = np.minimum(V1 * w, maxV1) # 对值范围进行限制return V1, Adef 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):print((m[:,:,k] - Mask_img))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(r'F:\traditional_vison\R-C.jfif') / 255.0) * 255).astype(np.uint8)cv2.imshow("ccccc",m)cv2.waitKey(0)# cv2.imwrite('20190708_02.png', m)
五:效果
图片原图:

暗通道图:
增强后效果图:

相关文章:
opencv-python图像增强二:图像去雾(暗通道去雾)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、简介:二、暗通道去雾方案简述:三、算法实现步骤3.1最小值滤波3.2 引导滤波3.3 计算图像全局光强 四:整体代码实现五…...
自研Vue3低代码海报制作平台第一步:基础拖拽组件开发
学习来源:稀土掘金 - 幽月之格大佬的技术专栏可拖拽、缩放、旋转组件 - 著作:可拖拽、缩放、旋转组件实现细节 非常感谢大佬!受益匪浅! 前面我们学习了很多vue3的知识,是时候把它们用起来做一个有意思的平台…...
QT 的 QSettings 读写 INI 文件的示例
在Qt中,QSettings 类提供了一种便捷的方式来存储和访问应用程序的设置,这些设置可以存储在多种格式的文件中,包括INI、Windows注册表(仅Windows平台)、XML和JSON等。以下是一些使用 QSettings 读写INI文件的示例。 写…...
【零基础学习CAPL语法】——testStep:测试结果输出函数
文章目录 1.函数介绍2.在报告中体现 1.函数介绍 testStep——测试结果输出函数 2.在报告中体现 //testStep() void PrintTxMsg() {testStep("Tx","[%x] [%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x]",Diag_Req.id,Diag_Req.byte(0),Diag_Req.byte(1),Di…...
8.5.数据库基础技术-规范化
函数依赖 函数依赖:给定一个X,能唯一确定一个Y,就称X决定(确定)Y,或者说Y依赖于X。 例如:YX*X函数,此时X能确定Y的值,但是Y无法确定X的值,比如x2,y4,但是y4无法确定x2。函数依赖又可扩展以下两…...
于博士Cadence视频教程学习笔记备忘
标签:PCB教程 PCB设计步骤 cadence教程 Allegro教程 以下是我学习该视频教程的笔记,记录下备忘,欢迎大家在此基础上完善,能回传我一份是最好了,先谢过。 备注: 1、未掌握即未进行操作 2、操作软件是15.…...
8.3.数据库基础技术-关系代数
并:结果是两张表中所有记录数合并,相同记录只显示一次。交:结果是两张表中相同的记录。差:S1-S2,结果是S1表中有而S2表中没有的那些记录。 笛卡尔积:S1XS2,产生的结果包括S1和S2的所有属性列,并且S1中每条记…...
【Vue3】vue模板中如何使用enum枚举类型
简言 有的时候,我们想在vue模板中直接使用枚举类型的值,来做一些判断。 ts枚举 枚举允许开发人员定义一组命名常量。使用枚举可以更容易地记录意图,或创建一组不同的情况。TypeScript 提供了基于数字和字符串的枚举。 枚举的定义这里不说了…...
组合求和2
题目描述: Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target. Each number in candidates may only be used once in the combinati…...
Apple Maps现在可在Firefox和Mac版Edge浏览器中使用
Apple Maps最初只能在 Windows 版 Safari、Chrome 浏览器和 Edge 浏览器上运行,现在已在其他浏览器上运行,包括 Mac 版 Firefox 和 Edge。经过十多年的等待,Apple Maps于今年 7 月推出了新版地图应用的测试版,但只能在有限的浏览器…...
基于嵌入式Linux的数据库
数据库 数据库是在数据库管理系统和控制之下,存放在存储 介质上的数据集合。 基于嵌入式的数据库 基于嵌入式linux的数据库主要有SQlite, Firebird,Berkeley DB,eXtremeDB Firebird是关系型数据库,功能强大,支持存储过 程&…...
C# 使用LINQ找出一个子字符串在另一个字符串中出现的所有位置
一、实现步骤 遍历主字符串,使用IndexOf方法查找子字符串的位置。如果找到了子字符串,记录其位置,并且从该位置的后面继续查找。重复上述步骤直到遍历完整个字符串。 二、简单代码示例 using System; using System.Collections.Generic; usi…...
YOLOv8添加MobileViTv3模块(代码+free)
目录 一、理由 二、方法 (1)导入MobileViTv3模块 (2)在ultralytics/nn/tasks.py的函数parse_model中修改 (3)在yaml配置文件中写入 (4)开始训练,先把其他梯度关闭&…...
从概念到落地:全面解析DApp项目开发的核心要素与未来趋势
随着区块链技术的迅猛发展,去中心化应用程序(DApp)逐渐成为Web3时代的重要组成部分。DApp通过智能合约和分布式账本技术,提供了无需信任中介的解决方案,这种去中心化的特性使其在金融、游戏、社交等多个领域得到了广泛…...
仓颉编程入门 -- 泛型概述 , 如何定义泛型函数
泛型概述 , 如何定义泛型函数 1 . 泛型的定义 在仓颉编程语言中,泛型机制允许我们定义参数化类型,这些类型在声明时不具体指定其操作的数据类型,而是作为类型形参保留,待使用时通过类型实参来明确。这种灵活性在函数和类型声明中…...
SOC估算方法之(OCV-SOC+安时积分法)
一、引言 此方法主要参考电动汽车用磷酸铁锂电池SOC估算方法这篇论文 总结: 开路电压的测量需要将电池静止相当长的一段时间才能达到平衡状态进行测量。 安时积分法存在初始SOC的估算和累积的误差。 所以上述两种方法都存在一定的缺陷,因此下面主要讲…...
指针(下)
文章目录 指针(下)野指针、空指针野指针空指针 二级指针**main**函数的原型说明 常量指针与指针常量常量指针指针常量常量指针常量 动态内存分配常用函数**malloc****calloc****realloc****free** **void**与**void***的区别扩展:形式参数和实际参数的对应关系 指针…...
C# 浅谈IEnumerable
一、IEnumerable 简介 IEnumerable 是一个接口,它定义了对集合进行迭代所需的方法。IEnumerable 接口主要用于允许开发者使用foreach循环来遍历集合中的元素。这个接口定义了一个名为 GetEnumerator 的方法,该方法返回一个实现了 IEnumerator 接口的对象…...
mmdebstrap:创建 Debian 系统 chroot 环境的利器 ️
文章目录 mmdebstrap 的一般性参数说明 📜mmdebstrap 的常见用法示例 🌈使用 mmdebstrap 的注意事项 ⚠️ 🌈你好呀!我是 山顶风景独好 🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然&am…...
【Linux SQLite数据库】一、SQLite交叉编译与移植
SQLite 是一个用 C 语言编写的开源、轻量级、快速、独立且高可靠性的 SQL 数据库引擎,它提供了功能齐全的数据库解决方案。SQLite 几乎可以在所有的手机和计算机上运行,它被嵌入到无数人每天都在使用的众多应用程序中。此外,SQLite 还具有稳定…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
