DIP图像去雾

实验目的

在数字图像处理中,图像去雾是一个重要的研究领域,主要目的包括:

  1. 改善图像质量:去雾技术能够提高图像的可见度和对比度,从而使图像更清晰,便于进一步的图像分析和处理。

  2. 应用广泛:图像去雾技术广泛应用于监控、交通、航空摄影、卫星图像处理等领域,对于提高图像信息的可用性和准确性非常关键。

  3. 促进后续处理:清晰的图像是许多图像处理任务(如目标检测、场景识别、图像分类等)的前提条件,去雾可以有效地优化这些任务的处理效果。

  4. 增强算法性能:研究不同的图像去雾算法可以帮助开发更高效、更准确的图像预处理工具,提升整体的图像处理性能。

通过这些目的的实现,图像去雾技术不仅提升了图像的质量,也为各种实际应用提供了支持,增强了图像处理技术的实用性和广泛性。

实验原理

Retinex算法的核心原理是假设图像可以被分解为反射分量(物体本身的颜色)和光照分量(由环境光照决定)。算法的目标是从观察到的图像中独立地估计这两个分量,从而恢复出物体的真实颜色,无论环境光照如何变化。

关键代码

import numpy as np
import cv2
import math


class DCP:
    def __init__(self, img):
        self.img = img
        self.smog = None
        self.new_img = np.zeros(img.shape)
        self.w = img.shape[0]
        self.h = img.shape[1]
        self.dark_channel = None
        self.A = 0

    def runAlgorithm(self, kernel_size, w=0.85, t0=0.1):
        """
        :param kernel_size: 以像素点x为中心的局部区域大小
        :param w: 预留雾的程度, 0<w<=1
        :param t0: 透射率下限
        """
        # 取出BGR三通道的最小值,返回二维矩阵
        min_BGR = np.min(self.img, axis=2)

        # 计算暗通道
        dark_channel = np.zeros(min_BGR.shape)
        mid = kernel_size//2
        tmp_img = np.zeros((self.w+kernel_size-1, self.h+kernel_size-1), dtype=np.float)
        tmp_img[:, :] = 255
        tmp_img[mid:self.w+mid, mid:self.h+mid] = min_BGR
        for i in range(mid, self.w+mid-1):
            for j in range(mid, self.h+mid-1):
                dark_channel[i-mid, j-mid] = min(np.min(tmp_img[i-mid:i+mid, j-mid:j++mid]), 255)

        self.dark_channel = dark_channel

        # 获取大气光值A
        pixels = {}
        # 根据像素点位置保存像素点
        for i in range(self.w):
            for j in range(self.h):
                pixels[(i, j)] = dark_channel[i, j]
        pixels_list = list(pixels.items())
        sorted(pixels_list, key=lambda x: x[1], reverse=True)

        # 挑选前0.1%最亮像素
        # 如果前0.1%像素点个数小于1,最选择第一个
        if int(len(pixels_list) * 0.001) == 0:
            loc = pixels_list[0]
            self.A = np.min(self.img[loc[0], loc[1], :])
        else:
            brightest_pixels = pixels_list[: int(len(pixels_list) * 0.001)]
            sum_A = 0
            for pixel in brightest_pixels:
                loc = pixel[0]
                sum_A += np.min(self.img[loc[0], loc[1], :])
            # 取前0.1%像素中最亮像素点的平均值
            self.A = sum_A/len(brightest_pixels)

        # 计算透射率t(x)的预估值
        self.dark_channel = np.float64(self.dark_channel)
        tx = 1 - w * self.dark_channel / self.A
        new_tx = np.clip(tx, t0, 1)

        # 滤波
        ksize = 20*kernel_size
        eps = 1e-5
        mean_i = cv2.blur(self.dark_channel, (ksize, ksize))
        mean_p = cv2.blur(new_tx, (ksize, ksize))
        corr_i = cv2.blur(np.multiply(new_tx, new_tx), (ksize, ksize))
        corr_ip = cv2.blur(np.multiply(new_tx, self.dark_channel), (ksize, ksize))
        var_i = corr_i - np.multiply(mean_i, mean_i)
        cov_ip = corr_ip - np.multiply(mean_i, mean_p)
        a = cov_ip / (var_i + eps)
        b = mean_p - np.multiply(a, mean_i)
        mean_a = cv2.blur(a, (ksize, ksize))
        mean_b = cv2.blur(b, (ksize, ksize))
        new_tx = np.multiply(mean_a, self.dark_channel) + mean_b

        # 计算无雾图
        tmp_img = np.float64(self.img)
        for i in range(3):
            self.new_img[:, :, i] = (tmp_img[:, :, i] - self.A) / new_tx + self.A
        self.new_img = np.clip(self.new_img, 0, 255)

    def getDarkChannel(self):
        return self.dark_channel

    def getRes(self):
        return np.uint8(self.new_img)


class Retinex:
    def __init__(self, img, sigma_list=[15, 80, 250]):
        self.img = np.float64(img)
        self.sigma_list = sigma_list
        self.RImg = None

    def runAlgorithm(self):
        img_msr = self.MSR()
        img_msr = self.clipImage(img_msr, 0.05, 0.95)
        for i in range(self.img.shape[2]):
            img_msr[:, :, i] = (img_msr[:, :, i] - np.min(img_msr[:, :, i])) / (
                        np.max(img_msr[:, :, i]) - np.min(img_msr[:, :, i])) * 255

        img_msr = np.clip(img_msr, 0, 255)
        self.RImg = np.uint8(img_msr)

    # 使用像素出现频率确定上下剪切点
    def clipImage(self, img, low_clip, high_clip):
        low_val = high_val = 0
        total = img.shape[0] * img.shape[1]
        for i in range(img.shape[2]):
            unique, counts = np.unique(img[:, :, i], return_counts=True)
            current = 0
            for u, c in zip(unique, counts):
                if float(current) / total < low_clip:
                    low_val = u
                if float(current) / total < high_clip:
                    high_val = u
                current += c
            img[:, :, i] = np.clip(img[:, :, i], low_val, high_val)

        return img

    def SSR(self, sigma):
        LImg = cv2.GaussianBlur(self.img, (0, 0), sigma)
        ans = np.log(self.img + 1) - np.log(LImg + 1)
        return ans

    def MSR(self):
        tmp = np.zeros_like(self.img)
        for sigma in self.sigma_list:
            tmp += self.SSR(sigma)
        tmp /= 3
        return tmp

    def getRimg(self):
        return self.RImg

实现GUI

GUI打开图片的路径不能有中文!

from tkinter import *
from tkinter.filedialog import askopenfilename
from PIL import ImageTk, Image
import cv2
from model import *
from tkinter.ttk import Combobox


def changeStyle(img):
    # 根据设定窗口尺寸修改展示图片
    img = cv2.resize(img, (400, 300), interpolation=cv2.INTER_LINEAR)
    # 转化成能显示的格式
    dst = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    dst = Image.fromarray(dst)

    show_img = ImageTk.PhotoImage(image=dst)
    return show_img


def openImage():
    global image
    imgPath = askopenfilename()
    if len(imgPath) == 0:
        Label(window, text="路径为空", fg='red').grid(row=4, column=1, sticky='w')
    else:
        imgPath = imgPath.replace("\\", "//")
        try:
            image = cv2.imread(imgPath, cv2.IMREAD_COLOR)
            Label(window, text="路径正确", fg='green').grid(row=4, column=1, sticky='w')

            show_img = changeStyle(image)

            origin_img_label = Label(window, image=show_img)
            origin_img_label.image = show_img
            origin_img_label.grid(row=1, column=0)
        except:
            Label(window, text="路径错误", fg='red').grid(row=4, column=1, sticky='w')


def removeSmog():
    algName = varLabel.get()
    if algName == "请选择去雾算法":
        Label(window, text="请选择去雾算法", fg="red").grid(row=4, column=1)
        Label(window, image=empty_img).grid(row=1, column=1)
    else:
        Label(window, text="", width=20).grid(row=4, column=1)

        if algName == values[0]:
            # 使用模型
            DCP_model = DCP(image)
            DCP_model.runAlgorithm(kernel_size=15)

            res_img = DCP_model.getRes()
            res_img = changeStyle(res_img)

            res_img_label = Label(window, image=res_img)
            res_img_label.image = res_img
            res_img_label.grid(row=1, column=1)
        elif algName == values[1]:
            # 使用模型
            Retinex_model = Retinex(image)
            Retinex_model.runAlgorithm()

            res_img = Retinex_model.getRimg()
            res_img = changeStyle(res_img)

            res_img_label = Label(window, image=res_img)
            res_img_label.image = res_img
            res_img_label.grid(row=1, column=1)


if __name__ == "__main__":
    window = Tk()  # 创建一个窗口
    window.title("图像去雾")
    window.geometry("820x600")  # 设置窗口大小

    # 创建一张空白图
    empty_img = Image.new('RGB', (400, 300), (255, 255, 255))
    empty_img = ImageTk.PhotoImage(image=empty_img)
    Label(window, text="图像去雾", font=30).grid(row=0, columnspan=2, sticky="n")
    Label(window, image=empty_img).grid(row=1, column=0, pady=20)
    Label(window, text="原图", font=15).grid(row=2, column=0)
    Label(window, image=empty_img).grid(row=1, column=1)
    Label(window, text="去雾后图像", font=15).grid(row=2, column=1)
    varLabel = StringVar()
    varLabel.set("请选择去雾算法")
    values = ["暗通道先验算法", "Retinex算法"]
    Combobox(window, height=2, width=20, state="readonly", cursor="arrow", textvariable=varLabel, values=values).grid(row=3, column=0)
    Button(window, text="打开图片", width=10, height=2, command=openImage).grid(row=3, column=1, pady=50, sticky="w")
    Button(window, text="图片去雾", width=10, height=2, command=removeSmog).grid(row=3, column=1, pady=50)
    window.mainloop()  # 维持窗口打开状态

参考代码

https://github.com/Fanynwork/image_defogging

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值