资讯动态

HDRNet原理与复现:低分辨率预测+双边网格实现实时图像增强

发布时间:2026/10/15 11:57:15 来源:尧图企业网站定制
1. 先说清楚HDRNet到底解决什么痛点图像增强这个方向看起来简单不就是调亮度、拉对比度、加饱和吗但真正做起来会发现最麻烦的是“局部”二字。全局提亮暗部起来了亮部却过曝局部压高光亮部保住了暗部又死黑。传统方法里双边滤波和引导滤波能一定程度缓解这个问题但要么速度慢要么参数需要手工调。SIGGRAPH 2017 的这篇 HDRNetDeep Bilateral Learning for Real-Time Image Enhancement之所以常被拿出来反复读就是因为它把“学习式局部增强”做到了实时而且思路极其干净低分辨率网络预测一组局部变换高分辨率图像直接套用。这篇论文我前前后后读了好几遍每次都有新收获尤其是它把双边网格、仿射变换和低分辨率推理三个东西缝在一起的方式非常适合做计算摄影或移动端图像处理的同学精读。在读细节之前需要先搞清楚一个核心矛盾网络想要理解全局内容往往需要看完整张图但最后要输出的增强结果又必须逐像素处理保持边缘细节。如果直接拿全分辨率图做卷积计算量大到没法实时如果单纯压缩分辨率再上采样边就糊了。HDRNet 的思路是把“决策”和“执行”分开。让网络在低分辨率下做全局分析得到每个局部区域应该做什么样的颜色变换然后在高分辨率下用一张全分辨率图去“查询”这些变换把变换应用到每个像素上。听起来像先画地图再按图行军实际操作也确实如此。1.1 传统图像增强方法为什么又慢又容易糊图像增强的传统路线大致分两类。第一类是全局映射比如 Gamma 校正、S 曲线、直方图均衡。这类方法快但它只能用一个曲线套全图没办法处理场景里不同区域需要不同曝光的情况。第二类是局部自适应方法比如双边滤波、局部直方图均衡、基于 Retinex 的方法。这些能保留局部对比度但跑起来很慢而且调参数非常痛苦。双边滤波尤其典型核大小、颜色标准差、空间标准差三个参数互相影响换一张图就要重新调试。另一个问题是传统局部方法很少能直接“学习”目标风格。比如我希望输出图像的阴影区提亮、中间调稍微加饱和、高光压暗这种规则用传统双边滤波根本没法表述就算勉强用全局映射效果也生硬。HDRNet 之前也有基于深度学习的增强方法但大多把问题建模成逐像素回归比如让网络预测一个光照图或者透射图再和原图合成。这类方法有几个通病模型往往只在下采样后的低分辨率特征上输出想要恢复高清边缘还得额外接一个上采样网络或者依赖光流、深度等中间估计计算链路很长。HDRNet 选择了一个完全不同的角度不预测图像本身也不预测逐像素标量而是预测一个局部的线性变换参数让变换发生在“双边网格”这样一个对边缘友好的空间里。1.2 一句话概括 HDRNet 的核心思路HDRNet 的核心可以拆成三步。第一步把输入图缩小到很低的分辨率大概长边 256送进一个全卷积网络网络输出的是若干组仿射变换系数这些系数按双边网格的方式组织。第二步保持全分辨率原图不动用每个像素的坐标和亮度值从双边网格中做三线性插值取出属于这个像素的一组变换系数——这一步叫 slicing。第三步用这组系数对像素做一次 3×3 颜色矩阵加偏移的变换得到最终增强结果。这套设计最漂亮的地方在于全分辨率路径上没有任何可学习参数也没有任何卷积计算只有逐像素的采样和矩阵乘法。也就是说输入图可以任意大HDRNet 在推理时的开销基本与分辨率无关只取决于最终要处理多少像素。而真正需要“智能”的部分全部被压缩到了低分辨率网络上。这个思路后来被很多后续工作借鉴但在 2017 年它确实把“实时”“高分辨率”“学习式增强”三件事同时做到了。2. 网络结构拆解低分辨率预测 仿射变换应用想真正读懂 HDRNet不能只看整体概念必须把三个关键模块拆开低分辨率分支长什么样、双边网格的系数是怎么组织的、slicing 操作到底做了什么。这三个模块任何一个环节理解错了复现的时候都会出问题。2.1 低分辨率分支用整图信息预测局部参数低分辨率分支的输入很简单原图缩放后的低分辨率版本。论文里一般把长边缩放到 256 左右。为什么要用低分辨率因为局部变换参数在空间上是平滑变化的不需要逐像素级别的精度。比如一张 1080p 的图阴影到高光的过渡可能占了上百像素但对应到低分辨率图上可能只有几个像素网络完全有能力在这种尺度下判断每一个区域该做什么样的变换。低分辨率分支的网络结构是典型的全卷积设计。我在复现时候参考论文给出的配置大致是第一层卷积使用 8×8 的大卷积核步长 4输出 16 个通道这样做一方面是快速下采样把 256×256 的输入压到 64×64 左右另一方面大卷积核能提供足够大的感受野让网络一开始就能结合周围上下文。接下来的几层是 3×3 卷积通道数逐渐从 16 增加到 64中间穿插 ReLU最后用一个 1×1 卷积把特征通道调整到目标数量。网络承担的是“全局理解 局部决策”双重任务所以它既需要足够大的感受野也不能丢掉局部细节。8×8 的起步卷积和连续小卷积的组合就是在找这两者之间的平衡。这一层的关键输出不直接是图像而是一个通道数等于“12×网格组数”的特征图。为什么要 12因为每个像素最终要用的变换是一个 3×3 颜色矩阵加一个 3 维偏移矩阵 9 个数加偏移 3 个数正好 12。特征图的空间分辨率大概是输入的 1/16也就是说网格的空间单元比较粗但配合后面的三线性插值视觉上不会出现明显的块状痕迹。2.2 双边网格给每个局部区域一组变换系数双边网格不是 HDRNet 首创它来自更早的双边滤波加速工作。传统双边滤波需要在像素邻域里反复计算权重速度很慢双边网格的做法是把像素按三个坐标映射到一个三维网格里——两个空间坐标代表位置第三个坐标代表亮度或颜色信息。每个网格点存储一个值处理完网格后再用插值把结果映射回像素空间。这样做的好处是亮度差异大的边缘处在网格的不同层里不会相互污染从而保持边缘。HDRNet 把双边网格推广成了“可学习的仿射变换场”。传统双边网格每个位置存的是一个标量HDRNet 每个网格顶点存的是 12 个数。低分辨率网络输出的特征图会被 reshape 成一个多维系数张量其中空间维对应网格的前两个坐标亮度维对应第三个坐标。论文里网格的空间分辨率通常取输入低分辨率图的 1/16 左右亮度维用一个固定值常见的是 8 到 16 等间隔。网格分辨率增大表达更精细但计算更贵亮度维太小暗部到亮部的过渡会断层太大不同亮度层之间的共享信息就少了。这里有个值得琢磨的点为什么要在网格里放仿射变换而不是直接放目标像素值如果直接存放目标颜色网络要记住的东西太多而且对噪声和场景内容高度敏感。仿射变换更抽象它描述的是“输入颜色应该如何被改变”这个规律而不是改变后的具体颜色。局部区域的变换总是比较平滑的——比如阴影区域偏向提亮和增加对比度高光区域偏向压暗——这种规律用少量系数就能表达泛化自然更好。2.3 Slicing 与全分辨率重建保持边缘的关键Slicing 是 HDRNet 里最值得反复品味的操作。全分辨率图像上的每一个像素都有三个坐标它在图像里的横纵坐标以及它的亮度值。用这三个坐标去双边网格里做三线性插值得到一组 12 个系数然后对该像素的 RGB 三通道做仿射变换output M × input_rgb b其中 M 是 3×3 矩阵b 是 3×1 偏移。如果某个像素位于高亮区域它对应的网格层和阴影区域的层不同取到的变换系数也不同。这就形成了一种“亮度自适应”的局部增强。边缘处像素哪怕空间上靠得很近只要亮度差异大就会从不同的网格区域获取系数所以不会出现把亮部信息扩散到暗部的情况。很多人第一次读到这里会困惑为什么切片就能保持边缘而直接在高分辨率上用卷积就不能区别在于卷积是在规则空间邻域内提取信息的边缘两侧像素天然会被混在一起双边网格把亮度作为一个强制分隔维度高亮像素和暗部像素即使在空间上紧邻也会被映射到完全不同的纵向位置。因此 slicing 产生的效果天然带有边缘保持属性不需要网络额外去学边缘。3. 设计巧思为什么这套架构能实时又不失真HDRNet 最打动我的不是它能做局部色调映射而是它把“实时”这个约束直接变成了结构设计的出发点。很多论文是先设计模型再考虑速度HDRNet 是先把速度边界画好再把功能和精度往里面装。这种思考方式对做工程的人来说特别有参考价值。3.1 计算复杂度把重活留给低分辨率拆开算一笔账。假设输入是一张 1920×1080 的图直接在高分辨率上做深度学习增强一次前向推理哪怕只用很少的卷积层FLOPs 都高得吓人。HDRNet 的做法是先把整张图缩到长边 256在这个小图上跑网络。此时参与卷积的像素数大约只有全分辨率的两百分之一。低分辨率网络的输出是一张很小的系数图之后对全分辨率图做切片和仿射变换。仿射变换本身非常便宜每个像素只有几十次乘加运算在 GPU 上可以做到完全并行。具体来说低分辨率网络的主要算力消耗集中在几层卷积上即使通道数不大但因为输入小整体 FLOPs 非常可控。全分辨率路径几乎可以看作是一个查表插值加矩阵乘法的过程。这种“低分辨率算参数、高分辨率套模板”的思路本质上是把昂贵的智能分析放在低成本的抽象空间里完成把廉价但必须的细节恢复交给直接的像素操作。我实际测试这类方案的时候发现时间瓶颈往往不在卷积部分而在 slicing 操作的具体实现。如果 slicing 用 CPU 逐像素循环做速度会腰斩但如果用 GPU 并行或者写成矩阵批量插值整条管线跑得非常轻松。原论文在当年的旗舰显卡上处理 1080p 图像帧率可以做到数百 FPS 量级即使放到移动端也能接近实时。考虑到那是 2017 年的硬件这个数字放在今天更是不在话下。3.2 训练策略低分辨率监督也能撑起全分辨率效果另一个巧妙之处是训练策略。HDRNet 的整个管线是可微的也就是说它可以端到端训练。但论文里选择了一个看起来似乎有点“偷懒”的做法训练时只在低分辨率输出上计算损失。你想网络输出的网格系数最终要作用在全分辨率图像上那损失理应算在全分辨率输出上才对。为什么不这样做因为全分辨率输出做一次 slicing 虽然推理时很便宜但在训练时要存全分辨率图的中间结果显存占用非常大。低分辨率训练的意义在于网络输出的系数网格是低分辨率空间里的表示低分辨率输出图也正是对这个网格的直接可微观察。只要低分辨率输出和真实目标相吻合就能保证网格系数本身是合理的而由于 slicing 是一个局部平滑的插值操作低分辨率下学到的网格系数应用到高分辨率时质量是有保障的。论文里对这一点做了对比实验低分辨率训练和全分辨率训练在最终效果上没有明显差别但训练速度和显存占用完全是两个量级。当然这不代表低分辨率训练完全没有代价。如果目标图像里有非常高频的细节需要恢复低分辨率损失是监督不到这些细节的因为低分辨率图压根就不包含高频信息。不过 HDRNet 的定位是增强而不是超分辨或去模糊增强前后图像在结构上应该保持一致高频纹理基本都是输入保留的所以损失不需要监督网络去生成高频这也就解释了为什么低分辨率训练可行。3.3 局限性与边界没有银弹HDRNet 也不是没有弱点。第一网格空间分辨率只有输入的 1/16 左右这意味着网络能表达的变换在空间上变化比较缓慢。如果一个很小的区域需要和周围完全不同的变换网格很可能表达不出来。第二亮度维度是离散化的如果场景的动态范围特别极端亮的极端亮、暗的极端暗中间落在某个亮度区间的区域难以获得足够细致的区分。第三模型学到的是一组固定的映射规则换一个任务比如从增强改成去雾就得重新训练没有传统滤波器那么通用。更重要的是低分辨率网络会丢失细小的结构信息。想象图片里有一条极细的线比如远处的高压线在低分辨率图上可能只有一两个像素网络对这条线的判断会受周围环境影响没法精确知道它该被如何增强。这个问题在后续很多工作中被讨论但对于大多数照片级别的图像增强需求这个尺度上的损失通常是可接受的。4. 实验与应用局部色调映射、HDR 重建与增强HDRNet 论文里做了好几个实验覆盖的并不是同一个具体功能而是验证“学习式局部仿射变换”这个框架的通用性。把不同任务统一到同一个架构下这是论文最耐人寻味的部分。4.1 局部色调映射和 HDR 重建局部色调映射简单说就是把一张动态范围很宽的 HDR 图像压缩到普通显示器能显示的 LDR 范围同时尽量保留局部细节。传统方法需要估计光照层和反射层或者做梯度域编辑计算量大并且容易产生光晕。HDRNet 把这个问题变成了学习映射规则的问题输入一张 HDR 或模拟 HDR 效果的 LDR 图输出一张色调映射后观感自然的图。网络的低分辨率分支在全局把握亮部和暗部的分布网格系数在亮度维度上分层高亮区域和昏暗区域被分开处理所以压制高光、提亮阴影可以同时进行。HDR 重建是另一个有意思的应用。给定一张或几张曝光不足/过曝的图模型要恢复里面被裁剪的细节。传统方法需要做相机响应曲线估计和曝光融合而 HDRNet 直接从数据里学到了如何把欠曝区域局部提亮并恢复颜色。我在读实验部分时留意到一个细节这类任务的难点不是单纯提亮而是提亮之后不能发灰、不能出现明显的噪声放大。HDRNet 的仿射变换能对颜色通道做交叉调整所以它可以在提亮的同时重新饱和颜色还能在网格亮度层之间用不同的增益控制噪声。这种“针对不同亮度区间做不同处理”的能力正是它相比普通直方图映射的优势。4.2 实时增强与降噪除了 HDR 相关任务论文还展示了它支持任意图像增强风格的模仿。比如从低质量手机照片到专业修图结果的映射模型不关心具体规则是什么只要提供成对样本它就能学会那个风格。这种“风格迁移式的自动增强”在手机摄影里非常常见HDRNet 的优势在于速度够快可以直接内嵌在相机流水线上。降噪任务上HDRNet 的表现也很有意思。传统降噪方法需要估计噪声水平然后做自适应滤波。HDRNet 学到的是对每个亮度层施加不同的降噪力度同时利用仿射变换对颜色做小幅修正。当然它的降噪能力肯定不如专门的去噪网络但胜在能和其他增强任务共同训练让一个模型同时完成“降噪 色调映射 色彩增强”这种多任务整合对于移动端应用来说非常实际。4.3 数字背后的含义论文里报的帧率很亮眼但我不建议大家直接背数字很多数值会随着硬件和输入分辨率变化。更值得关注的是趋势低分辨率网络的计算量几乎是固定的全分辨率路径的开销和像素数线性相关。这意味着在移动端HDRNet 在 720p 或 1080p 下完全有机会跑出实时帧率而在桌面级 GPU 上处理 4K 视频也不至于掉到“离线”的档次。论文的设计目标本来就是“可以塞进相机取景预览”的实时系统而不是离线批处理的工具。从实际工程角度看这个特性极其重要。很多论文模型在服务器上效果惊艳一到手机端就因为内存、耗时、发热等问题被放弃。HDRNet 的低分辨率分支天然把大计算量限制在很小的张量上部署压力小全分辨率路径又不需要浮点精度特别高量化后几乎不损失效果。这些因素让它成为计算摄影领域少数真正“落地”过的模型之一。5. 复现实操关键细节与避坑指南读论文是一回事把这个模型从纸面变成可跑的代码又是另一回事。HDRNet 的架构说起来不复杂实际复现时还是有几个坑值得专门提出来。尤其是双边网格的组织方式和 slicing 的实现稍不注意就会出奇怪的结果。5.1 数据与损失函数的选择复现 HDRNet 最需要先解决的是成对数据。好在图像增强领域不缺成对数据集一般用长短曝光或用户修图前后的照片即可。但数据配准问题很关键如果输入输出图之间存在像素级偏移模型会学到模糊的映射输出观感发软。作为初步验证完全可以先用已有公开的成对数据跑通流程再在自己的业务数据上微调。损失函数方面论文里通常使用颜色空间上的 L1 或 L2 损失。我在复现时发现直接用 RGB 空间的 L2 损失容易让结果偏灰原因是 L2 鼓励像素值取中间值。改用 L1 或者叠加一个简单的感知损失会好很多。另外很重要的一点是如果任务涉及较大的亮度变化最好在损失里对暗部给予更高权重否则网络会倾向于优先满足亮部。之前在训练一个夜间增强模型时损失权重没有调结果暗部提亮始终不够后来在暗部像素的损失上乘了 2 到 3 的权重效果立刻改善。注意训练时用低分辨率输出计算损失不代表最终评估也在低分辨率上。每次迭代的时候仍然需要用全分辨率输入做一次推理来观察视觉效果否则很容易出现“低分辨率损失很低但全分辨率增强后出现网格块状条纹”的情况。5.2 双边网格 slicing 的实现注意点Slicing 的核心是三线性插值。最直接的做法是为每个像素计算它在网格中的浮点坐标然后找周围的 8 个网格顶点按距离权重把系数加权出来。如果输入分辨率是 H×W输出网格空间分辨率约是 H/16×W/16每个像素落在哪个格子是可以预先算好的。这个过程可以完全向量化不要写成循环。实现时最容易出错的地方是亮度维度的归一化。双边网格的第三个坐标是亮度它必须和训练时的亮度范围保持一致。如果训练时把像素值归一化到 0 到 1亮度维采样范围就是 0 到 1推理时如果用了不同的归一化方式插值出来的系数会整体偏移颜色就会出现奇怪的偏色。这个问题我踩过不止一次最后给出的经验是把亮度归一化函数写成一个独立模块训练和推理都必须走同一个函数。另一个注意点是低分辨率分支输出的通道数要能被 12 整除。假设输出通道数是 48那么可以 reshape 为 4 组网格系数。有些复现版本会把 4 组系数在空间上堆叠在一起这时 slicing 的索引要按组内偏移计算而不是当作 48 维向量直接插值。如果组数划分不对结果会完全错误。建议在实现 slicing 之前先用一个小测试在网格第 3 组、第 5 个通道上设固定值看输出图上对应区域是否按预期出现颜色变化。5.3 网格分辨率与训练参数的搭配网格空间分辨率取输入的 1/16 是一个不错的起点。分辨率再低一些比如 1/32能明显提速但局部过渡会变粗再高一些比如 1/8局部细节更好但网络输出的空间尺寸变大计算量和内存也跟着涨。亮度维度的选择也很关键默认 16 层即可当处理动态范围很大的场景时我会适当增加到 24 层同时把亮度采样函数从线性改为对数域这样高光区域的层次会更丰富。训练时 batch size 可以尽量开大因为低分辨率损失计算本身很省显存。我习惯用 batch size 32 起步配合较小的学习率。HDRNet 对初始化比较敏感如果一开始 1×1 卷积将所有系数初始化为单位矩阵对应的数值训练前期会稳定很多。具体来说1×1 卷积的权重可以初始化成使对角线为 1、其余为 0 的形状这样初始状态下网络相当于一个恒等映射然后再慢慢学习真正的变换。直接随机初始化会让训练初期出现不小的色彩漂移。5.4 部署到实时管线时的优化技巧推理时最直接的优化是先把全分辨率路径做融合。每个像素的仿射变换只有 12 个参数可以把它折叠成一个 3×4 矩阵。如果相邻像素恰好落在同一个网格单元我们完全可以先按网格单元把系数算好再一次性将整个块应用矩阵变换。这样能减少很多冗余插值计算。其次深度学习的框架在低分辨率卷积上通常能自动加速但 slicing 操作不一定有现成的高效算子。我见过不少复现版本直接用通用的 gather 或 grid_sample 函数速度也不错如果追求极限性能可以为 slicing 专门写一个并行 kernel把三线性插值和矩阵乘法合并成一个 pass。实测下来这一步对高分辨率输入影响最大尤其是 4K 图像能够把帧率提升一到两倍。移动端部署时我会把低分辨率网络量化成半精度甚至混合精度。网格系数对量化的敏感度比普通任务低因为插值操作本身就是一种平滑小的权重误差会被平均掉。但要注意量化和网格亮度维采样精度不要同时降低否则暗部会出现色带。我的经验是先在模拟量化环境下测试一遍再决定哪些层需要保留浮点精度。5.5 常见问题速查现象可能原因解决建议输出出现规则块状条纹网格空间分辨率太低亮度维归一化不一致提高空间网格分辨率统一训练/推理的亮度归一化函数暗部发灰、对比度不足损失函数只关注整体 MSE改用 L1 或感知损失对暗部像素加大权重色彩严重偏移系数通道 reshape 顺序错误或初始化不是单位矩阵检查 slicing 索引映射用单位矩阵初始化 1×1 卷积训练不收敛学习率过大或网络输出范围没有约束调低学习率对系数输出层加 tanh 限幅观察网格均值推理速度慢slicing 用循环实现或者没有合并矩阵乘法向量化插值把仿射变换折叠成 3×4 矩阵批量应用低分辨率表现好高分辨率发虚全分辨率路径存在配准偏移或切片精度不足确认输入图像对齐检查坐标计算是否基于像素中心6. 一点个人体会这篇论文我每次读都会带出一些新想法。HDRNet 真正厉害的地方不在于某个卷积层设计得多么精巧而在于它把“高分辨率图像保持细节”和“低分辨率图像理解全局”这两个互相矛盾的需求用一张双边网格缝合在了一起。低分辨率分支像是一个冷静的规划者它不必看到每根发丝但它知道阴影从哪里开始、高光到哪里结束全分辨率 slicing 又像是一个高效的执行者不消耗太多算力就把规划变成了现实。这种分工思想后来在很多视频增强、图像恢复模型里都能看到影子。如果你正要开始复现这篇文章我建议不要急着堆代码先手动画一下整个张量在每一步的形状变化把“低分辨率特征图如何变成双边网格、像素坐标如何查表、查到的系数怎么作用在颜色上”这三步彻底想清楚。想清楚这三步HDRNet 的代码无论换什么框架都能写出来而且能写出自己的优化版本。图像增强这个领域更新很快但 HDRNet 作为“实时学习式增强”的代表作确实值得反复读上几遍。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑