4. 权重函数设计:像素权重计算、基于曝光的权重、基于饱和度的权重、基于梯度的权重
多帧融合的核心,说白了就是「怎么把几张图里最好的部分挑出来,拼成一张完美的图」。
你想想看,短曝光那帧暗部细节好,但亮部可能欠曝;长曝光那帧亮部层次丰富,但暗部可能死黑。怎么让算法知道「这里该用短曝光的像素,那里该用长曝光的像素」?
答案就是——权重函数。
我刚开始做HDR融合时,以为权重就是简单的线性插值。后来发现,事情远没那么简单。权重设计的好坏,直接决定了融合结果有没有鬼影、有没有噪声、细节是否丰富。
4.1 权重函数的基本概念
权重函数,就是给每个像素打一个「质量分」。分数越高,说明这个像素越值得被信任,在最终融合时占的比重大。
数学上,多帧融合可以表示为:
I_final(x,y) = Σ [ W_i(x,y) * I_i(x,y) ] / Σ W_i(x,y)
其中,W_i(x,y) 就是第 i 帧在位置 (x,y) 的权重。分母做归一化,保证总权重和为1。
权重设计有三个基本维度:
- 曝光权重:像素亮度是否处于传感器的最佳响应区间
- 饱和度权重:像素是否过曝或欠曝
- 梯度权重:像素所在区域的纹理丰富程度
实际工程中,通常把这三种权重乘在一起,得到最终的融合权重。
关键点:权重函数必须是平滑的、连续的。如果权重在某个亮度值处突然跳变,融合结果就会出现明显的拼接痕迹。
4.2 基于曝光的权重
曝光权重是最直观的。每个像素都有一个「最佳曝光区间」——在这个区间内,传感器的信噪比最高,量化误差最小。
典型的曝光权重函数是一个高斯型曲线:
W_exp(I) = exp( - (I - I_mid)² / (2 * σ²) )
其中:
I是像素亮度值(归一化到0~1)I_mid是中间灰度值,通常取0.5σ控制曲线的宽度,一般取0.2~0.3
这个函数的意思是:亮度在0.5附近的像素权重最高,越亮或越暗,权重越低。
我在项目中遇到过一个问题:直接用高斯权重,暗部区域的权重会变得非常小。结果就是,短曝光帧的暗部虽然信噪比低,但好歹有信号;长曝光帧的暗部虽然信噪比高,但可能已经饱和了。如果权重给得太极端,融合结果反而不好。
我的经验:实际工程中,我通常把σ设得大一些(0.3~0.4),让权重曲线更平坦。这样暗部和亮部都能保留一定的贡献,避免融合结果出现「断层」。
4.3 基于饱和度的权重
饱和度权重解决的是「过曝」和「欠曝」的问题。
过曝的像素(亮度接近1.0)已经失去了纹理信息,全是白色一片。欠曝的像素(亮度接近0.0)被噪声淹没,信噪比极低。这两种像素都应该被「惩罚」——权重设为0或接近0。
饱和度权重的设计思路很简单:
W_sat(I) =
0, if I < I_low_thresh
(I - I_low_thresh) / (I_mid - I_low_thresh), if I_low_thresh ≤ I < I_mid
1, if I_mid ≤ I < I_high_thresh
(1.0 - I) / (1.0 - I_high_thresh), if I_high_thresh ≤ I < 1.0
0, if I ≥ 1.0
说白了,就是中间一段给满分,两端逐渐降为0。
阈值怎么选?我一般这样设:
| 参数 | 推荐值 | 说明 |
|---|---|---|
I_low_thresh |
0.05 ~ 0.10 | 低于此值视为欠曝,权重为0 |
I_high_thresh |
0.90 ~ 0.95 | 高于此值视为过曝,权重为0 |
I_mid |
0.50 | 最佳曝光点 |
注意:饱和度权重和曝光权重不要「双重惩罚」。我曾经犯过这个错误——曝光权重已经给暗部打了低分,饱和度权重又给暗部打了一次低分。结果暗部权重几乎为0,融合结果暗部全是噪声。正确的做法是:曝光权重和饱和度权重取其一,或者让饱和度权重只处理极端情况。
4.4 基于梯度的权重
梯度权重是我个人觉得最有意思的一个维度。
它的核心思想是:纹理丰富的区域,权重应该更高。为什么?因为纹理区域包含了更多的图像信息,而且人眼对纹理区域的失真更敏感。
梯度权重的计算:
G(x,y) = sqrt( Gx² + Gy² )
其中 Gx 和 Gy 是Sobel算子计算的水平和垂直梯度。
然后,把梯度映射到权重:
W_grad(x,y) = min( G(x,y) / G_max, 1.0 )
或者用更平滑的方式:
W_grad(x,y) = 1 - exp( -G(x,y) / τ )
其中 τ 控制梯度响应的灵敏度,一般取0.1~0.3。
梯度权重有个很实用的场景:消除鬼影。
你想想看,如果场景中有运动物体,不同帧之间同一个位置的梯度会发生变化。运动区域的梯度权重会降低,从而减少运动物体对融合结果的贡献。这就是梯度权重在「运动检测」中的妙用。
实战技巧:梯度权重不要单独使用,一定要和曝光权重或饱和度权重配合。否则,纯黑区域(梯度为0)和纯白区域(梯度也为0)都会被赋予低权重,但原因完全不同——一个是欠曝,一个是过曝。只有结合曝光信息,才能正确区分这两种情况。
4.5 多权重融合策略
实际工程中,我们通常把三种权重组合起来。组合方式有两种:
- 乘法组合:
W_total = W_exp * W_sat * W_grad - 加权组合:
W_total = α*W_exp + β*W_sat + γ*W_grad
我个人习惯用乘法组合。因为乘法组合是「与」的关系——一个像素必须在曝光、饱和度和纹理三个方面都表现良好,才能获得高权重。加权组合是「或」的关系,某个维度得分高就能拉高总分,容易引入质量差的像素。
下面是我常用的权重计算流程:
// 伪代码:多帧融合权重计算
for each frame i:
for each pixel (x,y):
// 1. 计算曝光权重
w_exp = exp( - (I_i(x,y) - 0.5)² / (2 * 0.3²) )
// 2. 计算饱和度权重
if I_i(x,y) < 0.05:
w_sat = 0
elif I_i(x,y) > 0.95:
w_sat = 0
else:
w_sat = 1.0
// 3. 计算梯度权重
grad = sobel_gradient(I_i, x, y)
w_grad = 1 - exp( -grad / 0.2 )
// 4. 组合权重
W_i(x,y) = w_exp * w_sat * w_grad
// 5. 空间平滑(可选)
W_i = gaussian_blur(W_i, sigma=3)
避坑指南:最后一步的空间平滑很重要。如果不做平滑,权重在像素级别剧烈变化,融合结果会出现「颗粒感」。我一般用3x3或5x5的高斯核做一次平滑,让权重过渡更自然。
4.6 权重函数设计全景图
下面这张图展示了权重函数设计的完整知识体系:
4.7 实战中的注意事项
权重设计看起来简单,但实际调参时坑很多。我总结几个常见问题:
- 权重太陡:融合结果出现明显的「拼接缝」。解决方案是增大σ或使用更平滑的权重函数。
- 权重太平:融合结果没有充分利用各帧的优势。解决方案是适当减小σ,让权重更有区分度。
- 忽略空间一致性:相邻像素的权重差异过大,导致融合结果出现「颗粒感」。解决方案是加空间平滑。
- 权重计算太慢:每个像素都要计算指数函数,性能开销大。解决方案是用查找表(LUT)预计算权重曲线。
性能优化建议:权重计算不要逐像素做指数运算。我一般把亮度值量化到256级,预计算一个256长度的权重查找表。运行时直接查表,速度提升10倍以上。
嗯,权重函数设计就讲到这里。记住一句话:好的权重函数,是让每帧图像只贡献它最擅长的部分。曝光好的区域贡献细节,纹理丰富的区域贡献结构,中间调的区域贡献色彩。这样融合出来的HDR图像,才能既自然又丰富。