pytorch实现DCP暗通道先验去雾算法及其onnx导出

news2024/12/25 14:25:47

pytorch实现DCP暗通道先验去雾算法及其onnx导出

  • 简介
  • 实现
  • ONNX导出
    • 导出
    • 测试

简介

最近在做图像去雾,于是在Pytorch上复现了一下dcp算法。暗通道先验去雾算法是大神何恺明2009年发表在CVPR上的一篇论文,还获得了当年的CVPR最佳论文。
dcp算法效果

实现

具体原理就不阐述了,网上的解析多的是,这里直接把用pytorch复现的代码贴出来:

import torch


def dcp(img, omega=0.75):
    h, w = img.shape[2:]
    imsz = h * w
    # 要查找的是暗通道中前0.1%的值
    numpx = torch.clamp_min(imsz // 1000, 1)
    # 找到暗通道的索引,弄成[batch, 3, numpx],因为要匹配三个通道,所以需要expand
    dark = torch.min(img, dim=1, keepdim=True)[0]
    indices = torch.topk(dark.view(-1, imsz), k=numpx, dim=1)[1].view(-1, 1, numpx).expand(-1, 3, -1)
    # 用上述索引匹配原图中的3个通道,并求其平均值
    a = (torch.gather(img.view(-1, 3, imsz), 2, indices).sum(2) / numpx).view(-1, 3, 1, 1)
    
    # 代公式算tx
    tx =  1 - omega * torch.min(img / a.view(-1, 3, 1, 1), dim=1, keepdim=True)[0]
    # 代公式算jx
    return (img - a) / torch.clamp_min(tx, 0.1) + a

函数有两个参数:

  1. img:经归一化后的(N,C,H,W)布局的图像
  2. omega:DCP算法的一个参数ω,数值越大效果越强

如果想在模型训练时引入dcp算法,可以用nn.Module封装一下:

class DCP(torch.nn.Module):
    def __init__(self, omega):
        self._omega = omega

    def forward(self, x):
        return dcp(x, self._omega)

ONNX导出

导出

既然能封装成Module,那么就顺便试了一下导出ONNX。
导出onnx需要安装onnx和onnxsim:

pip install onnx onnxsim

导出代码如下:

import torch
import onnx
from onnxsim import simplify 


def dcp(img, omega=0.75):
    h, w = img.shape[2:]
    imsz = h * w
    # 要查找的是暗通道中前0.1%的值
    numpx = torch.clamp_min(imsz // 1000, 1)
    # 找到暗通道的索引,弄成[batch, 3, numpx],因为要匹配三个通道,所以需要expand
    dark = torch.min(img, dim=1, keepdim=True)[0]
    indices = torch.topk(dark.view(-1, imsz), k=numpx, dim=1)[1].view(-1, 1, numpx).expand(-1, 3, -1)
    # 用上述索引匹配原图中的3个通道,并求其平均值
    a = (torch.gather(img.view(-1, 3, imsz), 2, indices).sum(2) / numpx).view(-1, 3, 1, 1)
    
    # 代公式算tx
    tx =  1 - omega * torch.min(img / a.view(-1, 3, 1, 1), dim=1, keepdim=True)[0]
    # 代公式算jx
    return (img - a) / torch.clamp_min(tx, 0.1) + a

class DCPExport(torch.nn.Module):
    def forward(self, x, omega):
        return dcp(x, omega)

def export(output='dcp.onnx'):
    torch.onnx.export(
        DCPExport(), 
        (torch.randn(1, 3, 255, 255, dtype=torch.float32), torch.tensor(0.75, dtype=torch.float32)), 
        'dcp.onnx', 
        input_names=['fog_image', 'omega'], 
        output_names=['clear_image'], 
        dynamic_axes={
            'fog_image': {0: 'batch', 2: 'height', 3: 'width'},
            'clear_image': {0: 'batch', 2: 'height', 3: 'width'},
        }
    )
    onnx_model = onnx.load(output) 
    model_simp, check = simplify(onnx_model) 
    assert check, "简化模型失败" 
    onnx.save(model_simp, output) 

if __name__ == '__main__':
	export()

导出结果如下:

onnx
导出后的onnx输入输出如下:

  • 输入:
    1. fog_image[float32]:形状为NCHW,且归一化的有雾图像,其中通道数C必须为3
    2. omega[float32]:dcp的参数,类型为浮点数
  • 输出:
    1. clear_image[float32]:形状为NCHW,且归一化的无雾图像,其中通道数C为3

下载链接:https://pan.baidu.com/s/1A1jSJQBFCGTeM8vbHOrysQ?pwd=tl6p

测试

用cv2和pil都可以:

import numpy as np
import cv2
from PIL import Image
from onnxruntime import InferenceSession


model = InferenceSession('dcp.onnx')

# CV2读图
image = cv2.imread('dehaze/dehaze/input/images/indoor1.jpg')
# 这里说明一下,因为dcp对所有通道进行同等变换,所以不用bgr和rgb互转了,出来的结果都是一样的
# x = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
x = np.transpose(image, (2, 0, 1))[None].astype(np.float32) / 255.
res = model.run(['clear_image'], {'fog_image': x, 'omega': np.array(0.75, dtype=np.float32)})[0][0]
res = np.transpose(res, (1, 2, 0))
res = np.clip(res*255+0.5, 0, 255).astype(np.uint8)
# res = cv2.cvtColor(res, cv2.COLOR_RGB2BGR)
cv2.imwrite('onnx-cv.png', np.concatenate((image, res), 1))

# PIL读图
image = Image.open('dehaze/dehaze/input/images/indoor1.jpg')
x = np.transpose(image, (2, 0, 1))[None].astype(np.float32) / 255.
res = model.run(None, {'fog_image': x, 'omega': np.array(0.75, dtype=np.float32)})[0][0]
res = np.transpose(res, (1, 2, 0))
res = np.clip(res*255+0.5, 0, 255).astype(np.uint8)
Image.fromarray(np.concatenate((image, res), 1)).save('onnx-pil.png')

效果:

onnx效果

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

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

相关文章

微课录课软件盘点,让教学变得更轻松!

“有人知道怎么录制课程吗?上网课的时候,老师讲课的速度很快,有些知识点还没理解,就已经跳过了,这时我就想把网课录下来,课后再进行复习,大家有什么录课的软件推荐吗?” 随着信息技…

微信小程序动态导航栏(uniapp + vant)

本文使用到vant的van-tabbar组件来实现 一、uniapp整合vant ui vant小程序版本:https://vant-contrib.gitee.io/vant-weapp/#/home 注:vant并没有uniapp的版本,所以此处是引入小程序版本的ui 1. 下载vant编译后代码 https://github.com/youzan/vant-weapp/tree/dev/dist 2…

SpringBoot框架介绍数据库操作Mybatis注入JDBC注入

目录 0x00 前言 0x01 SpringBoot框架介绍 1、SpringBoot实现简单的 GET、POST 请求 2、SpringBoot 实现数据库操作 0x02 JDBC&Mybatis注入 0、环境及靶场介绍 - Hello-Java-Sec 1、JDBC 注入 2、Mybatis 注入 3、代码审计案例 - inxedu 后台 MyBatis 注入 0x00 前…

神经网络Python实现(9行代码)

1. 神经网络简介 神经网络由输入层、输出层和之间若干层(一层或多层)隐含层构成,每一层可以有若干个节点。层与层之间节点的连接状态通过权重来体现。 下面介绍一下单个神经元: 输入节点:x1,x2 权重:w1,w…

27.BGP边界网关路由协议

BGP边界网关路由协议 外部网关路由协议 ospf能承载的路由条目有限 用在运营商与运营商之间,国与国之间 BGP运行在IGP之上(内部网关路由) IGP都是在物理链路上直连的基础之上才能建立邻居关系,BGP可以跨路由器建立邻居关系&…

Postman进行参数化的2种方式

前言 Postman作为一款接口测试工具,受到了非常多的开发工程师的拥护。 那么做为测试,了解Postman这款工具就成了必要的了。 这篇文章就是为了解决Postman怎么进行参数化的。 同时,我也为大家准备了一份软件测试视频教程(含面试、…

为“EYE”加码,蔡司光学公益助童活动走进湖南省宁乡市

为不断强化品牌的责任担当,用公益传递社会正能量。2023年11月28日,国内眼视光领域领导品牌蔡司光学携手海南精功眼镜走进湖南省宁乡市青少桥初级中学开展蔡司公益助童行动,全校共504名学生参与其中。 因爱而生,接续传递“EYE”的美…

arcmap + oracle11g 迁移数据 报错 copyFeatures失败

原因排查: 1.通过这个界面,我们无法查到真正的原因, 2.将数据拷贝到我们自己的arcmap服务器中,采用 单个要素 导入,从result面板中查找原因; 从上面这个图中,看到关键信息 DBMS error ORA-016…

Opencv入门五 (显示图片灰度值)

源码如下&#xff1a; #include <opencv2/opencv.hpp> int main(int argc, char** argv) { cv::Mat img_rgb, img_gry, img_cny; cv::namedWindow("Example Gray",cv::WINDOW_AUTOSIZE); cv::namedWindow("Example Canny", cv::WINDOW_…

数据隐私治理所面临的四大挑战

PrimiHub一款由密码学专家团队打造的开源隐私计算平台&#xff0c;专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。 近年来&#xff0c;隐私功能越来越受到重视&#xff0c;在重大立法改革和加强监管审查的支持下&#xff0c;各组织通过部署和扩展…

07.stack 容器

7、stack 容器 概念&#xff1a; stack 是一种先进后出&#xff08;First In Last Out&#xff0c;FILO&#xff09;的数据结构&#xff0c;它只有一个出口 栈中只有顶端的元素才可以被外界使用&#xff0c;因此栈不允许有遍历行为栈中进入数据称为 — 入栈 push栈中弹出数据…

清理优化,卸载高效——PP Cleaner Uninstaller Pro for Mac

随着时间的推移&#xff0c;Mac电脑上的垃圾文件和无用程序可能会逐渐积累&#xff0c;影响电脑的性能和运行速度。为了解决这个问题&#xff0c;我们推荐您使用PP Cleaner & Uninstaller Pro for Mac软件&#xff0c;它是一款专业的清理和卸载工具&#xff0c;能够帮助您保…

基于ssm作业提交与查收系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本作业提交与查收系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信…

多对多关系通用操作组件,省时省力的神器

项目上有很多对多操作的场景&#xff0c;建对象&#xff0c;建mapper接口&#xff0c;设置查询条件&#xff0c;查询多对多数据等都是一项极为耗时耗力的工作。因此&#xff0c;搓了这款集建表-保存-查询-设置条件等操作于一体的组件。原理简单&#xff0c;利用$标签动态作些操…

【自动化测试】selenium元素定位方式大全!

前言 当我们在使用selenium进行自动化测试工作时&#xff0c;元素定位是非常重要的一环&#xff0c;因为我们是借助脚本模拟我们通过鼠标和键盘对元素进行点击、输入内容和滑动操作的&#xff0c;所以准确的元素定位是我们执行测试脚本的重要一环。本文就来给大家介绍一下sele…

windows11 ssd掉盘(无法访问)

故障描述&#xff1a; 开机的时候能够正常访问SSD当使用电源的时候很容易SSD无法访问接入电源以后掉盘情况缓解 故障原因&#xff1a;win11加入了一个新的电源策略 更改高级电源设置&#xff08;默认是10/20&#xff09;&#xff0c;把这个参数调整大。 非常蠢的一个设计&…

信号处理基础之噪声与降噪(二)| 时域降噪方法(平滑降噪、SVD降噪)python代码实现

接上期信号处理基础之噪声与降噪(一) | 噪声分类及python代码实现&#xff0c;本期为大家介绍噪声评价指标&#xff0c;并且讲解两种降噪方法——平滑降噪、SVD降噪&#xff0c;并给出python代码。 信号处理基础之噪声与降噪(二&#xff09;| 时域降噪方法&#xff08;平滑降噪…

Z Potentials | 叶生晅:生成式 AI 下不变的是需求,坚定成为客户的营销技术合伙人

移动互联网时代&#xff0c;视频、直播、兴趣电商、社交、新资讯等线上新平台新服务实现大发展&#xff0c;吸引用户加速融入日益不可或缺的线上生活和「线上线下」融合场景&#xff0c;铸就海量的流量红利。营销场景从来都是软件应用行业最大的市场&#xff0c;离客户的预算最…

基于ssm双星小区物业管理系统的设计与实现论文

摘 要 传统办法管理双星小区物业信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装双星小区物业管理系统软件来发挥其高效地信息处…

【性能测试】登录接口性能压测+选择并发用户数总结...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、需要登录的接口…