2. 多曝光融合算法原理:Debevec与Mertens算法对比、权重图计算、拉普拉斯金字塔融合
多曝光融合,说白了就是把几张不同亮度的照片合成一张。你拍过夜景吧?天空亮了,地面就死黑;地面亮了,天空就过曝。这就是动态范围不够。HDR融合就是来解决这个问题的。
我最早接触这个方向是在做手机相机算法的时候。那时候硬件不行,全靠算法硬扛。嗯,今天我们就来聊聊两种最经典的融合思路:Debevec 和 Mertens。
2.1 两种主流思路:Debevec vs Mertens
先看一张对比图,帮你快速建立认知。
Debevec 算法走的是"辐射域"路线。它先通过多张不同曝光的图像,反推出场景真实的辐射照度,再用色调映射压缩到显示设备能呈现的范围。这个过程需要知道相机的响应曲线(CRF)。
Mertens 算法就简单粗暴多了。它直接在图像域操作,给每张图的每个像素算一个权重,然后加权融合。不需要CRF,不需要色调映射,一步到位。
我在项目中做过对比:Debevec 的效果确实更细腻,但计算量太大,在嵌入式平台上跑不动。Mertens 虽然物理上不那么严谨,但视觉上足够好,而且快得多。
2.2 权重图计算——Mertens的核心
Mertens 算法的精髓就在权重图上。它考虑三个因素:
| 权重因子 | 含义 | 计算公式 |
|---|---|---|
| 对比度 (Contrast) | 拉普拉斯响应的值,越大表示细节越丰富 | C = |Laplacian(I)| |
| 饱和度 (Saturation) | RGB三通道的标准差,颜色越鲜艳权重越高 | S = std(R, G, B) |
| 良好曝光度 (Well-exposedness) | 像素值越接近0.5(中间灰)权重越高 | E = exp(-(I-0.5)² / 2σ²) |
最终的权重图是这三个因子的乘积:
W = C^wc * S^ws * E^we
其中 wc、ws、we 是控制因子,默认都取1。我个人习惯把 we 调大一点,因为曝光良好的区域通常细节也最丰富。
避坑指南: 我曾经在权重图上吃过亏——直接对原始权重做归一化然后融合,结果在明暗交界处出现了明显的接缝。后来才意识到,权重图必须经过金字塔分解,在不同尺度上平滑过渡,才能避免鬼影和接缝。
2.3 拉普拉斯金字塔融合——多尺度平滑的艺术
为什么要用金字塔?你想想看,如果直接在原始分辨率上做加权平均,边缘处权重突变就会产生"硬边"。金字塔融合的核心思想是:大尺度结构用大尺度权重,小尺度细节用小尺度权重。
具体流程分三步:
- 构建拉普拉斯金字塔:对每张输入图像,逐层下采样再上采样,与原图做差,得到带通细节层。
- 构建高斯金字塔:对权重图做同样的下采样,得到平滑的权重金字塔。
- 逐层融合:每层拉普拉斯图像乘以对应层的权重图,然后累加重建。
伪代码如下:
function LaplacianPyramidFusion(images, weights):
for each image i:
L[i] = BuildLaplacianPyramid(images[i])
G[i] = BuildGaussianPyramid(weights[i])
result_pyramid = []
for level l from top to bottom:
fused = sum(L[i][l] * G[i][l] for all i)
result_pyramid.append(fused)
return CollapseLaplacianPyramid(result_pyramid)
注意: 金字塔层数不是越多越好。层数太多,最顶层分辨率太低,会丢失全局结构信息。我一般取 floor(log2(min(H,W))) - 2 层,留一点余量。
2.4 两种算法的对比总结
| 对比维度 | Debevec | Mertens |
|---|---|---|
| 处理域 | 辐射域(线性光) | 图像域(非线性) |
| 是否需要CRF | 是 | 否 |
| 色调映射 | 需要额外步骤 | 不需要 |
| 计算复杂度 | 高(CRF估计 + 色调映射) | 中(权重 + 金字塔) |
| 物理准确性 | 高 | 中等 |
| 视觉自然度 | 依赖色调映射算子 | 通常较好 |
| 嵌入式落地难度 | 高 | 低 |
做嵌入式系统的人,我建议优先掌握 Mertens。它不需要标定相机,不需要复杂的色调映射,而且效果在大多数场景下已经足够好。Debevec 更适合做参考标准,或者用在专业影像软件里。