3.1 概述

  1. 分类:Zero-shot Learning

  2. 数据集:SICE、NPE、LIME、MEF、DICM、VV、DARK FACE

  3. 损失函数:

    1. spatial consistency loss(空间一致性损失函数)
    2. exposure control loss(曝光控制损失函数)
    3. color constancy loss(颜色恒定损失函数)
    4. illumination smoothness loss(照明平滑度损失函数)
  4. 评估标准:User Study PI; PNSR SSIM; MAE Runtime; Face detection

  5. 现存难点

    1. 配对数据训练:1)数据难以收集 2)如果使用合成数据训练,模型泛化能力往往有限
    2. 非配对数据训练:需要精心选择非配对训练数据
  6. 动机:有些图像编辑软件更改曲线就能修改图像,所以本文也想设计一种通过修改曲线就能实现暗图像增强

3.2 贡献

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4tyuL8gh-1685260025119)(7、论文总结.assets/image-20230523194653403.png)]

  1. 贡献一: 首创不基于配对数据或非配对数据的增强网络
    1. 优点:1)防止过拟合 2)泛化能力强
  2. 贡献二:设计了一种图像特定的曲线,这些曲线能对输入动态范围进行像素级调整,以获得增强图像
  3. 贡献三:提出了利用特定非参考损失函数间接评估增强质量,探索在没有参考图像的情况下训练一个深度图像增强模型的可能性

3.3 摘要

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D3TJKGv9-1685260025121)(7、论文总结.assets/image-20230523190443689.png)]

  1. Zero-DCE以低光图像为输入,产生高阶曲线作为输出。然后使用这些曲线对输入动态范围进行像素级调整,以获得增强图像
  2. 曲线是专门设计的,考虑了像素值范围单调性可微性
  3. 优点:训练的时候不需要配对数据,也不需要非配对数据
  4. 缺点:需要精心设计非参考损失函数以下是本文精心设计的非参考损失函数
    1. spatial consistency loss(空间一致性损失函数)
    2. exposure control loss(曝光控制损失函数)
    3. color constancy loss(颜色恒定损失函数)
    4. illumination smoothness loss(照明平滑度损失函数)

3.4 网络结构及解析

3.4.1 LE曲线

LE曲线:Light-Enhancement Curve (LE-curve)

3.4.1.1 曲线要求
  1. 增强图像的每个像素值应在[0,1]的归一化范围内,以避免溢出截断引起的信息丢失
    1. 疑问:为什么需要归一化,在什么情况下会导致溢出截断
    2. 解答:如果按照正常像素值进行操作,多次255255255相加就可能因数值过大导致截断溢出
  2. 这条曲线应该是单调的,以保持相邻像素的差异(对比度)
    1. 疑问:为什么曲线得要是单调的,单调曲线为啥能保持相邻像素的差异
    2. 解答:如果一个像素值本来就是比另一个大,那么经过变换后这个像素值仍然应该比另一个像素值大。这样可以保持相邻像素值之前的差异,也就是对比度。如果不是单调的,经过变换后亮的变暗,暗的变亮,这会降低图像的质量
  3. 在梯度反向传播过程中,这条曲线的形式应尽可能简单和可微
    1. 疑问:曲线简单和可微对于反向传播有何益处?
    2. 解答
      1. 简单:简单的曲线参数量少,相应的计算量少,而且能降低过拟合的风险
      2. 可微:这样网络就可以通过梯度反向传播更新参数,从而提升性能
3.4.1.2 曲线函数
1)公式

LE(I(x);α)=I(x)+αI(x)(1−I(x)) LE(I(x);\alpha)=I(x)+\alpha I(x)(1-I(x)) LE(I(x);α)=I(x)+αI(x)(1I(x))

x\color{#DD5145}xx:像素坐标

α\color{#DD5145}\alphaαα∈[−1,1]\alpha\in [-1,1]α[1,1]α\alphaα能控制IEIEIE曲线的大小,并能控制曝光水平

I(x)\color{#DD5145}I(x)I(x):输入内容,I(x)∈[0,1]I(x)\in [0,1]I(x)[0,1]

LE(I(x);α)\color{#DD5145}LE(I(x);\alpha)LE(I(x);α):输入的增强版本

2)图像
不同α值对图像的影响

LE(I(x);α)={I(x)2α=−1I(x)α=0−(I(x)−1)2+1α=1 LE(I(x);\alpha)= \begin{cases} I(x)^2 & \alpha=-1\\ I(x) & \alpha=0 \\ -(I(x)-1)^2+1 & \alpha =1 \end{cases} LE(I(x);α)= I(x)2I(x)(I(x)1)2+1α=1α=0α=1

由图像可知:LE(I(x);α)LE(I(x);\alpha)LE(I(x);α)大多时候是一个简单的单调递增的二次函数

3)效果

这函数能有效地增加减少输入图像的动态范围,还能移除过曝伪影

  • 疑问

    • 什么是过曝?

      • 过曝是指在拍照时,有太多的光线进入相机,使得照片变得太亮,失去了细节对比度
      过曝图像示例
    • 什么是伪影?

      • 伪影是指在照片中出现一些不真实或不自然的现象,比如颜色失真噪点模糊条纹等。
      图1 颜色失真
      图2 噪点失真
      图3 模糊图像
      图4 条纹伪影
    • 什么是过曝伪影?

      • 过曝伪影是指在图片中,由于过曝导致的一种伪影
      太阳光强的周围建筑明显出现了颜色失真等伪影问题
3.4.1.3 高阶曲线

由于二次函数曲线变化有限,为了拟合更为复杂的曲线,本文迭代嵌套了这个函数

LE1(x)=I(x)+α1I(x)(1−I(x))LE2(x)=LE1(x)+α2LE1(x)(1−LE1(x))⋯⋯LEn(x)=LEn−1(x)+αnLEn−1(1−LEn−1(x)) \begin{aligned} LE_1(x)&=I(x)+\alpha_1I(x)(1-I(x)) \\ LE_2(x)&=LE_1(x)+\alpha_2LE_1(x)(1-LE_1(x))\\ \\ \cdots\cdots\\ \\ LE_n(x)&=LE_{n-1}(x)+\alpha_nLE_{n-1}(1-LE_{n-1}(x)) \end{aligned} LE1(x)LE2(x)⋯⋯LEn(x)=I(x)+α1I(x)(1I(x))=LE1(x)+α2LE1(x)(1LE1(x))=LEn1(x)+αnLEn1(1LEn1(x))

n用于控制曲率的迭代次数,本文n设置为8

n=4时,曲线随α变化效果
3.4.1.4 逐像素曲线

高阶曲线可以在更宽的动态范围内调整图像。尽管如此,它仍然是一个全局调整,因为 α 用于所有像素。全局映射倾向于过度/不足地增强局部区域。为了解决这个问题,我们将 α 表述为逐像素参数,即给定输入像的每个像素都有一个对应的曲线,具有最佳拟合 α 来调整其动态范围。

LEn(x)=LEn−1(x)+An(x)(1−LEn−1(x)) LE_n(x)=LE_{n-1}(x)+\mathcal{A}_n(x)(1-LE_{n-1}(x)) LEn(x)=LEn1(x)+An(x)(1LEn1(x))

A\mathcal{A}A是与给定图像大小相同的参数图

n=8,中间三张图是输入图像R、G、B三通道的A参数图

3.4.2 DCE−NetDCE-NetDCENet

DCE-Net网络

输入:低光照图像(256×256×3256\times256\times3256×256×3

输出:一组像素级的曲线参数图(最终产生了242424个参数图)

卷积核:每一层由323232个大小为3×33\times 33×3,步长为111的卷积核组成,

激活函数:除了最后一个卷积层使用TanhTanhTanh激活函数外,其余层都是使用的是ReLUReLUReLU激活函数

3.4.3 无参考损失函数

3.4.3.1 Spatial Consistency Loss

Spatial Consistency Loss :空间一致性损失,一种用于衡量图像提亮效果的方法
主要思想:提亮后的图像应该和原来的图像在空间上保持一致,也就是说,相邻的像素之间的差别不应该变得太大或太小

Lspa=1K∑i=1K∑j∈Ω(i)(∣Yi−Yj∣−∣(Ii−Ij)∣)2 L_{spa}=\frac{1}{K}\sum_{i=1}^{K}\sum_{j\in\Omega(i) }(|Y_i-Y_j|-|(I_i-I_j)|)^2 Lspa=K1i=1KjΩ(i)(YiYj(IiIj))2

K:局部区域的数量

Ω(i)\color{#DD5145}\Omega(i)Ω(i)Ω(i)\Omega(i)Ω(i)是以区域 iii 为中心的四个相邻区域(顶部、下、左、右)

Y增强版本的局部区域的平均强度值

I输入版本的局部区域的平均强度值

2)代码
# Spatial Consistency Loss : 空间一致性损失
class L_spa(nn.Module):

    def __init__(self):
        super(L_spa, self).__init__()
        # print(1)kernel = torch.FloatTensor(kernel).unsqueeze(0).unsqueeze(0)
        kernel_left = torch.FloatTensor([[0, 0, 0], [-1, 1, 0], [0, 0, 0]]).unsqueeze(0).unsqueeze(0)
        kernel_right = torch.FloatTensor([[0, 0, 0], [0, 1, -1], [0, 0, 0]]).unsqueeze(0).unsqueeze(0)
        kernel_up = torch.FloatTensor([[0, -1, 0], [0, 1, 0], [0, 0, 0]]).unsqueeze(0).unsqueeze(0)
        kernel_down = torch.FloatTensor([[0, 0, 0], [0, 1, 0], [0, -1, 0]]).unsqueeze(0).unsqueeze(0)
        self.weight_left = nn.Parameter(data=kernel_left, requires_grad=False)
        self.weight_right = nn.Parameter(data=kernel_right, requires_grad=False)
        self.weight_up = nn.Parameter(data=kernel_up, requires_grad=False)
        self.weight_down = nn.Parameter(data=kernel_down, requires_grad=False)
        self.pool = nn.AvgPool2d(4)

    def forward(self, org, enhance):
        b, c, h, w = org.shape

        org_mean = torch.mean(org, 1, keepdim=True)
        enhance_mean = torch.mean(enhance, 1, keepdim=True)

        org_pool = self.pool(org_mean)
        enhance_pool = self.pool(enhance_mean)

        weight_diff = torch.max(
            torch.FloatTensor([1]) + 10000 * torch.min(org_pool - torch.FloatTensor([0.3]),
                                                              torch.FloatTensor([0])),
            torch.FloatTensor([0.5]))
        E_1 = torch.mul(torch.sign(enhance_pool - torch.FloatTensor([0.5])), enhance_pool - org_pool)

        D_org_letf = F.conv2d(org_pool, self.weight_left, padding=1)
        D_org_right = F.conv2d(org_pool, self.weight_right, padding=1)
        D_org_up = F.conv2d(org_pool, self.weight_up, padding=1)
        D_org_down = F.conv2d(org_pool, self.weight_down, padding=1)

        D_enhance_letf = F.conv2d(enhance_pool, self.weight_left, padding=1)
        D_enhance_right = F.conv2d(enhance_pool, self.weight_right, padding=1)
        D_enhance_up = F.conv2d(enhance_pool, self.weight_up, padding=1)
        D_enhance_down = F.conv2d(enhance_pool, self.weight_down, padding=1)

        D_left = torch.pow(D_org_letf - D_enhance_letf, 2)
        D_right = torch.pow(D_org_right - D_enhance_right, 2)
        D_up = torch.pow(D_org_up - D_enhance_up, 2)
        D_down = torch.pow(D_org_down - D_enhance_down, 2)
        E = (D_left + D_right + D_up + D_down)
        # E = 25*(D_left + D_right + D_up +D_down)

        return E
3.4.3.2 Exposure Control Loss

Exposure Control Loss :曝光控制损失,一种用来衡量图像曝光效果的方法

主要思想:提亮后的图像应该避免有过暗或过亮的区域,而是让每个像素的亮度都接近一个合适的水平

计算

  1. 将提亮图像转换成灰度图
  2. 把灰度图划分成很多个小块,每个小块里有16×1616\times1616×16个像素
  3. 计算所有像素的平均亮度,然后和预设的理想亮度进行比较,本文的理想亮度叫做:well-exposedness level,值为0.60.60.6
  4. 计算每个小块的平均亮度和理想亮度之间的差别求绝对值,然后求平均
  5. Exposure Control Loss值越小,提亮后的图像和理想亮度月接近,反之则提亮后的图像存在过亮或过暗的问题
1)公式

Lexp=1M∑k=1M∣Yk−E∣ L_{exp}=\frac{1}{M}\sum_{k=1}^{M}|Y_k-E| Lexp=M1k=1MYkE

M:表示大小为$ 16\times16$ 的非重叠局部区域的数量

Y增强图像的局部区域的平均强度值

E:well-exposedness level理想亮度值,本文设置的值为0.60.60.6

2)代码
# Exposure Control Loss : 曝光控制损失
class L_exp(nn.Module):

    def __init__(self, patch_size, mean_val):
        super(L_exp, self).__init__()
        # print(1)
        self.pool = nn.AvgPool2d(patch_size)
        self.mean_val = mean_val

    def forward(self, x):
        b, c, h, w = x.shape
        x = torch.mean(x, 1, keepdim=True)
        mean = self.pool(x)

        d = torch.mean(torch.pow(mean - torch.FloatTensor([self.mean_val]), 2))
        return d
3.4.3.3 Color Constancy Loss

Color Constancy Loss : 颜色恒定损失,一种用来保持图像颜色平衡的方法

主要思想:提亮后的图像应该避免有色偏的现象,而是让每个颜色通道(红、绿、蓝)的平均亮度都接近一个灰度值

计算

  1. 将提亮图像分成RRRGGGBBB三通道,计算每个通道的平均亮度,记作JpJ^pJp
  2. 将不同通道的平均亮度两两相减,求平均和
  3. Color Constancy Loss值越小,说明提亮图像颜色越平衡,损失越大则说明提亮图像可能有色偏的问题
1)公式

Lcol=∑∀(p,q)∈ε(Jp−Jq)2,ε=(R,G),(R,B),(G,B) L_{col}=\sum_{\forall (p,q)\in\varepsilon }(J^p-J^q)^2,\varepsilon ={(R,G),(R,B),(G,B)} Lcol=(p,q)ε(JpJq)2,ε=(R,G),(R,B),(G,B)

2)代码
# Color Constancy Loss : 颜色恒定损失
class L_color(nn.Module):

    def __init__(self):
        super(L_color, self).__init__()

    def forward(self, x):
        b, c, h, w = x.shape

        mean_rgb = torch.mean(x, [2, 3], keepdim=True)
        mr, mg, mb = torch.split(mean_rgb, 1, dim=1)
        Drg = torch.pow(mr - mg, 2)
        Drb = torch.pow(mr - mb, 2)
        Dgb = torch.pow(mb - mg, 2)
        k = torch.pow(torch.pow(Drg, 2) + torch.pow(Drb, 2) + torch.pow(Dgb, 2), 0.5)

        return k
3.4.3.4 Illumination Smoothness Loss

Illumination Smoothness Loss :照明光滑度损失,一种用来保持图像光照平滑的方法

主要思想:提亮后的图像应该避免有明显的光照变化或伪影,而是让每个像素的光照变化都很小

计算

  1. 将提亮图像分成三个颜色通道,然后计算每个通道的光照曲线参数图A\mathcal{A}A
  2. 在每个参数图A\mathcal{A}A在水平方向和垂直方向上求梯度,也就是求它们的变化率
  3. 计算所有梯度的平方和后求平均
  4. Illumination Smoothness Loss越小,提亮图像光照越平滑,反之说明提亮图像光照有突变或伪影
1)公式

LtvA=1N∑n=1N∑c∈ξ(∣∇xAnc+∇yAnc∣)2,ξ={R,G,B} L_{tv_\mathcal{A} }=\frac{1}{N}\sum _{n=1}^N\sum_{c\in\xi }(|\nabla_x\mathcal{A}_n^c +\nabla_y \mathcal{A}_n^c |) ^2,\xi =\{R,G,B\} LtvA=N1n=1Ncξ(xAnc+yAnc)2,ξ={R,G,B}

N:迭代次数

∇x\color{#DD5145} \nabla_xx :水平梯度操作

∇y\color{#DD5145}\nabla_yy:垂直梯度操作

A\color{#DD5145}\mathcal{A}A:曲线参数图

2)代码
# Illumination Smoothness Loss : 照明损失度函数
class L_TV(nn.Module):
    def __init__(self, TVLoss_weight=1):
        super(L_TV, self).__init__()
        self.TVLoss_weight = TVLoss_weight

    def forward(self, x):
        batch_size = x.size()[0]
        h_x = x.size()[2]
        w_x = x.size()[3]
        count_h = (x.size()[2] - 1) * x.size()[3]
        count_w = x.size()[2] * (x.size()[3] - 1)
        h_tv = torch.pow((x[:, :, 1:, :] - x[:, :, :h_x - 1, :]), 2).sum()
        w_tv = torch.pow((x[:, :, :, 1:] - x[:, :, :, :w_x - 1]), 2).sum()
        return self.TVLoss_weight * 2 * (h_tv / count_h + w_tv / count_w) / batch_size
3.4.3.5 总损失

Ltotal=Lspa+Lexp+WcolLcol+WtvALtvA L_{total}=L_{spa}+L_{exp}+W_{col}L_{col}+W_{tv_{\mathcal{A}}}L_{tv_{\mathcal{A}}} Ltotal=Lspa+Lexp+WcolLcol+WtvALtvA

3.5 实验部分

3.5.1 概述

训练图像242224222422张,图像大小为:512×512512\times 512512×512

测试图像600600600

网络参数

  1. batch size888
  2. 网络权值初始化:均值为000,方差为0.020.020.02的标准差高斯函数
  3. 偏置初始化:常量
  4. 优化器ADAMADAMADAM
  5. 学习率1e−41e^{-4}1e4
  6. Wcol\color{#9414aa}W_{col}Wcol0.50.50.5
  7. WtvA\color{#9414aa}W_{tv_{\mathcal{A}}}WtvA202020

3.5.2 消融实验

3.5.2.1 各损失函数的贡献

在这里插入图片描述

w/o Lspa\color{#DD5145}w/o\ L_{spa}w/o Lspa:对比度较低(例如:云区)

w/o Lexp\color{#DD5145}w/o\ L_{exp}w/o Lexp:无法恢复低光区域

w/o Lcol\color{#DD5145}w/o\ L_{col}w/o Lcol:出现了严重的颜色投射

w/o LtvA\color{#DD5145}w/o\ L_{tv_{\mathcal{A}}}w/o LtvA:出现了明显的伪影

3.5.2.2 参数设置效果
l-f-n:l表示l个卷积层(即网络层数)、
f表示每层卷积核个数(即输出通道数)、n表示曲线的迭代次数

Zero−DCE3−32−8\color{#dd5145}Zero-DCE_{3-32-8}ZeroDCE3328:这个的效果已经很好了

Zero−DCE7−32−8、Zero−DCE7−32−16\color{#dd5145}Zero-DCE_{7−32−8}、Zero-DCE_{7−32−16}ZeroDCE7328ZeroDCE73216:在自然曝光和适当对比度下产生最令人愉悦的视觉效果

Zero−DCE7−32−8\color{#9414aa}Zero-DCE_{7-32-8}ZeroDCE7328:本文选择的最终模型,在效率和恢复性能之间取得了良好的平衡

3.5.2.3 训练数据的影响

在这里插入图片描述
数据集

  1. Zero−DCElow\color{#1f71e0}Zero-DCE_{low}ZeroDCElow242224222422张图像,其中900900900张微光图像
  2. Zero−DCELargeL\color{#1f71e0}Zero-DCE_{LargeL}ZeroDCELargeL:暗脸数据集提供的900090009000张未标记的微光图像
  3. Zero−DCELargeLH\color{#1f71e0}Zero-DCE_{LargeLH}ZeroDCELargeLH:来自SICESICESICE数据集Part1Part1Part1Part2Part2Part2子集的数据增强组合的480048004800幅多次曝光图像

效果

  1. (c)、(d)\color{#1f71e0}(c)、(d)(c)(d):倾向过度增强光照良好的区域(例如:面部),表明了多曝光训练数据的合理性和必要性
  2. (e)\color{#1f71e0}(e)(e):能更好地恢复暗区域

3.5.3 基准评估

这部分基本是和其它最先进的方法比较,然后说明自己的方法牛逼

3.6 结论

在这里插入图片描述
我们提出了一个用于微光图像增强的深度网络。它可以通过零参考图像进行端到端训练。这是通过将微光图像增强任务制定为图像特定的曲线估计问题来实现的,并设计了一组可微的非参考损失。实验证明了我们的方法与现有的光增强方法的优越性。在未来的工作中,我们将尝试引入语义信息来解决困难情况并考虑噪声的影响。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐