
暗光环境下的图像不管是在做手机摄影、安防监控还是自动驾驶感知都是绕不过去的一道坎。白天随便一拍效果都不错一到晚上要么黑乎乎一片要么噪点像雪花一样铺满屏幕。我在实际项目里处理这类问题时早期用过各种直方图均衡、伽马校正的土办法效果只能说是亮了但没法看。后来转向深度学习这一块最先啃的就是两篇非常经典的工作——一篇是从RAW数据端到端重建的《Learning to See in the Dark》另一篇是把传统Retinex理论搬进深度网络的《Deep Retinex Decomposition for Low-Light Enhancement》。这两篇可以说是低光增强领域的标准动作一个代表完全数据驱动、从传感器源头直接处理一个代表物理模型约束下的可解释增强。这篇文章我会把两套技术路线的核心原理、关键设计、应用边界和我在复现过程中踩过的坑讲透适合正在做图像增强方向、或者打算把低光增强落地到实际产品里的同学阅读。1. 低光增强为什么这么难先看清问题的四个层面1.1 暗光图像的信息损失不只是暗很多人以为低光增强就是把像素值乘上一个系数让它变亮就完事了。真正在暗光下拍过照、处理过真实数据的人都知道问题远远不止亮度不够这么简单。我把它拆成四个层面第一层是亮度动态范围的坍缩。暗光场景下传感器接收到的光子数极少大部分像素的响应值集中在ADC量程的低端直方图呈现一个紧贴左侧的尖峰。简单的线性增益虽然能把峰拉出来但同时会把原本有层次的暗部细节挤成一块块大色斑这就是动态范围塌陷。第二层是噪声的放大效应。暗光下信号和噪声混合在一起而且这两者都小一旦做线性放大噪点的增幅其实比信号更激进。这也是为什么几乎任何低光增强管线后面都要跟一个专门去噪模块的原因——增强和去噪在数学上是一对互相拉扯的对手先增后去还是先去后增各有取舍。第三层是色彩失真。暗光环境的色温变化大白平衡算法在低信噪比下很容易失效导致增强出来的图像偏色、色偏不稳定。即便同一个场景在不同帧之间颜色也可能产生明显漂移。第四层是更底层的传感器信息损耗这一点尤其关键暗光下sRGB域图像里很多像素已经是被ISP处理过的死数据——去马赛克、白平衡、色彩校正每一步都可能放大噪声或抹掉微弱信号。真正可靠的信息只在RAW域里还保留着。1.2 三条技术路线从传统方法到深度模型搞清楚问题本质之后再看解决手段就清楚多了。低光增强大致有三条路线我按使用顺序说传统图像处理路线以直方图均衡化、伽马校正、对比度拉伸为代表。优点是快、无训练成本缺点是纯全局操作对噪声毫无办法暗部细节拉出来了噪点也随之放大实际项目里通常只敢小幅使用。传统物理模型路线是以Retinex理论为核心的一系列方法。旧式的单尺度/多尺度Retinex、带色彩恢复的变体通过估计照度分量做增强。这类方法的问题是照度估计基本靠高斯滤波、双边滤波这类手工先验遇到夜景霓虹灯、灯光边界就很容易出现光晕和伪影。深度学习的路线大致又可以分成两个流派完全端到端监督学习和物理模型驱动的深度分解。这两条正是本篇核心的两篇论文分别代表的路线。前者笃信数据和网络容量可以学到暗光到亮光的复杂映射后者认为引入反射率-照度的物理先验可以让网络学习得更稳、更可控、对数据量的要求更低。理解了这两条路线的对立与互补也就能看懂低光增强领域后来五六年的发展脉络。2. 重新曝一次光《Learning to See in the Dark》的RAW域端到端逻辑2.1 为什么要把操作对象放在RAW而不是sRGB《Learning to See in the Dark》这篇文章最核心的观点只有一个如果要让网络学习暗光到亮光的映射应该喂它RAW数据而不是sRGB数据。这个说法在当年有不少人质疑毕竟常规图像算法都是在最终的可视图像上操作。但仔细想一下就明白了暗光场景里sRGB域上的很多信息在ISP处理的早期阶段就被永久丢掉了。以最典型的拜耳阵列为例传感器每个像素只采集红绿蓝中的一种颜色sRGB输出需要经过去马赛克插值这一插值过程本身就引入了空间平滑之后还有白平衡的通道增益、色彩矩阵变换、伽马压缩每一步都是非线性且不可逆的。暗光数据在这些环节中被反复拉伸和变换噪声结构被彻底打乱微量信号也被掩盖。相反RAW数据是传感器的原话光子响应的线性关系、噪声的泊松分布特性都还保留着网络可以直接从最真实的物理起点出发学习。换句话说在RAW域做增强相当于让网络替你做一次更聪明的ISP而不是在已经牺牲过的画面上做修补。这个观点对后续工作的影响非常大。后面很多商业方案在暗光成像上都回归了RAW域或RAW域优先的思路手机夜景模式里的多帧融合其实也是这个逻辑的工程化变体。2.2 数据配对的构建策略与三大关键设定有了正确的问题域还要有足够的训练数据。这篇论文在数据准备上做了两件关键的事。第一件是构建了严格配对的短曝光和长曝光图像对。拍摄方法是在三脚架上先拍一张低光短曝光然后保持场景不变再拍一张长曝光作为地面真实。整个数据集包含很多真实室内室外夜间场景短曝光对应的照度可能在0.1到5勒克斯之间非常贴近真实的夜景环境。因为两张图来自同一传感器同一场景网络学到的映射是像素级的而且不存在人工合成数据的域差异。第二件是数据管线里对RAW数据的几个关键预处理设定这三处如果处理不对整个复现效果都会大受影响拜耳阵列的格式选择。网络输入用的是原始的RGGB拜耳四通道而不是先插值成RGB图。这意味着要把RAW按照拜耳排列拆分成R、G、G、B四个通道保持空间分辨率不变输入通道数为4。黑电平Black Level减去。很多公开RAW数据集的标称值其实都含有一个暗电流偏置如果不先减去黑电平网络的回归目标就多了一个常数偏移尤其在暗部区域会造成额外的误差。这个常数通常就是在完全遮光条件下采到的传感器响应值。归一化与缩放的甜蜜点。输入短曝光RAW的最大值远小于长曝光RAW训练时需要对两个目标分别做归一化不能简单除以255或65535。论文测试时会把短曝光RAW放大一个倍数再喂给网络这个倍数的选择对输出亮度的影响很大太大会产生过曝太小则增强不足。2.3 网络结构与损失函数的搭配逻辑网络本身反而不是最花哨的部分是一个相对规整的全卷积网络在紧凑的卷积-激活-下采样重复加上跨尺度连接的UNet式结构上做了若干改进。有意思的地方在于训练时网络输入的是4通道RAW输出的是2通道或者最终目标设计上刻意让中间特征在更窄的通道数下保持空间细节以减少显存占用并提升推理速度。损失函数选择了SSIM和L1的组合。L1提供像素级的绝对回归约束保证输出亮度与长曝光目标的一致性SSIM则负责结构感知它能惩罚亮度和对比度上的局部偏差使得输出在边缘和纹理处显得像真的照片。两者在实验上是互补的单独用L1会使结果偏模糊单独用SSIM则可能产生不自然的局部过曝。在我自己的复现实验里SSIM权重取0.8到1.0之间比较合适太高会让画面出现类似过度流畅的塑料感。2.4 复现时最容易翻车的几个细节这部分是实操中的经验光看论文很容易忽略。首先是GPU显存问题。RAW放大的分辨率加4通道输入训练的显存消耗比普通UNet大不少我在单卡上经常要把batch size压到4以下然后靠梯度累积来模拟更大的batch。如果不想用梯度累积也可以考虑把输入分辨率先裁成256×256训练推理时再切块叠加但切块会带来拼接缝需要在重叠区域做羽化融合。其次是训练时的数据增强。暗光增强很容易出现过拟合因为不同相机的传感器响应、拜耳排列和黑电平都不一致。我复现时加了随机旋转90度、随机水平和垂直翻转、随机裁剪但要注意不能加随机颜色抖动——这会破坏RAW域原有的物理一致性让网络学出错误的颜色映射。最后是关于sRGB域版本的一个认知误区。论文也做了输入sRGB短曝光图像、输出sRGB长曝光图像的对比实验效果显著差于RAW域输入。有些读者把这个结论理解成sRGB不能做端到端增强这其实是一种误读。更准确的说法是在已经定型的ISP管线之后做增强信息损失发生在前面网络无论多强大都无法凭空恢复但如果你的数据本身就是合成的sRGB图像或者ISP参数可参与联合优化sRGB端到端依然是可行选项。3. 老理论配上新引擎《Deep Retinex Decomposition》的分解-增强结构3.1 Retinex理论的通俗理解把一张图拆成本该如此和环境光照Retinex理论诞生得很早核心思想其实不难人眼感知到的物体颜色是反射属性而相机拍到的颜色是反射属性和光照的乘积。一张暗光图像可以被分解成反射图R和照度图L其中R代表场景各物体在标准光照下本来的反射率也就是物体本身的颜色和纹理L代表当前环境照射在场景每个位置上的强度分布也就是光照环境的样子。两者的关系是逐像素相乘I R ⊙ L这个分解最大的价值在于它把低光增强问题拆成了两个子问题一是如何从拍坏的暗光图像里估计出干净的R二是如何把表示暗环境的L调整成正常曝光的L然后把R和L相乘得到增强结果。前者本质上是去噪、去雾和恢复纹理后者本质上是照度估计和亮度映射。这种解耦让每一步都可以用更合适的工具来优化也让最终效果的可解释性大大增强。传统Retinex方法的瓶颈在于估计R和L时靠的是手工滤波器比如高斯卷积、引导滤波它们表达不了复杂场景中的全局光照和局部阴影交互。而深度网络天然擅长从数据中学习这种复杂的先验于是把Retinex的分解逻辑搬进网络就成了非常自然的一步。3.2 分解网络与三支损失的协同约束《Deep Retinex Decomposition for Low-Light Enhancement》提出的网络本质上是一个多任务学习框架核心是分解部分。它接收一张低光图像输出对应尺度的反射图R和照度图L。为了让这两张分解出来的图像话光靠重建损失是不够的还需要额外的物理约束。第一个约束是重建一致性。既然我们假设I R ⊙ L那么把分解出的R和L相乘应该能够还原输入图像。这个损失保证了分解结果不会随意偏离原始数据是整个网络稳定的基石。第二个约束是反射图一致性。这里是非常聪明的设计如果能拿到同一场景的低光-正常光配对数据那么从这两张图分解出的R理论上应该完全一致因为反射率由物体材质决定不会因为光照改变而改变。所以训练时把低光图和正常光图分别输入分解网络得到两组R和L然后强制两组R彼此一致。正是这个约束教会模型去区分哪些是物体本身的纹理和哪些是光照带来的效果。第三个约束是照度图的平滑性。真实的光照在大范围内通常是渐变平滑的但在边界处会因几何遮挡而出现锐利变化。如果只使用简单的一阶或二阶平滑损失会导致光照边缘被过度抹平形成光晕。论文中针对这个问题的做法是引入结构感知的平滑权重用反射图或输入灰度图的梯度来给平滑项加权在纹理丰富区域允许照度图有变化在平坦区域则严格约束平滑。这样既避免了光晕又保留了光照的真实边界。有了分解之后增强阶段就变得非常直观把低光的照度图做亮度映射对反射图做噪声抑制再把两者重新融合。整个流程完全绕开了传统方法里先整体变亮再去噪的不良路径每一步都在处理预期明确的目标。3.3 与传统Retinex方法的本质差异很多人第一次看这篇论文会觉得不就是把老方法换个网络实现吗其实不然。传统Retinex和深度Retinex有一个本质性的区别先验的来源不同。传统方法里照度图L是通过对原图做高斯卷积、双边滤波这类固定先验来估计的R则是原图逐元素除以估计出的L几乎不需要学习什么。这种方式的假设是光照的低频性和平滑性在大多数简单场景下成立但在逆光、强阴影、多光源场景中会系统性失败。深度Retinex则没有预先假设具体的平滑核是什么它通过学习大量数据隐式地掌握了一种更复杂的光照先验知道哪些区域的光照可以突变、哪些区域必须平滑也知道反射图在什么情况下应该保留何种纹理。另外还有个容易被忽视的区别——传统方法只能在一张图上做分解深度Retinex可以利用配对数据训练出的跨图一致性也就是反射一致性损失这使得估计出的R更接近真实的物理反射率而不是仅仅看起来合理的分解结果。3.4 分解思路在工程落地中的选型建议我后续在多个实际项目里尝试过把Retinex分解引入管线。有一个比较通用的经验是如果手里有稳定的配对数据可以训练完整的分解-增强框架如果没有配对数据也可以用这项工作的另一个延伸思路——单图分解加无监督一致性约束但这通常需要额外的噪声模型和更重的调参工作。还有一个选型上的建议如果在移动端部署分解网络通常不会作为主增强网络使用而是作为预处理或后处理的辅助模块。因为完整框架里包含分解网络、亮度映射、去噪模块串行推理的耗时偏大。更常见的落地方式是用一个轻量UNet对图像做分解再用查表方式来做照度映射把去噪并入统计滤波器这样在端侧可以把单帧处理时间压缩到几十毫秒级别。4. 两种技术路线的正面较量与实际选型4.1 端到端重建和Retinex分解的硬核对比我把两个方案放在同一张表格里做对比这样选型时一眼能看清差别。维度Learning to See in the Dark端到端RAW重建Deep Retinex Decomposition物理模型驱动输入域RAW域需要传感器原始数据sRGB域或RAW域均可对输入类型宽容数据需求严格配对的短曝光-长曝光图像对构建成本高配对数据可以训练但单图分解加一致性约束也能工作可控性黑盒映射中间过程不可干预分解出R和L可分别调节亮度、噪点和色彩可解释性较弱难以回答为什么这个区域这么亮较强增强结果可以归因到照度调节和反射恢复对ISP的依赖完全绕过ISP需要在RAW域自建处理管线通常依赖已有sRGB图像可作为ISP之后的后处理部署友好性依赖RAW解码、黑电平、归一化等参数工程复杂相对简单可直接接入现有图像处理流程适用场景暗光摄影、手机夜景、监控RAW增强通用低光图像增强、视频增强、实时轻量化处理从这个表格能看出两者并没有绝对优劣而是在不同工程约束下各有取舍。RAW端到端方法的上限更高因为它从源头处理但门槛也高Retinex分解的方法更灵活、更可控而且可以拆成子模块逐个优化更接近工程里常说的能做迁移、能解释、能调优三个目标。4.2 两套思想能否结合管线、损失、数据三个层面在实际项目中我尝试过把两套思想做结合确实有几种可行且效果不错的组合方式。第一种是管线层面的结合。先用端到端RAW模型把暗光RAW恢复成带噪的增强RAW再在增强RAW上做Retinex分解拆出R和L后进一步做去噪和光照精修。这个思路能同时拿到端到端模型的强重建能力和Retinex分解的可调性。我实测下来在极暗场景下比单独用任何一套效果都稳代价是整体推理时间翻了一倍。第二种是损失层面的结合。在端到端模型的损失函数里不光用L1和SSIM还加入一个预先训练好的Retinex分解模块作为感知损失计算器比较增强结果和长曝光目标各自的R分量这样做可以让网络更关注纹理恢复而不是单纯亮度到位。第三种是数据层面的结合。如果没有大量真实配对数据可以用Retinex分解模型先从单张暗光图里生成一张粗略的伪长曝光图再把它和原图组合成伪配对用来预训练端到端RAW模型等拿到真实配对数据后再微调。这种两阶段策略在实际项目里很常见能显著降低数据标注的成本门槛。4.3 从这两篇论文延伸出来的通用工程心得如果只让我留下一句话那就是低光增强问题没有一个万金油方案选型的本质是在可控性和性能上限之间做权衡。端到端方法的调参路径相对清晰核心在数据和训练细节上推理端固定后效果稳定但出了问题很难定位是哪个环节的锅。Retinex分解方法每个子模块都相对独立哪个环节效果不行就替换哪个环节工程可维护性更好但多模块之间的误差会累积拆得越多管线的整体折耗越大。基于这些经验我的通用建议是第一版产品尽量选Retinex分解路线快速验证等效果瓶颈明确出现在某个模块、且清晰判断出需要更强的信号恢复能力时再引入端到端RAW域网络来做增强或细化。这种先简单后复杂、先可解释后追求上限的路线可以避开很多反复返工的坑。5. 复现两套方案时的通用避坑指南5.1 数据质量配对数据的对齐和标定问题两套方案最终效果的上限都取决于训练数据质量这一点容易被低估。配对数据采集时两个最关键的问题是像素对齐和曝光一致性。长曝光期间场景如果有轻微移动哪怕是风吹树叶的抖动都会让配对图的像素错位导致网络学出重影。我在采集环境里放了三脚架加遥控快门还不够还专门用了一个低速卷帘快门的相机模式来减少卷帘畸变。标定方面需要记录每张RAW的曝光时间、ISO、黑电平、传感器增益等多个元数据。很多开源数据集没有完整提供这些参数使用时不自行补齐训练时黑电平偏差会直接形成系统性色偏放大后非常难排查。5.2 训练稳定性从损失曲线识别假收敛低光增强网络的训练过程有一定迷惑性。L1损失会随着训练逐步下降看起来是收敛了但实际生成的图像可能偏灰、偏糊或存在局部过曝因为L1并不惩罚结构层面的不自然。这时候我会额外观察几个指标一是输出在暗部区域是否有条带二是高光边缘是否存在溢色三是SSIM曲线有没有明显波动。如果SSIM曲线上下振荡通常说明学习率偏大或者损失权重失衡如果SSIM曲线在某个平台期持续不动而L1还在降说明训练进入了一种过度平滑的伪收敛这时要降低L1的权重或提高SSIM权重。一个额外小技巧在验证集上配合一两个高难度暗光样本的横评比光看曲线更直观。5.3 推理阶段不同相机间的泛化策略训练数据如果来自单一相机传感器模型迁移到另一台相机时效果往往会断崖式下降因为不同传感器的拜耳排列、色彩响应、噪声分布都不同。应对方案有两层轻量方案是在推理前利用目标相机的标定参数黑电平、白平衡把RAW归一化到训练时的标准空间进阶方案是用少量目标相机数据做微调哪怕只有几百张无标注真实暗光图配合伪配对策略也能显著改善泛化。5.4 性能优化从方案选型到端侧部署的取舍当需要把模型部署到移动端或嵌入式设备时有几个经验值得提前考虑。输入分辨率不要贪大暗光增强通常不需要把全图分辨率喂进去可以先在1/2或1/4尺度上获取亮度分布再在原分辨率上做细节恢复。通道数能省则省4通道RAW输入比3通道sRGB输入在端侧要多吃三分之一的第一层计算量如果传感器没有提供RAW访问接口直接用sRGB输入也够用。如果硬算力实在不够可以进一步把Retinex分解里的照度映射换成直方图或查找表实现把去噪模块换成轻量时域滤波这样在单核CPU上也能跑通分解-调亮-去噪全流程代价是比深度模块少一些极端场景的鲁棒性。6. 写在最后我对这两个经典方案的落地体会如果把低光增强比作一间黑暗的屋子那么《Learning to See in the Dark》做的是把整扇门拆掉、直接从窗户外面重新设计采光完全推翻ISP的既定流程而《Deep Retinex Decomposition》更像是在屋里点起一盏一盏分辨墙壁原本的颜色和灯光带来的效果的灯每一步都有据可查、可单独调整。两者没有谁取代谁而是分别回答了工程实践中的两个核心问题我们能不能追求更高的视觉上限我们能不能把增强过程做得更可控、更可维护我自己的选择习惯是在没有明确算力限制、且能拿到传感器RAW数据的产品里优先用端到端RAW网络去冲击画质上限在需要快速集成、跨平台上线、且希望效果能被简单解释的产品里Retinex分解路线始终是稳妥的起点。两套方案的损失函数也可以互相借鉴甚至把两者做成级联或联合训练的形态都是低光增强方向上非常值得继续探索的空间。如果你正准备入坑低光增强我建议你先亲手复现这两篇论文把暗光图像从RAW到sRGB的完整链路走一遍很多看似玄学的问题在理解了两套核心逻辑之后都会变成有迹可循的工程细节。