Kindling the Darkness:A Practical Low-light Image Enhancer

时间:2024-03-30 18:27:04

Abstract

在弱光条件下拍摄的图像通常会出现(部分)可见度较差的情况。,除了令人不满意的照明之外,多种类型的退化也隐藏在黑暗中,例如由于相机质量有限而导致的噪点和颜色失真。,换句话说,仅仅调高黑暗区域的亮度将不可避免地放大隐藏的伪像。,这项工作为 Kindling the Darkness(记为 KinD)构建了一个简单而有效的网络,该网络受 Retinex 理论的启发,将图像分解为两个部分。,一个组件(照明)负责光调节,而另一个组件(反射率)负责消除退化。,通过这种方式,原始空间被解耦成两个更小的子空间,期望得到更好的正则化/学习。,值得注意的是,我们的网络是使用在不同曝光条件下拍摄的配对图像进行训练的,而不是使用任何地面实况反射率和照明信息。,进行了大量的实验来证明我们的设计的有效性及其相对于最先进的替代方案的优越性。,我们的 KindD 能够有效应对严重的视觉缺陷,并且用户可以任意调整光线水平。,此外,我们的模型在 2080Ti GPU 上处理 VGA 分辨率图像的时间不到 50 毫秒。,所有上述优点使我们的 KindD 具有实际应用的吸引力。

1 INTRODUCTION

很多时候,在昏暗的光线条件下捕捉高质量的图像是具有挑战性的。,虽然在这种情况下可以进行一些操作,例如设置高ISO、长时间曝光和闪光,但它们都有不同的缺点。,例如,高 ISO 会增加图像传感器对光的敏感度,但噪声也会被放大,从而导致低(信噪比)SNR。,长曝光仅限于拍摄静态场景,否则很可能会出现结果模糊的问题。,使用闪光灯可以在某种程度上使环境变亮,但是这经常会给照片带来意想不到的亮点和不平衡的光线,使照片在视觉上令人不快。,在实践中,典型用户甚至可能无法使用有限的拍摄工具(例如,相机)来实现上述选项。,嵌入便携式设备中的相机。,尽管低光图像增强一直是社区中长期存在的问题,并且在过去几年中取得了很大进展,但开发实用的低光图像增强器仍然具有挑战性,因为灵活地照亮黑暗,有效消除退化,以及,效率应该是所有人都关心的。

图 1 提供了在具有挑战性的光照条件下拍摄的三张自然图像。,具体来说,第一种情况是光线极弱的情况。,黑暗中隐藏着严重的噪点和色彩失真。,通过简单地放大图像的强度,退化就会显示在右上角。,第二张图像是在日落时拍摄的(环境光较弱),其中大多数物体都受到背光的影响。,中午面对光源(太阳)成像也很难摆脱像第二种情况所示的问题,尽管环境光更强并且场景更清晰。,请注意,最后两张照片的那些相对明亮的区域将通过直接放大而饱和。

基于深度学习的方法在数值低级视觉任务(例如去噪和超分辨率)中展现了其优越的性能,其中大多数任务需要具有真实值的训练数据。,对于目标问题,例如弱光图像增强,尽管可以确定光强度的顺序,但不存在真实的真实数据。,因为,从用户的角度来看,不同的人/需求最喜欢的灯光水平可能会有很大不同。,换句话说,我们无法说出什么光线条件是最好的/真实的。,因此,仅将图像映射到具有特定光照水平的版本并不那么合适。

基于上述分析,我们将弱光图像增强的挑战总结如下:

• 如何有效地估计单幅图像的光照分量,并灵活调整光照水平? ,

• 如何在照亮黑暗区域后消除先前隐藏在黑暗中的噪声和颜色失真等劣化? ,

• 如何通过仅查看两个/几个不同的示例来训练没有明确定义的地面实况光照条件的模型以实现低光图像增强?

在本文中,我们提出了一种深度神经网络来同时考虑上述问题。

1.1 Previous Arts

人们提出了大量的弱光图像增强方案。,下面我们简单回顾一下与我们密切相关的经典和当代作品。

Plain Methods

直观上,对于全局低光的图像,可以通过直接放大来增强可见度。,但是,如图 1 的第一种情况所示,包括噪点和颜色失真在内的视觉缺陷沿着细节显现出来。,对于包含明亮区域的图像,例如,对于图 1 中的最后两张图片,此操作很容易导致(部分)饱和/过度曝光。,一条技术路线,以直方图均衡化(HE)[1]、[2]、[3]及其后续[4]、[5]为代表,试图将取值范围映射为[0, 1]并进行平衡,用于避免截断问题的输出直方图。,这些方法实际上旨在增加图像的对比度。,另一种映射方式是伽马校正(GC),它以非线性方式对每个像素单独进行。,虽然GC可以提升亮度,特别是暗像素的亮度,但它没有考虑某个像素与其邻居的关系。,普通方法的主要缺点是它们几乎不考虑真实的照明因素,通常会使增强的结果在视觉上容易受到影响并且与真实场景不一致。

Traditional Illumination-based Methods.

与普通方法不同,此类策略了解光照的概念。,受 Retinex 理论 [6] 启发,关键假设是(彩色)图像可以分解为两个组成部分,即反射率和照明度。,早期的尝试包括单尺度 Retinex (SSR) [7] 和多尺度 Retinex (MSR) [8]。,受限于产生最终结果的方式,输出通常看起来不自然并且在某些地方过度增强。,王等人。,提出了一种称为 NPE [9] 的方法,该方法共同增强对比度并保持照明的自然度。,傅等人。,开发了一种方法[10],通过融合初始估计的照明图的多个推导来调整照明。,然而,这种方法有时会牺牲那些包含丰富纹理的区域的真实感。,郭等人。,专注于从初始图估计结构化照明图 [11]。,这些方法通常假设图像无噪声和颜色失真,并且没有明确考虑退化。,在[12]中,设计了一种用于同时反射率和照明估计(SRIE)的加权变分模型以获得更好的反射率和照明层,然后通过操纵照明来生成目标图像。,继[11]之后,Li 等人。,进一步引入了一个额外的术语来表示宿主噪声[13]。,虽然[12]和[13]都可以抑制图像中的轻微噪声,但它们在处理颜色失真和严重噪声方面缺乏能力。

Deep Learning-based Methods

随着深度学习的出现,许多低级视觉任务已经受益于深度模型,例如用于去噪的[14]、[15],用于超分辨率的[16],用于压缩伪影去除的[17]和,[18] 用于除雾。,关于本文的目标任务,[19]中提出的低光网络(LLNet)构建了一个深度网络,该网络充当同时对比度增强和去噪模块。,沉等人。,认为多尺度Retinex相当于具有不同高斯卷积核的前馈卷积神经网络。,受此启发,他们构建了一个卷积神经网络(MSR-net)[20]来学习暗图像和亮图像之间的端到端映射。,魏等人。,设计了一个名为 RetinexNet [21] 的深度网络,它集成了图像分解和照明映射。,请注意,Retinex-Net 还使用了现成的去噪工具(BM3D [22])来清理反射分量。,这些策略都假设存在具有“地面真实”光的图像,而没有考虑噪声对具有不同光的区域的不同影响。,简单来说,提取光照因子后,暗区的噪声水平(远)高于亮区的反射率。,在这种情况下,采用/训练在图像上具有均匀能力(反射率)的降噪器不再合适。,此外,上述方法没有明确处理颜色失真的退化,这在实际图像中并不罕见。,最近,陈等人。,提出了一种基于全卷积网络的端到端训练的低光图像处理管道[23],它可以联合处理噪声和颜色失真。,然而,这项工作特定于RAW格式的数据,限制了其适用场景。,正如[23]中所述,如果修改网络以接受JPEG格式的数据,性能会显着下降。

大多数现有方法通过伽玛校正来操纵照明,指定精心构建的训练数据或融合中存在的级别。,对于伽马校正,它可能无法反映不同光线(曝光)级别之间的关系。,对于第二种方式,其受到训练数据中是否包含指定级别的严格限制。,而对于最后一个,它甚至不提供操作选项。,因此,需要学习一种映射函数来任意地将一种光(曝光)级别转换为另一种光级别,以便为用户提供调整的灵活性。

Image Denoising Methods

在图像处理、多媒体和计算机视觉领域,图像去噪长期以来一直是一个热门话题,在过去的几十年里提出了许多技术。,经典的方案通过利用自然干净图像的一些特定先验来对问题进行建模/规范化,例如非局部自相似性、分段平滑性、信号(表示)稀疏性等。最流行的方案可以说是 BM3D [22] 和 WNNM [ ,24]。,由于测试中优化过程的高度复杂性以及适当参数的搜索空间大,这些传统方法在实际情况下往往表现出不令人满意的性能。,最近,基于深度学习的降噪器在这项任务上表现出了优越性。,代表性的工作,例如使用堆叠稀疏去噪自动编码器的 SSDA [25]、[26]、通过可训练的非线性反应扩散的 TNRD [27]、具有残差学习和批量归一化的 DnCNN [15],可以节省计算费用,这要归功于仅,测试阶段涉及前馈卷积运算。,然而,这些深度模型仍然存在图像盲去噪的困难。,可能会训练多个不同级别的模型,或者一个模型有大量参数,这在实践中显然不灵活。,通过将反复思考纳入任务中,可以缓解这个问题[28]。,但是,上述方法都没有考虑到光增强图像的不同区域存在不同级别的噪声。,颜色失真也会出现同样的问题。

1.2 Our Contributions

这项研究提出了一种用于实际解决弱光增强问题的深度网络。,这项工作的主要贡献可以概括为以下几个方面。

• 受 Retinex 理论的启发,所提出的网络将图像分解为两个组成部分,即反射率和照明度,从而将原始空间解耦为两个较小的空间。 ,

• 网络使用在不同光线/曝光条件下捕获的配对图像进行训练,而不是使用任何地面实况反射率和照明信息。,

• 我们设计的模型提供了映射功能,可以根据用户的不同需求灵活调整亮度。 ,

• 所提出的网络还包含一个模块,该模块能够有效消除通过照亮黑暗区域而放大的视觉缺陷。 ,

• 进行了大量的实验来证明我们的设计的有效性及其相对于最先进的替代方案的优越性。

2 METHODOLOGY

理想的低光图像增强器应该能够有效地消除隐藏在黑暗中的劣化,并灵活​​地调整光照/曝光条件。,我们建立一个深度网络,表示为KinD,以实现该目标。,如图 2 所示,该网络由两个分支组成,分别用于处理反射率和照明分量。,从功能上看,也可分为图层分解、反射率恢复、光照调节三个模块。,在接下来的小节中,我们将解释有关网络的详细信息。

2.1 Consideration & Motivation

2.1.1 Layer Decomposition

正如第 1.1节中所讨论的。 ,、朴素方法的主要缺点来自于光照的盲目性。,因此,获取光照信息是关键。,如果从输入中很好地提取了照明,则其余部分包含细节和可能的退化,可以在其中执行恢复(或退化消除)。,在 Retinex 理论中,图像 I 可以被视为两个分量的组合,即反射率 R 和照度 L,其形式为 I = R ◦ L,其中 ◦ 表示元素级乘积。,此外,以 Retinex 方式分解图像因此将退化的低光图像映射到所需图像的空间解耦为两个更小的子空间,期望更好、更容易地正则化/学习。,此外,照明图是灵活调整光照/曝光条件的核心。,综上所述,基于Retinex的层分解对于目标任务来说是合适且必要的。

2.1.2 Data Usage & Priors

对于光照条件,没有明确定义的地面实况。,此外,没有/很少有真实图像的真实反射率和照明图可用。,层分解问题本质上是不确定的,因此额外的先验/正则化器很重要。,假设图像是无退化的,某个场景的不同镜头应该具有相同的反射率。,虽然照明图虽然可能变化很大,但结构简单且相互一致。,在实际情况中,低光图像中体现的退化通常比明亮图像中的退化更严重,这将被转移到反射率分量中。,这启发我们,亮光下图像的反射率可以作为退化的低光图像的反射率来学习修复者。,有人可能会问,为什么不使用合成数据呢?,因为它很难合成。,退化不是以简单的形式出现,并且随着不同的传感器而变化。,请注意,反射率(明确定义)的使用完全不同于使用(相对)亮光下的图像作为低光图像的参考。

2.1.3 Illumination Guided Reflectance Restoration

反射率恢复无法在整个图像上进行统一处理,而照明图可以作为一个很好的指导。有人可能会想,如果直接从输入I中去掉E会怎么样?一方面,不平衡问题仍然存在。从另一个角度来看,内在细节与噪音的混杂程度是不同的。另一方面,与反射率不同,我们不再有以这种方式去除退化的适当参考,因为 L 是变化的。类似的分析适用于其他类型的退化,例如颜色失真。

2.1.4 Arbitrary Illumination Manipulation

不同的人/应用最喜欢的照明强度可能非常不同。,因此,实际的系统需要提供用于任意照明操作的接口。,在文献中,增强光照条件的三种主要方法是融合、光照水平指定和伽玛校正。,基于融合的方法由于融合模式固定,缺乏光调节的功能。,如果采用第二种选择,训练数据集必须包含具有目标级别的图像,限制了其灵活性。,对于伽玛校正来说,虽然可以通过设置不同的伽玛值来达到目的,但它可能无法反映不同光线(曝光)级别之间的关系。,本文主张从真实数据中学习灵活的映射函数,该函数接受用户指定任意的光照/曝光级别。

2.2 KinD Network

受到思考和动机的启发,我们构建了一个深度神经网络,记为KinD,用于点燃黑暗。,下面,我们从功能角度详细描述这三个子网。

2.2.1 Layer Decomposition Net

层分解网络包含两个分支,分别对应于反射率和照度。,反射分支采用典型的 5 层 UNet [29],后面是卷积(conv)层和 Sigmoid 层。,照明分支由两个 conv+ReLU 层和来自反射分支的串联特征图上的 conv 层组成(可能从照明中排除纹理),最后是 Sigmoid 层。,表1提供了详细的层分解网络配置。

2.2.2 Reflectance Restoration Net

如图 3 和图 5 所示,低光图像的反射率图比亮光图像的反射率图更容易受到降级的干扰。,使用更清晰的反射率作为杂乱反射率的参考(非正式的基本事实)是我们的原则。,为了寻求恢复函数,目标变得简单如下:

其中SSIM(·,·)是结构相似性度量,Rˆ对应于恢复的反射率。,第三项集中于纹理方面的接近度。,该子网与层分解子网中的反射分支类似,但更深。,原理图配置如图 2 所示,详细信息参见附录。,我们记得,衰减在反射率中分布复杂,这在很大程度上取决于照明分布。,因此,我们将照明信息与退化的反射率一起带入恢复网络。,该操作的有效性可以在图5中观察到。在具有不同退化(光)级别的两个反射率图中,BM3D的结果可以相当地去除噪声(不考虑本质上的颜色失真)。,模糊效果几乎无处不在。,在我们的结果中,原本明亮且几乎没有污染的窗户区域的纹理(例如灰尘/水性污渍)保持清晰锐利,而黑暗区域的退化则通过细节(例如上面的字符)得到了很大程度的消除。,瓶子)维护得很好。,此外,我们的方法也解决了颜色失真问题。,表 2 提供了详细的反射恢复网络配置。

2.2.3 Illumination Adjustment Net

不失一般性,我们考虑两种调整,包括一种调暗和一种调亮。,图6(a)描绘了光源照明,(b)和(d)是通过伽马校正调整的结果,而(c)和(e)是我们的结果。,为了更清楚地显示差异,我们在 x = 100、200、400 处绘制一维强度曲线。对于光照情况,我们学习的方式在相对明亮的区域上强度比伽马校正减少更多,而在,黑暗区域。,对于点亮的情况,出现相反的趋势。,换句话说,我们的方法在相对黑暗的区域增加较少的光,而在明亮的区域增加更多或大致相同。,学到的方式更符合实际情况。,而且α方式比γ方式更方便用户操作。,例如,将 α 设置为 2 意味着将灯光调亮 2 倍。,详细的光照调节网络配置如表3所示。

3 EXPERIMENTAL VALIDATION

3.1 Implementation Details

我们使用 LOL 数据集作为训练数据集,其中包括 500 个低/正常光图像对。,在训练中,我们仅使用 450 个图像对,没有使用合成图像。,对于层分解网络,批量大小设置为 10,补丁大小设置为 48x48。,而对于反射率恢复网络和照明调整网络,批量大小设置为4,补丁大小设置为384x384。,我们使用随机梯度下降(SGD)技术进行优化。,整个网络使用 Tensorflow 框架在 Nvidia GTX 2080Ti GPU 和 Intel Core i7-8700 3.20GHz CPU 上进行训练。

3.2 Performance Evaluation

我们在广泛采用的数据集上评估我们的方法,包括 LOL [21]、LIME [11]、NPE [9] 和 MEF [30]。,采用四个指标进行定量比较,即 PSNR、SSIM、LOE [9] 和 NIQE [31]。 ,PSNR 和 SSIM 的值越高表示质量越好,而 LOE 和 NIQE 的值越低越好。 ,BIMEF [32]、SRIE [12]、CRM [33]、Dong [34]、LIME [11]、MF [35]、RRM [13]、Retinex-Net [21] 的最先进方法,]、GLAD [36]、MSR [8] 和 NPE [9] 作为竞争对手参与其中。

4 CONCLUSION

在这项工作中,我们提出了一种名为 KinD 的深度网络,用于低光增强。,受 Retinex 理论的启发,所提出的网络将图像分解为反射层和照明层。,因此,分解将原始空间解耦为两个较小的子空间。,由于地面真实反射率和照明信息很短,因此可以使用在不同光线/曝光条件下捕获的成对图像来训练网络。,为了消除之前隐藏在黑暗中的退化,KinD 构建了一个恢复模块。 ,KinD中还学习了映射函数,比传统的gamma校正更贴合实际情况,灵活调节亮度。,大量的实验证明了我们的设计相对于最先进的替代方案具有明显的优势。,在当前版本中,KinD 在 Nvidia 2080Ti GPU 上处理 VGA 分辨率的图像所需时间不到 50 毫秒。,通过应用 MobileNet 或量化等技术,我们的 KindD 可以进一步加速。

代码解释

DecomNet_simple

def DecomNet_simple(input):
    with tf.variable_scope('DecomNet', reuse=tf.AUTO_REUSE):
        conv1=slim.conv2d(input,32,[3,3], rate=1, activation_fn=lrelu,scope='g_conv1_1')
        pool1=slim.max_pool2d(conv1, [2, 2], stride = 2, padding='SAME' )
        conv2=slim.conv2d(pool1,64,[3,3], rate=1, activation_fn=lrelu,scope='g_conv2_1')
        pool2=slim.max_pool2d(conv2, [2, 2], stride = 2, padding='SAME' )
        conv3=slim.conv2d(pool2,128,[3,3], rate=1, activation_fn=lrelu,scope='g_conv3_1')
        up8 =  upsample_and_concat( conv3, conv2, 64, 128 , 'g_up_1')
        conv8=slim.conv2d(up8,  64,[3,3], rate=1, activation_fn=lrelu,scope='g_conv8_1')
        up9 =  upsample_and_concat( conv8, conv1, 32, 64 , 'g_up_2')
        conv9=slim.conv2d(up9,  32,[3,3], rate=1, activation_fn=lrelu,scope='g_conv9_1')
        # Here, we use 1*1 kernel to replace the 3*3 ones in the paper to get better results.
        conv10=slim.conv2d(conv9,3,[1,1], rate=1, activation_fn=None, scope='g_conv10')
        R_out = tf.sigmoid(conv10)

        l_conv2=slim.conv2d(conv1,32,[3,3], rate=1, activation_fn=lrelu,scope='l_conv1_2')
        l_conv3=tf.concat([l_conv2, conv9],3)
        # Here, we use 1*1 kernel to replace the 3*3 ones in the paper to get better results.
        l_conv4=slim.conv2d(l_conv3,1,[1,1], rate=1, activation_fn=None,scope='l_conv1_4')
        L_out = tf.sigmoid(l_conv4)

    return R_out, L_out

R是UNet类型,输出三通道,反射率,L是输出单通道,光照估计。

Restoration_net

def Restoration_net(input_r, input_i):
    with tf.variable_scope('Restoration_net', reuse=tf.AUTO_REUSE):
        input_all = tf.concat([input_r,input_i], 3)
        
        conv1=slim.conv2d(input_all,32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv1_1')
        conv1=slim.conv2d(conv1,32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv1_2')
        pool1=slim.max_pool2d(conv1, [2, 2], padding='SAME' )

        conv2=slim.conv2d(pool1,64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv2_1')
        conv2=slim.conv2d(conv2,64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv2_2')
        pool2=slim.max_pool2d(conv2, [2, 2], padding='SAME' )

        conv3=slim.conv2d(pool2,128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv3_1')
        conv3=slim.conv2d(conv3,128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv3_2')
        pool3=slim.max_pool2d(conv3, [2, 2], padding='SAME' )

        conv4=slim.conv2d(pool3,256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv4_1')
        conv4=slim.conv2d(conv4,256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv4_2')
        pool4=slim.max_pool2d(conv4, [2, 2], padding='SAME' )

        conv5=slim.conv2d(pool4,512,[3,3], rate=1, activation_fn=lrelu,scope='de_conv5_1')
        conv5=slim.conv2d(conv5,512,[3,3], rate=1, activation_fn=lrelu,scope='de_conv5_2')

        up6 =  upsample_and_concat( conv5, conv4, 256, 512, 'up_6')

        conv6=slim.conv2d(up6,  256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv6_1')
        conv6=slim.conv2d(conv6,256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv6_2')

        up7 =  upsample_and_concat( conv6, conv3, 128, 256, 'up_7'  )
        conv7=slim.conv2d(up7,  128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv7_1')
        conv7=slim.conv2d(conv7,128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv7_2')

        up8 =  upsample_and_concat( conv7, conv2, 64, 128, 'up_8' )
        conv8=slim.conv2d(up8,  64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv8_1')
        conv8=slim.conv2d(conv8,64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv8_2')

        up9 =  upsample_and_concat( conv8, conv1, 32, 64, 'up_9' )
        conv9=slim.conv2d(up9,  32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv9_1')
        conv9=slim.conv2d(conv9,32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv9_2')

        conv10=slim.conv2d(conv9,3,[3,3], rate=1, activation_fn=None, scope='de_conv10')
    
        out = tf.sigmoid(conv10)
        return out

光照和反射作为输入,传入恢复网络,输出三通道

Illumination_adjust_net

def Illumination_adjust_net(input_i, input_ratio):
    with tf.variable_scope('Illumination_adjust_net', reuse=tf.AUTO_REUSE):
        input_all = tf.concat([input_i, input_ratio], 3)
        
        conv1=slim.conv2d(input_all,32,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_1')
        conv2=slim.conv2d(conv1,32,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_2')
        conv3=slim.conv2d(conv2,32,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_3')
        conv4=slim.conv2d(conv3,1,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_4')

        L_enhance = tf.sigmoid(conv4)

输入是光照和比例值合并