1.Single Image Haze Removal Using Dark Channel Prior
这是何凯明在博士期间发表的一篇经典的图像去雾算法的文章。这篇文章中他通过观察提出了一种暗通道算法(Dark Channel Prior),简单来说就在一张正常图像中,除了天空区域,在图像的每个小块(patch)中一定有一些像素点至少有一个通道的值是非常小的,基于这个先验条件,何凯明团队使用了一种简单有效的办法来进行图像去雾。
下面的公式为经典的去雾模型,其中指获取得到的图片亮度,是去雾后恢复的图像,指透射率,是指大气的光成分(即雾成分)。这个公式还是很容易直观的理解,因为透射率可以在一定程度上代表损失率。为大气散射系数,为景深。
由于在统计意义上,一个patch中总有几个像素的至少一个通道是很暗的,此时的趋近于0,于是在一个patch中有如下公式成立:
这样我们就可以算出t的近似值了。同时,当patch为天空时,大气光和真实图像光十分相近,于是t的近似值趋向于0。
获得了反射率t以后,下一步便是对图像进行soft matting获得轮廓特征,这样可以将透射率t精细化。
这样我们就获得了精细化后的透射率t值。对于有雾区域,我们可以根据下面的公式进行去雾,其中我们对t设定了一个最低的阈值。
对于A的获取,我们可以借助于暗通道图来从有雾图像中获取该值。从暗通道图中按照亮度的大小取前0.1%的像素。
在这些位置中,在原始有雾图像I中寻找对应的具有最高亮度的点的值,作为A值。
以下图为例说明一下这么做的理由:如果使用传统的方法,直接选取图像中的亮度值最高的点作为全局大气光值,这样原始有雾图像中的白色物体会对此有影响,使得其值偏高。暗通道的运算可以抹去原始图像中小块的白色物体,所以这样估计的全局大气光值会更准确。
最终的公式如下:
2.DehazeNet: An End-to-End System for Single Image Haze Removal
在这篇文章中,作者提出了用神经网络方法对反射率t进行训练并预测,网络结构如下:
首先用CNN接maxout抽取图像特征,再接几个平行的multi-scale mapping,然后进行池化,经过BReLU激活函数得到最终的反射率t
BReLU如图b所示,因为rgb具有上界和下界,如果不进行截断可能会越界。
网络结构如图:
Pytorch复现:
import torch
import torch.nn as nn
import numpy as np
import cv2
import random
from torchsummary import summary
import os
from torch.autograd import Variable
from tqdm import tqdm
import torch.utils.data as Data
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
class MaxoutConv(torch.nn.Module):
def __init__(self, in_channels,
out_channels, kernel_size,stride):
super(MaxoutConv, self).__init__()
self.conv = torch.nn.Conv2d(in_channels, out_channels, kernel_size,stride=stride)
self.BN = torch.nn.BatchNorm2d(out_channels)
def forward(self, _input, is_norm=False):
z = self.conv(_input)
if is_norm:
z = self.BN(z)
# (batch size, channels, height, width)
h = torch.max(z, 1).values # take max operation from first dimension(channel)
# Insert 1 as channel dimension to h
hshape = h.shape
h = h.reshape(*([hshape[0]] + [1] + list(hshape[1:])))
return h
class BRelu(nn.Module):
def __init__(self):
super(BRelu,self).__init__()
self.relu=nn.ReLU()
def forward(self,x):
return torch.min(self.relu(x),torch.tensor([1.0],device=device))
class DehazeNet(nn.Module):
def __init__(self):
super(DehazeNet, self).__init__()
#conv2d_maxout
self.conv_1=MaxoutConv(in_channels=3,out_channels=4,kernel_size=(5,5),stride=(1,1))
self.conv_2=MaxoutConv(in_channels=3,out_channels=4,kernel_size=(5,5),stride=(1,1))
self.conv_3=MaxoutConv(in_channels=3,out_channels=4,kernel_size=(5,5),stride=(1,1))
self.conv_4=MaxoutConv(in_channels=3,out_channels=4,kernel_size=(5,5),stride=(1,1))
#multi-scale conv
self.multi_layer_1=nn.Conv2d(in_channels=4,out_channels=16, kernel_size=(3, 3),stride=(1,1),padding=1)
self.multi_layer_2=nn.Conv2d(in_channels=4,out_channels=16, kernel_size=(5, 5),stride=(1,1),padding=2)
self.multi_layer_3=nn.Conv2d(in_channels=4,out_channels=16, kernel_size=(7, 7),stride=(1,1),padding=3)
#max pool
self.max_pool_1=nn.MaxPool2d(kernel_size=(7,7),stride=(1,1))
self.conv_5=nn.Conv2d(in_channels=48,out_channels=1,kernel_size=(6, 6), stride=(1, 1))
self.brelu=BRelu()
def forward(self,x):
x=torch.cat([self.conv_1(x),self.conv_2(x),self.conv_3(x),self.conv_4(x)],axis=1)
x=self.max_pool_1(torch.cat([self.multi_layer_1(x),self.multi_layer_2(x),self.multi_layer_3(x)],axis=1))
x=self.conv_5(x)
return self.brelu(x)
model=DehazeNet().to(device)
summary(model,(3,16,16))
网友评论