多帧合成HDR技术:短帧与长帧的曝光策略、帧对齐与融合
多帧合成HDR,说白了就是让摄像头“看”两次——一次看暗处,一次看亮处,然后把两张图里最好的部分拼起来。车载场景下,这个技术尤其关键。你想想看,隧道出口那几秒钟,一边是刺眼的阳光,一边是黑洞洞的隧道,单帧传感器根本扛不住。
我个人习惯把多帧HDR分成三个核心环节:曝光策略、帧对齐、权重融合。下面一个一个拆开讲。
1. 短帧与长帧的曝光策略
曝光策略决定了“拍什么”。短帧负责高亮区域,长帧负责暗部细节。但问题来了——长短帧的曝光时间怎么配?
我在项目中遇到过最典型的场景:车辆以80km/h行驶,前方突然出现一个逆光的行人。如果长帧曝光时间太长,运动模糊会把行人“抹掉”;如果短帧太短,信噪比又不够。嗯,这里要注意一个经验值:长短帧的曝光比通常控制在4:1到16:1之间。
| 场景 | 短帧曝光 | 长帧曝光 | 曝光比 |
|---|---|---|---|
| 隧道出口(强逆光) | 1/2000 s | 1/125 s | 16:1 |
| 城市夜间(路灯+暗区) | 1/500 s | 1/30 s | ~16:1 |
| 高速路日间(均匀光照) | 1/4000 s | 1/500 s | 8:1 |
| 雨天/雾天(低对比度) | 1/1000 s | 1/250 s | 4:1 |
2. 帧对齐算法:光流法与特征匹配
长短帧不是同时拍的,中间有几十毫秒的时间差。车辆在动,场景在变,直接融合会出现重影。所以必须先做帧对齐。
车载领域主流有两种对齐思路:光流法和特征匹配。我两种都用过,说说我的感受。
2.1 光流法
光流法假设像素在短时间内的运动是连续的、微小的。它计算每个像素的运动矢量,然后根据这个矢量把长帧“扭曲”到短帧的坐标系上。
我曾经在一条颠簸的乡间小路上测试过光流法。路面坑洼导致车辆高频振动,光流场变得非常杂乱。后来我加了一个金字塔分层策略——先在大尺度上估计整体运动,再逐层细化到像素级。效果好了很多。
// 简化版金字塔光流伪代码
for level = max_level down to 0:
// 在当前金字塔层计算光流
flow = calc_optical_flow(img1_pyr[level], img2_pyr[level], flow_init)
// 上采样到下一层
flow_init = upsample(flow) * 2
end
// 用最终光流场做图像扭曲
warped_img2 = warp_image(img2, flow)
2.2 特征匹配
特征匹配的思路更“粗暴”——先提取图像中的角点、边缘等特征,然后找两帧之间的特征对应关系,最后算出一个全局单应性矩阵或仿射变换矩阵。
特征匹配的优势是对大运动鲁棒。车辆急转弯时,光流法容易发散,但特征匹配只要还能找到几个稳定的特征点,就能算出变换矩阵。
我个人习惯在静态背景占主导的场景(比如高速路)用光流法,在动态物体多、运动幅度大的场景(比如城市路口)用特征匹配。当然,也有混合方案——先用特征匹配做粗对齐,再用光流法做细对齐。
| 对比项 | 光流法 | 特征匹配 |
|---|---|---|
| 计算量 | 大(逐像素) | 中等(稀疏特征) |
| 大运动鲁棒性 | 弱(容易发散) | 强(全局变换) |
| 精度 | 高(亚像素级) | 中等(像素级) |
| 适用场景 | 小运动、静态背景 | 大运动、动态场景 |
3. 权重映射与融合
帧对齐做完后,就到了融合环节。融合不是简单的“短帧取亮部、长帧取暗部”,那样会有明显的拼接痕迹。我们需要一个平滑的权重映射。
权重映射的核心思想:对每个像素,根据它的亮度、对比度、饱和度等信息,计算一个融合权重。亮部区域给短帧更高的权重,暗部区域给长帧更高的权重,中间区域做线性过渡。
我常用的权重函数包含三个分量:
- 亮度权重:像素值越接近中间灰度(128),权重越高。避免过曝和欠曝区域被过度信任。
- 对比度权重:局部梯度越大,权重越高。梯度大的区域通常是纹理丰富的区域,融合后细节保留更好。
- 饱和度权重:颜色越饱和,权重越高。防止融合后颜色发灰。
// 权重计算示例(简化版)
float compute_weight(float pixel_value, float local_gradient, float saturation) {
float w_brightness = 1.0 - abs(pixel_value - 128.0) / 128.0;
float w_contrast = min(local_gradient / 50.0, 1.0);
float w_saturation = min(saturation / 0.5, 1.0);
return w_brightness * 0.5 + w_contrast * 0.3 + w_saturation * 0.2;
}
最终融合公式很简单:
// 多帧融合
float total_weight = 0;
float3 final_pixel = 0;
for each frame i:
final_pixel += weight_i(x,y) * frame_i(x,y);
total_weight += weight_i(x,y);
end
final_pixel /= total_weight;
整体流程框架
下面这张图把整个多帧合成HDR的流程串起来了。从传感器曝光开始,到帧对齐、权重计算,最后融合输出。你可以把它当作一个参考管线。
多帧合成HDR不是“拍两张图叠一起”那么简单。曝光策略要适配场景,帧对齐要平衡精度和算力,权重映射要平滑自然。每一步都有坑,但踩过之后,你会发现这套管线在车载视觉系统里几乎是不可替代的。