opencv-python图像增强二:图像去雾(暗通道去雾)

news/2025/1/15 17:10:37/

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、简介:
  • 二、暗通道去雾方案简述:
  • 三、算法实现步骤
    • 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)

五:效果

图片原图:
图片原图

暗通道图:在这里插入图片描述
增强后效果图:
在这里插入图片描述


http://www.ppmy.cn/news/1508820.html

相关文章

【mysql 第三篇章】一条 update语句是怎么持久化到磁盘上的?

首先看一下这个 SQL 语句你会不会写? 下面是说明执行这个 SQL 语句&#xff0c;数据库底层做了什么操作。 update users set namexxx where id10;在引擎要执行更新语句的时候&#xff0c;比如更新 id10 这行数据时&#xff0c;他会先查看数据在缓冲池中是否存在&#xff0c;如…

C++:类与对象(下)

再探构造函数 构造函数体赋值与初始化列表 其实之前我们实现构造函数时&#xff0c;初始化成员变量主要使⽤函数体内赋值&#xff0c;构造函数初始化还有⼀种⽅式&#xff0c;就是初始化列表&#xff0c;C规定初始化列表的使⽤⽅式是以 ⼀个冒号开始&#xff0c;接着是⼀个以逗…

为RPC服务增加异步日志模块

在实际开发过程中我们不可能将一些错误信息或是提示信息全部打印到屏幕上&#xff0c;而是将这些信息输送到日志中去。但是存在着一个问题&#xff0c;写日志是在磁盘中写日志&#xff0c;是磁盘的io操作&#xff0c;效率会很慢&#xff0c;致使项目的效率降低。 为了解决这一个…

从零开始构建霸王餐返利APP的技术路线与挑战

从零开始构建霸王餐返利APP的技术路线与挑战 大家好&#xff0c;我是阿可&#xff0c;微赚淘客系统及省赚客APP创始人&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在电商领域&#xff0c;霸王餐返利APP作为一种新兴的商业模式&#xff0c;为用…

jq8900-16p代码索引

jq8900-16p代码索引: JQ8900.c #include "stm32f10x.h" #include "delay.h" #include "JQ8900.h"void Init_One_line_Uart(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStruct…

LeetCode_sql_day16(601.体育馆的人流量)

描述&#xff1a;601. 体育馆的人流量 - 力扣&#xff08;LeetCode&#xff09; 编写解决方案找出每行的人数大于或等于 100 且 id 连续的三行或更多行记录。 返回按 visit_date 升序排列 的结果表。 输入Stadium表: ----------------------------- | id | visit_date | peop…

【OpenCV-Python实战项目】01-OCR文本检测

OpenCVTesseract文本检测 0.介绍1.基础功能实现1.1 字符检测1.2 单词检测1.3 只检测数字 2.工程应用2.1 封装类2.2 屏幕截图识别2.3 视频文本检测&#xff08;待优化&#xff09; 3.参考 0.介绍 &#xff08;1&#xff09;Tesseract是一个开源文本识别 (OCR)引擎&#xff0c;是…

JavaScript高阶笔记总结第三天:(JavaScript高阶完结)

Xmind鸟瞰图&#xff1a; 简单文字总结&#xff1a; js高阶笔记总结&#xff1a; 严格模式&#xff1a; 1.开启严格模式&#xff1a;"use strict" 2.不使用var关键字声明会报错 3.严格模式下普通函数的this指向undefined 高阶函数&#xff1a; 满足…