3、多帧合成原理:短帧、中帧、长帧的曝光策略、帧对齐与运动补偿、权重映射与融合算法
多帧合成,说白了就是让摄像头像人眼一样,在不同亮度下各拍一张,然后挑最好的部分拼起来。我在RK平台上调过不少项目,发现很多工程师把精力全放在算法上,却忽略了最基础的东西——曝光策略。曝光策略没定好,后面帧对齐和融合做得再好,也是白搭。
这一章,我就把多帧合成的三个核心环节拆开来讲:曝光策略、帧对齐与运动补偿、权重映射与融合算法。你想想看,这三个环节任何一个出问题,最终HDR效果都会崩。
3.1 短帧、中帧、长帧的曝光策略
曝光策略,就是决定三帧分别用多少曝光时间、多少增益。我习惯把这三帧称为:短帧(S)、中帧(M)、长帧(L)。它们的核心任务很简单:
- 短帧:保住高光细节,防止过曝。
- 长帧:提亮暗部细节,防止欠曝。
- 中帧:作为主帧,提供中间调的画质基准。
曝光时间的比例,我一般推荐 1:4:16 或 1:8:64。具体选哪个,取决于场景的动态范围。举个例子,在RK3588上调试一个户外逆光场景,我用的是1:4:16,短帧1ms,中帧4ms,长帧16ms。为什么是这个比例?因为传感器在16ms时信噪比还能接受,再长就出现热噪点了。
关键指标:曝光比
曝光比 = 长帧曝光时间 / 短帧曝光时间。这个值决定了HDR能覆盖的动态范围。曝光比越大,动态范围越宽,但帧对齐难度也越大。我个人建议,在运动场景中曝光比不要超过16倍,否则运动鬼影会很难处理。
增益策略上,我有个习惯:优先调曝光时间,再调增益。因为增益会放大噪声,尤其是长帧。我曾经在RK3399上踩过一个坑——为了省帧率,把长帧增益拉到12dB,结果暗部全是彩色噪点,降噪都救不回来。后来我改成延长曝光时间、降低增益,效果立竿见影。
| 参数 | 短帧 | 中帧 | 长帧 |
|---|---|---|---|
| 曝光时间 | 1x | 4x | 16x |
| 模拟增益 | 1x (0dB) | 1x~2x | 1x~4x |
| 数字增益 | 1x | 1x | 1x~2x |
| 主要任务 | 保高光 | 主画质 | 提暗部 |
注意:数字增益尽量少用。它只是把信号放大,噪声也会被放大。我在项目中一般把数字增益限制在2x以内,超过这个值,暗部画质会明显劣化。
3.2 帧对齐与运动补偿
三帧曝光时间不同,拍摄时刻也不同。如果场景中有运动物体,比如行人、车辆,三帧中物体的位置会不一样。直接融合,就会出现鬼影——物体边缘出现半透明的重影。
帧对齐,就是把这些错位的像素找回来。我常用的方法是基于块匹配的运动估计。说白了,就是把图像分成16x16或32x32的小块,然后在相邻帧中搜索最匹配的位置。
具体流程是这样的:
- 参考帧选择:一般选中帧作为参考帧,因为它的曝光时间居中,画质最好。
- 块匹配:对每个块,在短帧和长帧中搜索最佳匹配位置。搜索范围一般是±32像素。
- 运动矢量计算:得到每个块的位移量(dx, dy)。
- 运动补偿:根据运动矢量,对短帧和长帧进行重采样,对齐到参考帧。
嗯,这里要注意。块匹配有个问题——遮挡。比如一个行人走过,他在短帧中出现在位置A,在长帧中出现在位置B,但位置B在短帧中被背景挡住了。这种情况下,匹配会失败。我一般会加一个置信度判断:如果匹配误差太大,就标记为“不可靠区域”,在融合时降低权重。
我的经验:在RK平台上,运动估计的搜索范围不要设太大。搜索范围越大,计算量越大,而且容易匹配到错误位置。我一般设±16像素,配合多分辨率金字塔,效果和性能都能兼顾。
运动补偿还有一个变种——光流法。光流法比块匹配更精细,能计算每个像素的运动矢量,但计算量也大得多。在RK3588的NPU上,我试过用光流法做帧对齐,效果确实好,但帧率从30fps掉到了15fps。所以,移动端还是优先用块匹配。
3.3 权重映射与融合算法
帧对齐之后,三帧已经对齐到同一个坐标系了。接下来就是融合——把三帧中最好的部分挑出来,合成一张HDR图像。
权重映射,就是给每个像素分配一个权重,告诉融合算法“这个像素值不值得信”。权重一般基于三个指标:
- 曝光度:像素值越接近中间调(比如128/255),权重越高。过曝或欠曝的像素权重低。
- 对比度:局部对比度高的区域,权重高。这能保留纹理细节。
- 饱和度:颜色饱和度高的区域,权重高。防止融合后颜色变灰。
我常用的权重函数是这样的:
// 基于曝光度的权重
float weight_exposure(float pixel_value) {
// 像素值归一化到0~1
float v = pixel_value / 255.0f;
// 高斯型权重,峰值在0.5
return exp(-pow((v - 0.5f) * 4.0f, 2.0f));
}
融合算法,最经典的是多尺度融合(Laplacian Pyramid)。为什么用多尺度?因为不同尺度下,图像的特征不一样。大尺度(低频)决定整体亮度,小尺度(高频)决定纹理细节。多尺度融合能分别处理,效果更自然。
流程是这样的:
- 对三帧分别构建拉普拉斯金字塔(一般4~6层)。
- 对权重图也构建高斯金字塔(平滑权重图)。
- 每层金字塔中,用权重图加权融合三帧的系数。
- 从顶层到底层,逐层重建,得到最终HDR图像。
核心公式:
融合后的第l层系数 = Σ (权重图第l层 × 帧的第l层系数) / Σ 权重图第l层
说白了,就是加权平均,但权重和系数都在金字塔域中处理。
还有一种更轻量的方法——单尺度加权融合。直接对原始图像做加权平均,不做金字塔。优点是速度快,缺点是容易产生光晕(halo)。我在RK3566上做过对比,单尺度融合在边缘处会出现明显的亮度跳变,而多尺度融合就平滑得多。
我曾经在RK3588上调试一个室内暗光场景,长帧曝光时间到了32ms,短帧只有2ms。融合时发现,长帧的暗部噪声被带到了最终图像中。后来我在权重映射中加了一个噪声估计项——如果某个像素的局部方差太大(说明噪声多),就降低它的权重。这样,噪声区域主要由中帧和短帧贡献,暗部画质明显提升。
避坑指南:我曾经在RK3399上遇到一个鬼影问题,怎么调都调不好。后来发现,问题出在帧对齐的搜索范围上——我设了±64像素,结果运动矢量经常匹配到错误位置。改成±16像素后,鬼影消失了。所以,搜索范围不是越大越好,要根据实际运动幅度来定。
3.4 本章知识体系
下面这张图,我把多帧合成的核心流程画出来了。你可以对照着看,每个环节的输入输出是什么,以及它们之间的依赖关系。
从这张图你可以看到,整个流程是串行的。曝光策略决定了输入质量,帧对齐解决了运动问题,权重映射决定了融合的优先级,融合算法最终合成结果。任何一个环节出问题,都会影响最终效果。
我个人觉得,初学者最容易忽略的是权重映射。很多人以为帧对齐做好了,直接平均就行。但实际项目中,权重映射才是决定画质的关键。你想想看,如果长帧的暗部噪声很大,你还给它高权重,那融合结果肯定一团糟。所以,权重映射一定要结合噪声估计和运动置信度,不能只看曝光度。