DehazeNet: An End-to-End System for Single ImageHaze Removal

DehazeNet是一种基于卷积神经网络的端到端系统,设计用于估计单个雾霾图像的介质传输图。该方法借鉴了图像去雾的先验知识,如暗通道先验,通过Maxout单元和新提出的双边整流线性单元(BReLU)进行特征提取和非线性回归。实验表明DehazeNet在保留高效性和易用性的同时,提高了去雾性能。
摘要由CSDN通过智能技术生成

Abstract

单图像雾霾去除是一个具有挑战性的不适定问题。现有的方法使用各种约束/先验来获得似是而非的去雾解。实现雾霾去除的关键是对输入的雾霾图像进行介质透射图的估计。在本文中,我们提出了一个可训练的端到端系统称为DehazeNet,用于介质传输估计。DehazeNet以雾霾图像为输入,输出其介质传输图,随后通过大气散射模型恢复无雾图像。DehazeNet采用了基于卷积神经网络(CNN)的深度架构,其层次是专门设计来体现图像去雾中既定的假设/先验的。其中,利用Maxout单元层进行特征提取,可以生成几乎所有与雾霾相关的特征。我们还在DehazeNet中提出了一种新的非线性激活函数,称为双边整流线性单元(BReLU),它能够提高恢复的无雾图像的质量。我们在提议的DehazeNet组件和现有方法中使用的组件之间建立连接。在基准图像上的实验表明,DehazeNet在保持高效和易于使用的前提下,取得了优于现有方法的性能。

I. INTRODUCTION

雾霾是一种传统的大气现象,灰尘、烟雾和其他干燥的颗粒掩盖了大气的清晰度。雾霾在地面摄影领域引起问题,在那里,稠密的大气的光线穿透可能是必要的,以成像遥远的主题。这导致了视觉效果的反差损失在主体,由于光散射通过雾霾粒子的影响。由于这些原因,雾霾去除是需要在消费者摄影和计算机视觉应用程序。

雾霾的去除是一个具有挑战性的问题,因为雾霾的传输取决于未知的深度,而深度在不同的位置是不同的。各种图像增强技术已经被应用于单个图像的去雾问题,包括基于直方图的[1],基于对比度的[2]和基于饱和度的[3]。此外,利用多幅图像或深度信息的方法也被提出。例如,基于偏振的方法[4]通过多幅不同偏振程度的图像去除了雾霾效果。在[5]中,将基于多约束的方法应用于不同天气条件下捕获同一场景的多幅图像。基于深度的方法[6]需要一些来自用户输入或已知3D模型的深度信息。在实践中,深度信息或多个朦胧图像并不总是可用的。

由于使用了更好的假设和先验,单幅图像的雾霾去除最近取得了显著的进展。具体来说,在无雾图像的局部对比度远大于雾霾图像的假设下,提出了一种基于马尔可夫随机场(Markov Random Field, MRF)的局部对比度最大化方法[7]去除雾霾。虽然对比度最大化方法能够获得令人印象深刻的结果,但它往往产生过饱和的图像。在[8]中,提出了基于最小输入的独立成分分析(Independent Component Analysis, ICA)方法来去除彩色图像中的雾霾,但该方法耗时较长,不能用于处理密集雾霾图像。在暗对象减影技术的启发下,通过对无雾图像的实验进行经验统计,发现了暗通道先验(Dark Channel Prior, DCP)[9],它表明,在大多数非雾霾斑块中,至少有一个颜色通道中存在一些像素强度很低的像素。利用暗通道先验,利用大气散射模型估算和去除雾霾厚度。然而,DCP在天空图像中失去了去雾的质量,并且是计算密集型的。为了克服这些局限性,提出了一些改进算法。为了提高去雾质量,Kratz和Nishino等人使用阶乘MRF对图像建模,以更准确地估计场景亮度;孟等人[11]提出了一种有效的正则化去雾方法,通过探索固有边界约束来恢复无hazfree图像。为了提高计算效率,采用标准中值滤波[12]、中值滤波的中值[13]、引导联合双边滤波[14]和引导图像滤波器[15]来替代耗时较长的软抠图[16]。近年来,机器学习框架对相关先验进行了研究。Tang et al.[17]将四种与雾霾相关的特征与Random Forests结合来估计传播。Zhu等人[18]在颜色衰减先验下建立线性模型来估计朦胧图像的场景深度,并使用监督方法学习模型的参数。尽管取得了显著的进步,但这些最先进的方法受到了与雾霾相关的先验或启发式线索的限制——它们对某些图像往往不那么有效。

从单个图像中去除雾霾是一项困难的视觉任务。相比之下,人类的大脑可以在没有任何额外信息的情况下从自然风景中迅速识别出雾的区域。随着生物启发cnn在高级视觉任务(如图像分类[19]、人脸识别[20]和目标检测[21])中的成功,人们可能会忍不住提出生物启发模型来进行图像去雾。事实上,最近已经有一些基于(卷积)神经网络的深度学习方法被提出用于图像恢复/重建的低级视觉任务[22],[23],[24]。但这些方法不能直接应用于单幅图像去雾。

请注意,除了估算全球大气光量级外,实现雾霾去除的关键是恢复准确的介质传输图。为此,我们提出了DehazeNet,一个可训练的基于CNN的端到端媒体传输估计系统。DehazeNet将一个朦胧图像作为输入,并输出其媒介传输图,随后通过一个简单的像素级操作来恢复无雾图像。DehazeNet的设计借鉴了图像去雾的既定假设/原则,其各层参数都可以通过训练雾图像自动学习。在基准图像上的实验表明,DehazeNet的性能优于现有的方法,但保持高效和易于使用。我们的主要贡献总结如下。

1) DehazeNet是一个端到端系统。该算法直接学习和估计了雾图像斑块与其介质传输之间的映射关系。这是通过其深层建筑的特殊设计来实现的,以体现既定的图像去雾原则。

2)我们在DehazeNet中提出了一个新的非线性激活函数,称为双边整流线性Unit1 (BReLU)。BReLU扩展了整流线性单元(ReLU),证明了其在获取精确图像恢复中的重要意义。在技术上,brrelu利用双边约束减小搜索空间,提高收敛性。

3)我们建立了DehazeNet组件与现有去雾方法中使用的那些假设/先验之间的联系,并解释了DehazeNet通过从端到端自动学习所有这些组件来改进这些方法。

本文的其余部分组织如下。在第二节中,我们回顾了大气散射模型和与雾霾相关的特征,这为理解DehazeNet的设计提供了背景知识。在第三节中,我们介绍了提议的DehazeNet的细节,并讨论了它与现有方法的关系。实验介绍在第四节,在第五节得出结论之前。

II. RELATED WORKS

文献中已经提出了许多图像去雾的方法。在这一节中,我们简要回顾了一些重要的研究成果,重点关注了提出大气散射模型的人,这是图像去雾的基本基础模型,以及对计算雾霾相关特征提出有用假设的人。

A. Atmospheric Scattering Model

为了描述雾状图像的形成,大气散射模型首先由McCartney[26]提出,由Narasimhan和Nayar[27],[28]进一步发展。大气散射模型的正式形式为

其中,I(x)是观测到的雾图像,J(x)是要恢复的真实的场景,t(x)是介质透射,α是全局大气光,并且x索引观测到的雾图像I中的像素。图1给出了一个示例。方程(1)中有三个未知数,估计α和t(x)后即可恢复真实的场景J(x)。

介质透射图t(x)描述了未被散射并到达照相机的光部分。t(x)定义为

 其中d(x)是场景点到摄像机的距离,β是大气的散射系数。等式(2)表明,当d(x)趋于无穷大时,t(x)接近零。结合等式(1),我们得到

 在远距离视图的实际成像中,d(x)不能是无穷大,而是给出非常低的透射t0的长距离。不依赖于等式(3)来获得全局大气光α,而是基于以下规则更稳定地估计全局大气光α

 以上讨论建议为了恢复干净的场景(即,为了实现雾状物去除),关键是估计精确的介质透射图。

B. Haze-relevant features

图像去雾是一个固有的不适定问题。基于经验观察,现有方法提出了用于计算中间雾度相关特征的各种假设或先验知识。基于这些雾度相关特征可以实现最终雾度去除。

1) Dark Channel:

暗通道先验是基于对室外无雾图像的广泛观察。在大多数无雾补片中,至少一个颜色通道具有强度值非常低甚至接近零的一些像素。暗通道[9]被定义为局部块中所有像素颜色的最小值:

 其中,Ic是I的RGB颜色通道,Ωr(x)是以x为中心的局部面片,大小为r × r。暗通道特征与图像中的雾度有很高的相关性,可以用来直接估计介质透射率t(x)∝ 1 −D(x)。

2) Maximum Contrast:

3) Color Attenuation:

 

 4) Hue Disparity:

 III. THE PROPOSED DEHAZENET

第II-A节中的大气散射模型表明,介质透射图的估计是恢复无雾图像的最重要步骤。为此,我们提出了DehazeNet,一个可训练的端到端系统,它显式地学习原始雾图像和它们相关的介质传输图之间的映射关系。在本节中,我们介绍去雾网的层设计,并讨论这些设计如何与现有图像去雾方法中的思想相关联。从估计的介质透射图获得恢复的无雾图像的最终逐像素操作将在第IV节中给出。

A. Layer Designs of DehazeNet

提出的DehazeNet由级联的卷积层和池化层组成,在其中一些层之后采用适当的非线性激活函数。图2显示了DehazeNet的体系结构。设计了DehazeNet的层次和非线性激活机制,实现了媒体传输估计的特征提取、多尺度映射、局部极值和非线性回归4个顺序操作。我们将这些设计详述如下。

1) Feature Extraction:

为了解决图像去雾问题的不适定性质,现有方法提出了各种假设,并且基于这些假设,它们能够提取雾度相关特征(例如,暗通道、色调差异和色彩衰减)。注意,密集地提取这些雾相关特征等效于将输入雾图像与适当的滤波器卷积,然后进行非线性映射。受那些雾度相关特征的颜色通道中的极值处理的启发,选择称为Maxout单元[30]的不寻常激活函数作为用于降维的非线性映射。最大输出单元是用于多层感知器或神经网络的简单前馈非线性激活函数。当用于神经网络时,它通过对k个仿射特征映射进行逐像素最大化操作来生成新的特征映射。基于Maxout单元,我们设计了DehazeNet的第一层,具体如下

 2) Multi-scale Mapping:

在[17]中,多尺度特征已被证明对雾度去除有效,其在多个空间尺度上密集地计算输入图像的特征。多尺度特征提取也是实现尺度不变性的有效方法。例如,GoogLeNet [31]中的初始架构使用具有不同滤波器大小的并行卷积,并且更好地解决了输入图像中对齐对象的问题,从而在ILSVRC14 [32]中实现了最先进的性能。受这些多尺度特征提取成功的启发,我们选择在DehazeNet的第二层中使用并行卷积操作,其中任何卷积滤波器的大小都在3 × 3,5 × 5和7 × 7之间,并且我们对这三个尺度使用相同数量的滤波器。第二层的输出形式为

 3) Local Extremum:

为了实现空间不变性,视觉皮层中的皮层复合细胞接收来自简单细胞的响应以进行线性特征整合。Ilan等人。[33]提出,复杂细胞的空间整合特性可以通过一系列池化操作来描述。根据CNN的经典架构[34],在每个像素下考虑邻域最大值以克服局部敏感性。此外,局部极值符合介质传输局部恒定的假设,一般是为了克服传输估计的噪声。因此,我们在DehazeNet的第三层中使用局部极值操作。

 其中,Ω(x)是以x为中心的f3xf3邻域,第三层的输出维度n3 = n2。与通常降低特征图分辨率的CNNs中的最大池相比,这里的局部极值操作密集地应用于每个特征图像素,并且能够保持分辨率以用于图像恢复。

4) Non-linear Regression:

深度网络中非线性激活函数的标准选择包括Sigmoid [35]和整流线性单元(ReLU)。前一种算法容易出现梯度消失现象,导致网络训练收敛速度慢或局部最优性差。为了克服梯度消失的问题,提出了提供稀疏表示的ReLU [36]。然而,ReLU是为分类问题而设计的,并不完全适合图像恢复等回归问题。特别是,ReLU仅在值小于零时才禁止值。这可能会导致响应溢出,特别是在最后一层,因为对于图像恢复,最后一层的输出值应该是在一个小范围内的下限和上限。为此,我们提出了一个双边整流线性单元(BReLU)激活函数,如图3所示,以克服这一限制。受Sigmoid和ReLU的启发,BReLU作为一种新的线性单元,保持了双边约束和局部线性。基于所提出的BReLU,第四层的特征图被定义为

 上述四层级联在一起以形成基于CNN的可训练端到端系统,其中与卷积层相关联的滤波器和偏置是要学习的网络参数。我们注意到,这些层的设计可以与现有图像去雾方法中的专业知识相关联,我们将在随后的部分中详细说明。

B. Connections with Traditional Dehazing Methods

DehazeNet中的第一层特征F1被设计用于hazerrelated特征提取。以暗通道特征[9]为例。如果权重W1是相反滤波器(在一个通道的中心处具有值-1的稀疏矩阵,如图4(a)所示)并且B1是单位偏差,则特征图的最大输出等于颜色通道的最小值,这类似于暗通道[9](参见等式(5))。以相同的方式,当权重是如图4(c)的圆形滤波器时,F1类似于最大对比度[7](参见等式(6));当W1包括全通滤波器和相反滤波器时,F1类似于最大和最小特征图,其是从RGB到HSV的颜色空间变换的原子操作,然后提取颜色衰减[18](参见等式(7))和色调视差[29](参见等式(8))特征。总之,在图4(e)中所展示的过滤器学习成功后,可潜在地从DehazeNet的第一层提取几乎所有雾度相关特征。另一方面,Maxout激活函数可以被认为是对任意凸函数的分段线性逼近。在本文中,我们选择四个特征图(k = 4)中的最大值来近似任意凸函数,如图4(d)所示。

图像中的白色物体类似于通常具有高亮度值和低饱和度值的重雾场景。因此,几乎所有的雾度估计模型都倾向于将白色场景对象视为遥远的,从而导致对介质透射率的不准确估计。基于场景深度局部恒定的假设,局部极值滤波器通常用来克服这个问题[9],[18],[7]。在DehazeNet中,第三层操作的局部最大值滤波器去除局部估计误差。因此,当传输t(x)接近零时,直接衰减项J(x)t(x)可以非常接近零。直接恢复的场景辐射度J(x)易于产生噪声。在DehazeNet中,我们提出了BReLU来限制tmin和tmax之间的传输值,从而缓解了噪声问题。请注意,BReLU等效于传统方法[9],[18]中使用的边界约束。

C. Training of DehazeNet

1) Training Data:

通常,收集大量标记数据用于训练深度模型是昂贵的[19]。对于DehazeNet的训练,由于自然场景的有雾和无雾图像对(或有雾图像对及其相关联的介质透射图)不是大量可用的,因此这甚至更加困难。相反,我们采用基于物理雾度形成模型的合成训练数据[17]。

更具体地说,我们基于两个假设合成雾和无雾图像块的训练对[17]:第一,图像内容独立于介质传输(相同的图像内容可以出现在场景的任何深度);第二,介质透射率是局部恒定的(小块中的图像像素趋向于具有相似的深度)。这些假设表明,我们可以假设单个图像块的任意透射率。给定无雾斑块JP(x)、大气光α和随机透射t ∈(0,1),雾斑块合成为IP(x)= JP(x)t+α(1 − t)。为了减少变量学习中的不确定性,大气光α被设置为1。

在这项工作中,我们从互联网上收集无雾图像,并从中随机抽取大小为16 × 16的斑块。与[17]不同的是,这些无雾图像不仅包括捕捉人们日常生活的图像,还包括自然和城市景观的图像,因为我们相信可以将这些各种训练样本学习到DehazeNet的过滤器中。图5显示了我们收集的无雾图像的示例。

2) Training Method:

在DehazeNet中,监督学习需要RGB值与介质透射率之间的映射关系F。网络参数Θ = {W1,W2,W 4,B1,B2,B4}通过最小化训练块IP(x)和对应的地面真实媒体传输t之间的损失函数来实现。给定一组雾图像块及其对应的介质传输,其中雾块是从如上所述的无雾块合成的,我们使用均方误差(MSE)作为损失函数:

 采用随机梯度下降法(SGD)对DehazeNet进行训练。我们使用Caffe包实现我们的模型[37]。我们提出的DehazeNet(如图2所示)的详细配置和参数设置总结在表I中,其包括3个卷积层和1个最大池化层,在第一次和最后一次卷积操作之后分别使用Maxout和BReLU激活。

 

 V. CONCLUSION

本文提出了一种用于单幅图像去雾的深度学习方法。受传统雾度相关特征和去雾方法的启发,我们证明了介质传输估计可以被重构为一个具有特殊设计的可训练的端到端系统,其中特征提取层和非线性回归层不同于经典的神经网络。在第一层F1中,证明了Maxout单元与先验方法相似,能更有效地学习雾度相关特征。在最后一层F4中,一种称为BReLU的新激活函数代替ReLU或Sigmoid以保持图像恢复的双边约束和局部线性。通过这种轻量级的架构,DehazeNet实现了比现有技术更高的效率和更好的去雾效果。

虽然我们成功地将细胞神经网络应用于雾霾去除,但仍有一些可扩展性的研究需要进行。也就是说,大气光α不能视为全局常数,将在统一网络中与介质传输一起学习。此外,我们认为大气散射模型也可以在更深层次的神经网络中学习,其中可以直接优化雾和无雾图像之间的端到端映射,而无需介质传输估计。我们把这个问题留待以后研究。

代码

import torch
import torch.nn as nn
from torch.utils.data.dataset import Dataset
from PIL import Image
import torchvision
from torchvision import transforms
import torch.utils.data as data
#import torchsnooper
import cv2

BATCH_SIZE = 128
EPOCH = 10

# BRelu used for GPU. Need to add that reference in pytorch source file.
class BRelu(nn.Hardtanh):
	def __init__(self, inplace=False):
		super(BRelu, self).__init__(0., 1., inplace)
		
	def extra_repr(self):
		inplace_str = 'inplace=True' if self.inplace else ''
		return inplace_str


class DehazeNet(nn.Module):
	def __init__(self, input=16, groups=4):
		super(DehazeNet, self).__init__()
		self.input = input
		self.groups = groups
		self.conv1 = nn.Conv2d(in_channels=3, out_channels=self.input, kernel_size=5)
		self.conv2 = nn.Conv2d(in_channels=4, out_channels=16, kernel_size=3, padding=1)
		self.conv3 = nn.Conv2d(in_channels=4, out_channels=16, kernel_size=5, padding=2)
		self.conv4 = nn.Conv2d(in_channels=4, out_channels=16, kernel_size=7, padding=3)
		self.maxpool = nn.MaxPool2d(kernel_size=7, stride=1)
		self.conv5 = nn.Conv2d(in_channels=48, out_channels=1, kernel_size=6)
		self.brelu = nn.BReLU()
		for name, m in self.named_modules():
			# lambda : 定义简单的函数    lambda x: 表达式
			# map(func, iter)  iter 依次调用 func
			# any : 有一个是true就返回true
			if isinstance(m, nn.Conv2d):
				# 初始化 weight 和 bias
				nn.init.normal(m.weight, mean=0,std=0.001)
				if m.bias is not None:
					nn.init.constant_(m.bias, 0)
	
	def Maxout(self, x, groups):
		x = x.reshape(x.shape[0], groups, x.shape[1]//groups, x.shape[2], x.shape[3])
		x, y = torch.max(x, dim=2, keepdim=True)
		out = x.reshape(x.shape[0],-1, x.shape[3], x.shape[4])
		return out
	#BRelu used to CPU. It can't work on GPU.
	def BRelu(self, x):
		x = torch.max(x, torch.zeros(x.shape[0],x.shape[1],x.shape[2],x.shape[3]))
		x = torch.min(x, torch.ones(x.shape[0],x.shape[1],x.shape[2],x.shape[3]))
		return x
	
	def forward(self, x):
		out = self.conv1(x)
		out = self.Maxout(out, self.groups)
		out1 = self.conv2(out)
		out2 = self.conv3(out)
		out3 = self.conv4(out)
		y = torch.cat((out1,out2,out3), dim=1)
		#print(y.shape[0],y.shape[1],y.shape[2],y.shape[3],)
		y = self.maxpool(y)
		#print(y.shape[0],y.shape[1],y.shape[2],y.shape[3],)
		y = self.conv5(y)
		# y = self.relu(y)
		# y = self.BRelu(y)
		#y = torch.min(y, torch.ones(y.shape[0],y.shape[1],y.shape[2],y.shape[3]))
		y = self.brelu(y)
		y = y.reshape(y.shape[0],-1)
		return y


loader = torchvision.transforms.Compose([
	transforms.ToTensor(),
	transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
augmentation = torchvision.transforms.Compose([
	transforms.RandomHorizontalFlip(0.5),
	transforms.RandomVerticalFlip(0.5),
	transforms.RandomRotation(30),
	transforms.ToTensor(),
	transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])


class FogData(Dataset):
	# root:图像存放地址根路径
	# augment:是否需要图像增强
	def __init__(self, root, labels, augment=True):
		# 初始化 可以定义图片地址 标签 是否变换 变换函数
		self.image_files = root
		self.labels = torch.cuda.FloatTensor(labels)
		self.augment = augment   # 是否需要图像增强
		# self.transform = transform

	def __getitem__(self, index):
		# 读取图像数据并返回
		if self.augment:
			img = Image.open(self.image_files[index])
			img = augmentation(img)
			img = img.cuda()
			return img, self.labels[index]
		else:
			img = Image.open(self.image_files[index])
			img = loader(img)
			img = img.cuda()
			return img, self.labels[index]

	def __len__(self):
		# 返回图像的数量
		return len(self.image_files)


path_train = []
file = open('path_train.txt', mode='r')
content = file.readlines()
for i in range(len(content)):
	path_train.append(content[i][:-1])

label_train = []
file = open('label_train.txt', mode='r')
content = file.readlines()
for i in range(len(content)):
	label_train.append(float(content[i][:-1]))
	#print(float(content[i][:-1]))

train_data = FogData(path_train, label_train, False)
train_loader = data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True, )

net = DehazeNet()
net.load_state_dict(torch.load(r'defog4_noaug.pth', map_location='cpu'))

#@torchsnooper.snoop()
def train():
	lr = 0.00001
	optimizer = torch.optim.Adam(net.parameters(), lr=0.0000005)
	loss_func = nn.MSELoss().cuda()
	for epoch in range(EPOCH):
		total_loss = 0
		for i, (x, y) in enumerate(train_loader):
	# 输入训练数据
	# 清空上一次梯度
			optimizer.zero_grad()
			output = net(x)
	# 计算误差
			loss = loss_func(output, y)
			total_loss = total_loss+loss
	# 误差反向传递
			loss.backward()
	# 优化器参数更新
			optimizer.step()
			if i % 10 == 5:
				print('Epoch', epoch, '|step ', i, 'loss: %.4f' % loss.item(), )
		print('Epoch', epoch, 'total_loss', total_loss.item())
	torch.save(net.state_dict(), r'defog4_noaug.pth')


#train()


def defog(pic_dir):
	img = Image.open(pic_dir)
	img1 = loader(img)
	img2 = transforms.ToTensor()(img)
	c, h, w = img1.shape
	patch_size = 16
	num_w = int(w / patch_size)
	num_h = int(h / patch_size)
	t_list = []
	for i in range(0, num_w):
		for j in range(0, num_h):
			patch = img1[:, 0 + j * patch_size:patch_size + j * patch_size,
				0 + i * patch_size:patch_size + i * patch_size]
			patch = torch.unsqueeze(patch, dim=0)
			t = net(patch)
			t_list.append([i,j,t])
	
	t_list = sorted(t_list, key=lambda t_list:t_list[2])
	a_list = t_list[:len(t_list)//100]
	a0 = 0
	for k in range(0,len(a_list)):
		patch = img2[:, 0 + a_list[k][1] * patch_size:patch_size + a_list[k][1] * patch_size,
				0 + a_list[k][0] * patch_size:patch_size + a_list[k][0] * patch_size]
		a = torch.max(patch)
		if a0 < a.item():
			a0 = a.item()
	for k in range(0,len(t_list)):
		img2[:, 0 + t_list[k][1] * patch_size:patch_size + t_list[k][1] * patch_size,
			0 + t_list[k][0] * patch_size:patch_size + t_list[k][0] * patch_size] = (img2[:,
			0 + t_list[k][1] * patch_size:patch_size + t_list[k][1] * patch_size,
			0 + t_list[k][0] * patch_size:patch_size + t_list[k][0] * patch_size] - a0*(1-t_list[k][2]))/t_list[k][2]
	defog_img = transforms.ToPILImage()(img2)
	defog_img.save('/home/panbing/PycharmProjects/defog/test/test.jpg')


defog('/home/panbing/PycharmProjects/defog/test/fogpic.jpg')

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值