手把手教你暗通道先验去雾算法

0,流程

暗通道先验去雾算法(Dark Channel Prior, DCP)是一种基于图像的去雾技术,由Kaiming He等人在2009年提出。这种算法利用了大气散射模型,通过估计大气光和图像的传输图来去除雾的影响。以下是暗通道先验去雾算法的基本步骤:

  • 暗通道提取

    • 对于一幅图像,首先提取其暗通道。暗通道是指图像中相对较暗的区域,这些区域在雾的影响下仍然保持一定的可见度。
    • 暗通道可以通过对图像的每个像素点的RGB三个通道进行最小值操作来获得。
  • 大气光估计

    • 利用暗通道,估计大气光的值。大气光是指由于大气散射而进入相机的光。
    • 可以通过对暗通道的像素值进行阈值处理来估计大气光的值。例如,可以选择暗通道中大于某个阈值的像素点的像素值作为大气光的估计值。
  • 传输图估计

    • 传输图是指图像中每个像素点的光透过雾的传输率。传输图的估计需要结合大气光和暗通道。
    • 传输图可以通过以下公式估计: 

其中,I(x) 是原始图像的像素值,Lmax​ 是大气光的估计值。

  • 图像恢复

    • 利用传输图和大气光,恢复原始图像。恢复过程可以通过以下公式进行:

​ 其中,I′(x)是恢复后的图像,I(x)是原始图像,L是大气光的估计值,t(x)是传输图。

  • 细节增强

    • 为了增强恢复图像的细节,可以对恢复后的图像进行一些细节增强处理,比如使用双边滤波等。

1,暗通道先验理论内容

 在大多数非天空区域,至少有一个通道的像素值是很低的并且接近于0,并且在一个小的区域内最小的像素强度也接近于0.

暗通道先验定义的数学公式:

公式中Jc表示彩色图像的每个通道 ,Ω(x)表示以像素X为中心的一个窗口。首先求出每个像素RGB分量中的最小值,之后利用opencv的腐蚀操作求出以每个像素为中心的一个窗口的最小值,一般有WindowSize = 2 * Radius + 1。

1.1 暗通道先验的理论依据


        低强度的像素值通常由于以下几个方面造成:首先是现实世界中物体的阴影,因为阴影本身具有较低的光强度。其次是色彩鲜艳的物体或表面,它们在 RGB 通道中的某些通道上具有较低的值,因此在图像中呈现较暗的颜色,比如灰暗色的树干和石头等。总的来说,自然景物中到处都存在阴影或色彩丰富的物体,这些因素都会导致图像的暗通道具有较低的像素值,呈现出灰暗的色调。

获取暗通道图像算法代码:

import cv2
import numpy as np
 
def dark_channel_prior(image, kernel_size=15):
    # 分割图像通道
    b, g, r = cv2.split(image)
    # 计算三个通道中的最小值
    min_channel = cv2.min(cv2.min(r, g), b)
    # 使用指定大小的矩形卷积核进行腐蚀操作
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
    dark_channel = cv2.erode(min_channel, kernel)
    return dark_channel
 
# 读取图像
image = cv2.imread("4.jpg")
 
# 计算暗通道
dark_channel = dark_channel_prior(image)
 
# 显示结果
cv2.imshow('Dark Channel', dark_channel)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果呈现图: 

有雾暗通道

无雾暗通道

 3.去雾算法流程
        1.估计图像透射率和大气光:提供了有关图像中光线衰减和背景光的重要信息,帮助去除大气散射并恢复图像的清晰度和真实感。

        2.去雾处理:根据透射率和大气光,对图像中的每个像素进行修复,以减轻由于大气散射引起的光线衰减效应。可以在处理过程中对图像进行进一步的优化,以提高图像的质量和真实感。

        3.评估去雾效果:使用PSNR(峰值信噪比)图像质量评估指标,评估去雾后图像与原始图像之间的相似度和质量。

去雾效果图展示:

 暗通道先验去雾算法代码:

pip install scikit-image

import cv2
import numpy as np
from skimage.metrics import peak_signal_noise_ratio as psnr


# 计算每个通道中的最小值,输入Image图像,输出最小值img_min
def min_channel(img):
    dst_channel = np.min(img, 2)
    return dst_channel


def min_filter(image, r):  # 暗通道

    # 最小值滤波,输入最小值图像,在2*r+1的矩形窗口内寻找最小
    return cv2.erode(image, np.ones((2 * r + 1, 2 * r + 1)))


# 引导滤波
# I=img_arr归一化  引导图像
# p=img_mim每个通道最小值 输入图像
def guided_filter(I, p, r, eps):  # (引导I 原图p)
    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_p

    m_II = cv2.boxFilter(I * I, -1, (r, r))
    var_I = m_II - m_I * m_I

    a = cov_Ip / (var_I + eps)
    b = m_p - a * m_I

    m_a = cv2.boxFilter(a, -1, (r, r))
    m_b = cv2.boxFilter(b, -1, (r, r))
    q = m_a * I + m_b
    return q


def select_bright(Image, img_origin, w, t0, V):


    # 计算大气光A和折射图t
    # 输入:Image最小值图像,img_origion原图,w是t之前的修正参数,t0阈值,V导向滤波结果
    rows, cols = Image.shape
    size = rows * cols

    # h,w,d=img.shape,size=h*w*d,b=img.reshape(size)
    order = [0 for i in range(size)]  # order=np.zeros(size)
    m = 0  # map0=Image.reshape(1,-1)[0]   map1=map0.sort() map2=map1[::-1]
    for t in range(0, rows):
        for j in range(0, cols):
            order[m] = Image[t][j]
            m = m + 1
    order.sort(reverse=True)
    index = int(size * 0.001)  # 从暗通道中选取亮度最大的前0.1%
    mid = order[index]
    A = 0
    img_hsv = cv2.cvtColor(img_origin, cv2.COLOR_RGB2HLS)
    for i in range(0, rows):
        for j in range(0, cols):
            if Image[i][j] > mid and img_hsv[i][j][1] > A:
                A = img_hsv[i][j][1]
    V = V * w
    t = 1 - V / A
    t = np.maximum(t, t0)
    return t, A


def repair(Image, t, A):
    rows, cols = Image.shape[:2]
    J = np.zeros(Image.shape)
    for i in range(0, rows):
        for j in range(0, cols):
            t[i][j] = t[i][j] - 0.35
            J[i][j] = (Image[i][j] - A / 255.0) / t[i][j] + A / 255.0
    return J

img = cv2.imread(r'F:\whl_package\img_1.png', 1)  # 修改路径即可

# 归一化图像
img_arr = img.astype(float) / 255.0

# 计算暗通道
img_min = min_channel(img_arr)
img_dark = min_filter(img_min, 1)
img_guided = guided_filter(img_min, img_dark, 75, 0.001)
t, A = select_bright(img_dark, img, 0.95, 0.1, img_guided)


# 加载原始图像
if img is None:
    print("错误:无法加载原始图像。")
    exit()

# 进行去雾处理
dehazed_image = repair(img_arr, t, A)
if dehazed_image is None:
    print("错误:图像处理失败。")
    exit()

# 计算 PSNR
dehazed_image_uint8 = (dehazed_image * 255).astype(np.uint8)
psnr_value = psnr(img, dehazed_image_uint8)

# 输出 PSNR
print("PSNR:", psnr_value)

# 显示原始图像
cv2.imshow('Original', img)
cv2.waitKey(0)  # 等待用户按下任意键继续

# 显示暗通道图像
cv2.imshow('Dark Channel', img_dark)
cv2.waitKey(0)  # 等待用户按下任意键继续

# 显示去雾后的图像
cv2.imshow('Dehazed Image', dehazed_image)
cv2.waitKey(0)  # 等待用户按下任意键继续

# 释放窗口
cv2.destroyAllWindows()

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值