图像加雾算法的研究与应用

news2024/11/20 14:20:14

目录

前言

一、图像加雾

1、基于传统方法的雾图合成

2、基于深度学习的雾图合成

3、基于Lightroom Classic实现软件加雾

4、基于深度图的方法实现加雾

二、开源的数据集

三、参考文章


前言

在去雾任务当中,训练和评估去雾算法需要大量的带有雾霾和无雾霾的图像对。由于实际拍摄的带雾霾的图像不易获得并且不可控,因此研究者常常通过加雾(Image Fogging)技术来人工生成含雾图像,以丰富数据集。这不仅有助于生成多样化的训练数据,还能在控制实验中评估去雾算法的性能。本文将探讨图像加雾的基本原理和常用方法,并介绍一些用于图像加雾的具体技术。

一、图像加雾

1、基于传统方法的雾图合成

大气散射模型: 大气散射是指光线在大气中传播时,由于空气中的微小颗粒和气体分子的散射,使得光线强度随着传播距离的增加而衰减。根据贝尔-朗伯定律(Beer-Lambert Law),光强度 I 可以表示为:

I(d)=I_{0}\cdot e^{-\beta d}

其中:

  • I_{0} 是初始光强度。
  • \beta  是衰减系数,控制雾霾的浓度。
  • d   是光线传播的距离。

雾霾效果模拟:对于图像中的每一个像素,计算其到中心点的距离 d。使用指数衰减函数

td = e^{-\beta d}计算雾霾的强度。调整每个像素的亮度,使其受到雾霾的影响。具体公式为:

new_pixel=original_pixel×td+brightness×(1−td)

其中 brightness 参数控制了雾霾的亮度。

下面让我们实现这个算法:

import numpy as np


def addfog(image, beta=0.05, brightness=0.5):
    """
    对输入的图像添加雾霾效果。

    Args:
        image (numpy.ndarray): 输入的图像,范围在0-255.
        beta (float, optional): 控制雾霾效果的参数.beta值越大,雾霾效果越明显.默认为0.05.
        brightness (float, optional): 雾霾的亮度值.该值越大,图像整体亮度越高.默认为0.5.

    Returns:
        numpy.ndarray: 添加雾霾效果后的图像,数据类型为uint8,范围在0-255。
    """
    img_f = np.array(image, dtype=np.float32) / 255.0
    row, col, chs = image.shape
    size = np.sqrt(max(row, col))  # Atomization size
    center = (row // 2, col // 2)  # Atomization center
    for j in range(row):
        for l in range(col):
            d = -0.04 * np.sqrt((j - center[0]) ** 2 + (l - center[1]) ** 2) + size
            td = np.exp(-beta * d)
            img_f[j][l][:] = img_f[j][l][:] * td + brightness * (1 - td)
    img_f = np.clip(img_f * 255, 0, 255).astype(np.uint8)
    return img_f


if __name__ == '__main__':
    import pyzjr
    path = r'test1.png'
    image = pyzjr.imreader(path)
    print(image.shape)
    image_fog = addfog(image)
    print(image_fog.shape)
    pyzjr.display("Comparison between original image and fogged image",
                  [[image, image_fog]], 0.4)

关于光线传播的距离d,它的系数-0.04应该是一个经验值,主要是用于调整距离对雾霾强度的影响。 可以根据实际效果进行调整,较小的系数会使距离对雾霾效果的影响减小,反之则增大。添加 size 是用来调节雾霾的范围大小的。通常情况下,雾化效果在中心点附近比较强烈,随着距离中心点的增加,雾化效果逐渐减弱。

加雾效果如下所示: 

在运行期间,时间明显比较长,现在我们来写一个优化的版本吧

这个时间长主要是因为这个嵌套循环,所以我们可以利用NumPy的矢量化操作来提高计算效率,可以使用 np.ogrid 生成行和列的索引,并计算每个像素点到中心点的距离。计算 td 采用矢量化方式,避免使用双重循环,提高效率。用 [..., np.newaxis] 进行广播,使得每个通道都应用相同的雾霾效果。这样就能显著提升大图像的处理速度,特别是在高分辨率图像上效果明显。

import numpy as np


def addfogv1(image, beta=0.05, brightness=0.5):
    """
    对输入的图像添加雾霾效果。

    Args:
        image (numpy.ndarray): 输入的图像,范围在0-255.
        beta (float, optional): 控制雾霾效果的参数.beta值越大,雾霾效果越明显.默认为0.05.
        brightness (float, optional): 雾霾的亮度值.该值越大,图像整体亮度越高.默认为0.5.

    Returns:
        numpy.ndarray: 添加雾霾效果后的图像,数据类型为uint8,范围在0-255。
    """
    img_f = np.array(image, dtype=np.float32) / 255.0
    row, col, chs = image.shape
    size = np.sqrt(max(row, col))  # Atomization size
    center = (row // 2, col // 2)  # Atomization center
    for j in range(row):
        for l in range(col):
            d = -0.04 * np.sqrt((j - center[0]) ** 2 + (l - center[1]) ** 2) + size
            td = np.exp(-beta * d)
            img_f[j][l][:] = img_f[j][l][:] * td + brightness * (1 - td)
    img_f = np.clip(img_f * 255, 0, 255).astype(np.uint8)
    return img_f

def addfogv2(image, beta=0.05, brightness=0.5):
    """
    对输入的图像添加雾霾效果的高效实现。

    Args:
        image (numpy.ndarray): 输入的图像,范围在0-255.
        beta (float, optional): 控制雾霾效果的参数. beta值越大, 雾霾效果越明显. 默认为0.05.
        brightness (float, optional): 雾霾的亮度值. 该值越大, 图像整体亮度越高. 默认为0.5.

    Returns:
        numpy.ndarray: 添加雾霾效果后的图像,数据类型为uint8,范围在0-255。
    """
    img_f = image.astype(np.float32) / 255.0
    row, col, chs = image.shape
    size = np.sqrt(max(row, col))  # Atomization size
    center = (row // 2, col // 2)  # Atomization center
    y, x = np.ogrid[:row, :col]
    dist = np.sqrt((x - center[1])**2 + (y - center[0])**2)
    d = -0.04 * dist + size
    td = np.exp(-beta * d)
    img_f = img_f * td[..., np.newaxis] + brightness * (1 - td[..., np.newaxis])
    img_f = np.clip(img_f * 255, 0, 255).astype(np.uint8)
    return img_f

if __name__ == '__main__':
    import pyzjr
    from pyzjr.dlearn.tools import Runcodes
    path = r'test1.png'
    image = pyzjr.imreader(path)
    with Runcodes("加雾算法v1版本"):
        image_fogv1 = addfogv1(image)
    with Runcodes("加雾算法v2版本"):
        image_fogv2 = addfogv2(image)
    pyzjr.display("Comparison between original image and fogged image",
                  [[image_fogv1, image_fogv2]], 0.4)

加雾v1与v2版本的效果: 

在时间对比上有很大提升

加雾算法v1版本: 10.10729 sec,加雾算法v2版本: 0.14432 sec

2、基于深度学习的雾图合成

利用成对数据训练模型,基于生成对抗网络(GAN)或者自编码器(Autoencoder)实现的深度学习方法可以实现端到端的合成雾图。然而,由于这些方法同样需要训练数据,合成的雾图和真实雾图之间可能存在一定的差异。

除此之外,我一直在思考一般我们做的去雾任务,能不能反过来做,把去雾的输入输出反过来训练,即将清晰图像作为输入,雾图像作为输出来训练模型,一般的模型都可以做到加雾任务。这种反向的方法,可能存在诸多的问题,但用深度学习的方法应该能够更好的控制雾的浓度和分布。

3、基于Lightroom Classic实现软件加雾

打开Lrc软件,左上角点击文件,导入照片和视频

点击图库,选择图片,修改图片,点击基本,调整去朦胧的值,往小的调整。 

这是拉到了-100的效果图 

如果想要恢复原来的照片,点击右下角「复位」按钮,就可以使照片恢复到最初的样子。也可以使用快捷键ctrl+z。

这是拉到了+100的效果图 

比起原图也更加清晰,我觉得可以采用这样的方式去丰富我们的数据集。

4、基于深度图的方法实现加雾

Synscapes这个数据集很大,有180多个G,你可以从这里进行下载,全部下载完之后才能解压。

Synscapes data set (liu.se)

从exr文件读取深度信息并进行可视化

import OpenEXR
import numpy as np
import Imath
import cv2

def synscapes_depth_as_disparity(depth_image):
    """将Synscapes深度图像转换为视差图像。"""
    # 将深度图归一化到0-1范围,并将深度值转换为视差值
    normalized_depth_image = depth_image / np.max(depth_image)
    disparity_image = 1.0 / (normalized_depth_image + 1e-5)

    # 将视差图归一化到0-255范围
    normalized_disparity_image = (disparity_image - np.min(disparity_image)) / (
                np.max(disparity_image) - np.min(disparity_image)) * 255
    normalized_disparity_image = normalized_disparity_image.astype(np.uint8)

    return normalized_disparity_image

def read_depth_from_exr(exr_file_path):
    """使用OpenEXR库打开指定的EXR文件 """
    exr_file = OpenEXR.InputFile(exr_file_path)
    header = exr_file.header()
    width = header['dataWindow'].max.x + 1
    height = header['dataWindow'].max.y + 1

    pixel_type = Imath.PixelType(Imath.PixelType.FLOAT)
    z_channel = exr_file.channel('Z', pixel_type=pixel_type)
    z_buffer = np.frombuffer(z_channel, dtype=np.float32)
    z_buffer = z_buffer.reshape((height, width))

    return z_buffer


if __name__=="__main__":
    exr_file_path = r"F:\dataset\Dehazy\synscapes\Synscapes\img\depth\3.exr"
    depth_image = read_depth_from_exr(exr_file_path)
    normalized_disparity_image = synscapes_depth_as_disparity(depth_image)

    cv2.imshow("Disparity Image", normalized_disparity_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

加雾效果对比图

因为这部分工作不是我做的,所以代码不能开源,只能给大家看看效果。

二、开源的数据集

ITS, SOTS, OHAZE, Dense-haze下载路径

dataset - Google Driveicon-default.png?t=N7T8https://drive.google.com/drive/folders/1mHr9p-c895tFtyRLz1JEeEGAurTmj_v-RSHaze、RESIDE-OUT、RESIDE-IN、RESIDE-6K

data - Google Driveicon-default.png?t=N7T8https://drive.google.com/drive/folders/1oaQSpdYHxEv-nMOB7yCLKfw2NDCJVtrx大家找开源数据集可以从近两年的去雾的论文的开源仓库里面找到。

三、参考文章

数据增强:图片加雾效果实现Python_图像加雾算法-CSDN博客

https://www.scirp.org/pdf/jcc_2021110215052004.pdf

域适应加雾代码:通过《bringing old photos back to life 》_生成雾图-CSDN博客

如何在 Lightroom 中使用去朦胧功能?_lightroom去朦胧-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1720290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超维小课堂 | 1、Pixhawk硬件平台和PX4固件以及QGC地面站之间的关联和区别

Pixhawk硬件平台和PX4固件以及QGC地面站之间的关联和区别 一、Pixhawk是无人机飞控的硬件平台。 主要集成了相关的单片机芯片和各种传感器的外围电路,因此,可以直观的认为Pixhawk一个由各种硬件模块整合成的硬件平台,类似于集成好的单片机开…

【Qt知识】Qt中的对象树是什么?

在深入Qt编程的世界时,你会频繁遇到一个核心概念——对象树(Object Tree)。这个概念是Qt框架管理内存、处理事件和组织用户界面元素的基础。 什么是Qt对象树? 如果你的Qt应用程序就像一片茂盛的森林,而这片森林中的每…

CameraProvider启动流程

从Android 8.0之后,Android 引入Treble机制,主要是为了解决目前Android 版本之间升级麻烦的问题,将OEM适配的部分vendor与google 对android 大框架升级的部分system部分做了分离,一旦适配了一个版本的vendor信息之后,之…

炫云亮相第二十届中国国际动漫节国际动漫游戏商务大会!

5月28日-29日,备受瞩目的第二十届中国国际动漫节国际动漫游戏商务大会(iABC2024)在杭州滨江开元名都大酒店隆重召开!本届大会以动漫IP为核心,从源头到全系列数字内容,探索创新协同、融合发展、价值转化,并对重点作品和…

校园安保巡逻机器人

2023年8月5日,陕西西安一高校实验室起火冒烟,导致学校化学实验室发生火灾。2022年8月3日,一名歹徒持械闯入江西吉安安福县城的一家私立幼儿园,对着无辜的幼儿行凶伤人,造成3死6伤。 像这样的事故有不断地发生&#xf…

计算机基础学习路线

计算机基础学习路线 整理自学计算机基础的过程,虽学习内容众多,然始终相信世上无难事,只怕有心人,期间也遇到许多志同道合的同学,现在也分享自己的学习过程来帮助有需要的。 一、数据结构与算法 视频方面我看的是青…

DNF手游攻略:勇士进阶指南!

在即将到来的6月5日,《DNF手游》将迎来一场盛大的更新,此次更新带来了大量新内容和玩法,极大丰富了游戏的体验。本文将为广大玩家详细解析此次更新的亮点,包括新增的组队挑战玩法“罗特斯入门团本”、新星使宠物的推出、宠物进化功…

【Android】

hint在text显示提示内容 设置主键,在mainactivity // 获取SharedPreferences对象存放的用户名和密码,并设为相应组件的值 //指定key的值,及获取不到值时使用的默认值 String sName sp.getString("name", "unknown")…

pom文件中,Maven导入依赖出现 Dependency not found

解决方案: 1、首先看一下自己的Maven是否配置好了 2、再检查一下镜像是否正确 3、如果上面都没有问题,看 dependencyManagement 标签 我这个出错,爆一大片红就是因为 这个标签 dependencyManagement 解决方法:在父工程中进行依…

实现样式一键切换

实现效果实现方法操作步骤 1.实现效果类似于: 点击切换后更改样式为: 2.实现方法 1.通过css变量切换主题 2.通过link引入css文件切换主题 3.实现方法 定义下拉框双向绑定数据(写到根组件app.vue中), 设置theme默认值…

【产品经理】从父订单到仓库出库单

订单拆单到仓库发货,整个流程是什么样的?拆单系统又分为哪几个部分? 正常购物的流程:选购好商品从购物车下单、生成订单、确认订单支付、然后坐等收货、收到货确认收货。 从购物车里面会选多个商家的商品一起下单,有时…

Python | Leetcode Python题解之第120题三角形最小路径和

题目: 题解: class Solution:def minimumTotal(self, triangle: List[List[int]]) -> int:n len(triangle)f [0] * nf[0] triangle[0][0]for i in range(1, n):f[i] f[i - 1] triangle[i][i]for j in range(i - 1, 0, -1):f[j] min(f[j - 1], …

Flutter基础 -- Dart 语言 -- 注释函数表达式

目录 1. 注释 1.1 单行注释 1.2 多行注释 1.3 文档注释 2. 函数 2.1 定义 2.2 可选参数 2.3 可选参数 默认值 2.4 命名参数 默认值 2.5 函数内定义 2.6 Funcation 返回函数对象 2.7 匿名函数 2.8 作用域 3. 操作符 3.1 操作符表 3.2 算术操作符 3.3 相等相关的…

使用cad绘制一个螺旋输送机

1、第一步,绘制一个矩形 2、使用绘图中的样条线拟合曲线,绘制螺旋线。 绘制时使用上下辅助线、阵列工具绘制多个竖线保证样条线顶点在同一高度。 3、调整矩形右侧的两个顶点,使其变形。 矩形1和矩形2连接时,使用blend命令&#…

[PyQt5] 窗口接收WM_COPY消息

#本程序是python qt5 创建的窗口,拦截外部消息给窗口发送的WM_COPY消息并显示出来。一般是用来作为窗口之间的通讯机制之一。 python文件如下:qt5拦截消息 #!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys from PyQt5.QtWidgets import QAp…

低代码与人工智能的深度融合:行业应用的广泛前景

引言 在当今快速变化的数字化时代,企业面临着越来越多的挑战和机遇。低代码平台和人工智能技术的兴起,为企业提供了新的解决方案,加速了应用开发和智能化转型的步伐。 低代码平台的基本概念及发展背景 低代码平台是一种软件开发方法&#x…

03-树1 树的同构(浙大数据结构PTA习题)

03-树1 树的同构 分数 25 作者 陈越 单位 浙江大学 给定两棵树 T1​ 和 T2​。如果 T1​ 可以通过若干次左右孩子互换就变成 T2​,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G…

案例实践 | 基于长安链的首钢供应链金融科技服务平台

案例名称-首钢供应链金融科技服务平台 ■ 建设单位 首惠产业金融服务集团有限公司 ■ 用户群体 核心企业、资金方(多为银行)等合作方 ■ 应用成效 三大业务场景,共计关联29个业务节点,覆盖京票项目全部关键业务 案例背景…

Pipecat: 创建语音对话agent的开源框架,支持多模态!

项目简介 pipecat 是用于构建语音(和多模态)对话代理的框架。诸如私人教练、会议助理、儿童讲故事玩具、客户支持机器人、摄入流程和尖刻的社交伙伴。 看看一些示例应用: 语音代理入门 您可以开始在本地计算机上运行 Pipecat,然…

相同的树(oj题)

一、题目链接https://leetcxode-cn.com/problems/same-tree/ 二、题目思路 遍历整颗树,判断两棵树的每个位置的结点都相同。 每个结点的左右孩子结点都要综合判断 三、题解代码 bool isSameTree(struct TreeNode* p, struct TreeNode* q) {//如果两颗树的根结点…