动态范围的定义在上一篇文章中已经介绍过了。8 位图像的动态范围约 48dB,普通显示器的范围也大致在这一量级。但是真实物理场景的动态范围往往超过 100dB——直视太阳和阴影处的亮度差可达六个数量级以上。用单次曝光去拍摄这样的场景,要么亮部过曝成一片白,要么暗部欠曝成一片黑,无法同时记录两端的信息。
高动态范围成像(High Dynamic Range Imaging,HDRI)就是为这个问题设计的。它的思路很直接:用多张不同曝光量的照片分别记录场景的不同亮度区间,然后合成一张保留全范围信息的辐照度图,最后通过 Tone Mapping 压缩到显示器可呈现的范围。
多曝光图像序列
对同一个静态场景,固定光圈、改变快门速度(或 ND 滤镜),拍摄一组曝光量等差或等比变化的照片:
- 短曝光:保留高亮区域的细节,暗部几乎全黑。
- 长曝光:保留暗部细节,亮部完全过曝。
- 中间曝光:覆盖常规亮度区间。
理想情况下,每张照片中都有一个”有效曝光区间”——像素既不饱和也不欠曝。HDR 合成的目标就是从每张照片中挑出它的有效部分,拼成一张完整的辐照度图。
相机响应函数(CRF)
上述过程无法直接操作,因为相机输出像素值与入射辐照度之间不是线性关系。传感器的光响应是线性的(光子数 电压),但经过伽马校正、白平衡、非线性去噪等一系列 ISP 处理后,最终输出的像素值 与场景辐照度 之间是一个未知的非线性映射。
定义曝光量 (辐照度 × 曝光时间),相机响应函数 将曝光量映射到像素值:
是单调递增的,但我们不知道它的解析形式。反过来,如果我们能从多张曝光照片中恢复出 ,就能将像素值反推出辐照度。
Debevec 算法恢复 CRF
Debevec(1997)提出的方法至今仍是恢复 CRF 的经典方案。对同一场景的 张照片,每张的曝光时间 已知。选取 个空间位置,要求这些位置在 张照片中都能找到对应像素(不过曝也不欠曝)。
对第 个像素点、第 张照片,有:
两边取对数,记 :
这里 是待求解的函数(定义在离散灰度值 上,共 256 个未知数), 是每个像素点的未知辐照度( 个未知数)。Debevec 将求解转化为一个加权最小二乘问题:
第一项确保拟合精度,第二项是平滑约束(惩罚 的二阶差分)。权重函数 在中间灰度值取最大值,在两端( 或 )趋近于 0——过曝和欠曝的像素不可靠,不应参与拟合。
这是一个大型稀疏线性系统,通过 SVD 求解后即可得到完整的 CRF 曲线 。
辐照度图合成
有了 CRF,就可以将多张照片融合为一张高动态范围的辐照度图。对每个像素位置 ,用所有照片在该位置的有效像素值加权平均:
权重 同样是中间灰度值权重大、两端权重小。最终得到的是浮点格式的辐照度图(通常是 .hdr 或 .exr),动态范围可达 100dB 以上。这张图不能在普通显示器上直接查看,需要一个压缩步骤。
Tone Mapping
Tone Mapping 将高动态范围辐照度图压缩到低动态范围(8bit/通道)的同时,尽量保留视觉细节和对比度感。
全局 Tone Mapping
最简单的形式是 Gamma 映射和 Reinhard 全局算子:
其中 为归一化辐照度, 为显示亮度。这个 S 形曲线在暗部近似线性(保留对比度),在亮部逐渐饱和(防止过曝),基本思路是”压低亮的、保持暗的”。全局映射的优点是速度快,缺点是局部对比度丢失——相邻区域只要有相近的绝对亮度,映射后就会被压成相近的显示值。
局部 Tone Mapping
局部算子考虑每个像素周围的局部区域亮度。经典方法包括:
- 基于 Retinex 理论:将图像分解为光照层和反射层,只压缩光照层。反射层包含了纹理细节,保留不动。
- 基于引导滤波或双边滤波:用滤波结果做亮度分区,将全局映射改为逐区域自适应。较亮的区域接受更强的压缩,较暗的区域压缩较少甚至不压缩。
局部映射能更好地保持细节,代价是计算量更大,且可能在 Halo 伪影(强边缘附近出现光晕)。
HDR 与 ISP 的关系
在相机 ISP pipeline 中,HDR 通常作为一个可选模块插入在 Demosaicing 之后、Tone Mapping 之前。手机上常见的方式有两种:
- 多帧合成 HDR:连续拍摄多张不同曝光的 RAW 图,在 RAW 域合成 HDR 再走标准 ISP 流程。计算量大,但画质最好。
- 单帧 HDR / DOL-HDR:传感器采用隔行交替曝光(长/短),一次读出两帧合成。适合视频录制。
无论哪种方案,从信号处理的角度看,核心始终是 Debevec 框架或它的硬件加速变体。