当前位置: 首页 > news >正文

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】window 下 VS Code 配置OpenCV
  • 【阿旭机器学习实战】【38】支持向量机SVM实现手写数字识别,模型训练、评估,以及参数调优全流程
  • maven下载及配置详细介绍(2024最新攻略)
  • opencv颜色格式
  • LeetCode旋转图像
  • 自动驾驶行业知识汇总
  • ChatMoneyAI嘴替,高情商回复
  • 【前端】NodeJS:实战案例——记账本
  • 知识与智慧
  • Proxmox LXC 部署ubuntu,centos
  • 在进行等保测评时,如何确保技术风险和非技术风险的评估结果具有可操作性?
  • Untiy Modbus 西门子 S7-1200 基础通信
  • wps云字库字体下载到电脑
  • 使用 Prometheus 和 Grafana 监控 FastAPI 服务
  • access函数
  • php的引用
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • [LeetCode] Wiggle Sort
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • Android单元测试 - 几个重要问题
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • Hibernate最全面试题
  • httpie使用详解
  • Java多态
  • Vue小说阅读器(仿追书神器)
  • 从PHP迁移至Golang - 基础篇
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 项目实战-Api的解决方案
  • - 转 Ext2.0 form使用实例
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (12)Linux 常见的三种进程状态
  • (javascript)再说document.body.scrollTop的使用问题
  • (ZT)薛涌:谈贫说富
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (原創) 物件導向與老子思想 (OO)
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .bashrc在哪里,alias妙用
  • .NET CF命令行调试器MDbg入门(一)
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET Framework 3.5安装教程
  • .NET MVC第三章、三种传值方式
  • .net Stream篇(六)
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .Net 基于MiniExcel的导入功能接口示例
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • 。Net下Windows服务程序开发疑惑
  • ::
  • :O)修改linux硬件时间
  • @软考考生,这份软考高分攻略你须知道