3. 经典多帧降噪算法
多帧降噪,说白了就是「用多张照片换一张干净照片」。你想想看,单帧降噪再怎么折腾,细节和噪声之间总得有个取舍。但如果你手里有 4 帧、8 帧甚至 16 帧同一场景的图像呢?那操作空间就大多了。
我刚开始做 ISP 时,觉得多帧降噪不就是「叠一叠」嘛。后来踩了不少坑才明白——怎么叠、叠多少、每帧信多少,这里面门道很深。今天咱们就把三种经典方法掰开揉碎了讲清楚。
3.1 均值帧叠加:最朴素的暴力美学
均值叠加的原理一句话就能说清:对同一像素位置,取 N 帧的像素值求平均。假设你有 N 帧图像 \(I_1, I_2, ..., I_N\),输出帧 \(I_{out}\) 在位置 \((x,y)\) 的值为:
I_out(x,y) = (1/N) * Σ I_i(x,y) (i=1..N)
为什么有效?因为噪声是零均值的随机信号。叠加 N 帧后,信号部分保持不变(因为每帧信号相同),而噪声的标准差会降低到原来的 \(1/\sqrt{N}\)。换句话说,4 帧叠加,噪声降低一半;16 帧叠加,噪声降低四分之三。
关键指标:均值叠加的 SNR 提升 = 10 * log10(N) dB。N=4 时提升 6dB,N=8 时提升 9dB。
我在项目中遇到过一个问题:用均值叠加处理夜景视频,结果画面发虚。后来发现是帧间有微小抖动,直接平均把边缘给「糊」了。所以均值叠加有个前提——帧间必须严格对齐,否则细节全毁。
我的习惯:均值叠加适合静态场景或经过精准运动补偿后的帧序列。如果运动补偿残差大于某个阈值,我会把这帧的权重直接置零。
3.2 中值帧叠加:对抗离群值的利器
均值叠加有个致命弱点——怕「脏数据」。如果某一帧恰好有热像素、坏点或者运动物体,均值会把异常值「平均」到结果里,导致整张图出现鬼影或亮点。
中值叠加的思路是:对每个像素位置,取 N 帧在该位置的像素值,排序后取中间值。比如 5 帧,取第 3 大的值;7 帧,取第 4 大的值。
I_out(x,y) = median( I_1(x,y), I_2(x,y), ..., I_N(x,y) )
中值叠加的好处很明显:对离群值不敏感。即使某一帧有热像素(比如值特别大),只要其他帧正常,中值结果基本不受影响。我曾经用中值叠加处理过一批有坏点的 sensor 数据,效果比均值好太多。
但中值叠加也有代价:计算量大。每个像素都要排序,N 越大越慢。另外,中值叠加对高斯噪声的抑制效果不如均值——因为中值只取一个值,没有利用所有帧的信息做统计平均。
| 方法 | 高斯噪声抑制 | 离群值鲁棒性 | 计算复杂度 | 适用场景 |
|---|---|---|---|---|
| 均值叠加 | 优(理论最优) | 差 | 低(O(N)) | 静态场景、已对齐帧 |
| 中值叠加 | 良 | 优 | 高(O(N log N)) | 有坏点/热像素、轻度运动 |
注意:中值叠加在 N 为偶数时,通常取中间两个值的平均。但偶数帧的中值估计偏差较大,我建议尽量用奇数帧(3、5、7、9)。
3.3 自适应加权叠加:让「好帧」多说话
均值和中值都是「一刀切」——要么所有帧平等,要么只取一帧。但实际情况是:不同帧的质量不一样。比如手持拍摄时,有些帧抖得厉害,有些帧比较稳;或者某些帧的局部区域有运动,其他区域是静止的。
自适应加权叠加的思路是:给每帧的每个像素分配一个权重,权重越高,该帧对该像素的贡献越大。输出为:
I_out(x,y) = Σ w_i(x,y) * I_i(x,y) / Σ w_i(x,y)
权重怎么算?常见的方法有:
- 基于运动检测:计算当前帧与参考帧的差异,差异大的区域权重降低。
- 基于梯度/纹理:纹理丰富的区域权重高,平坦区域权重低(因为平坦区噪声更明显)。
- 基于噪声估计:噪声大的帧整体权重降低。
我个人习惯用 双边权重:同时考虑像素值相似度和空间距离。这样既能抑制噪声,又能保护边缘。代码实现大致如下:
// 伪代码:自适应加权叠加
for each pixel (x,y):
total_weight = 0
total_value = 0
for each frame i:
// 计算当前帧与参考帧的亮度差异
diff = abs(I_i(x,y) - I_ref(x,y))
// 权重 = 高斯函数,差异越大权重越小
w = exp(-diff^2 / (2 * sigma^2))
total_weight += w
total_value += w * I_i(x,y)
I_out(x,y) = total_value / total_weight
避坑指南:我曾经把 sigma 设得太小,结果只有参考帧有贡献,其他帧几乎被忽略——等于没做降噪。sigma 一般取图像动态范围的 5%-10%,比如 8-bit 图像取 12-25。
3.4 基于噪声方差的帧融合:理论最优解
如果你知道每帧的噪声方差,那就可以用 最小方差融合——这是理论上的最优加权方式。假设第 i 帧的噪声方差为 \(\sigma_i^2\),那么最优权重为:
w_i = 1 / σ_i^2
为什么?因为噪声方差越大,该帧的「可信度」越低,权重就应该越小。这种加权方式能保证输出帧的噪声方差最小:
σ_out^2 = 1 / Σ (1/σ_i^2)
实际应用中,噪声方差怎么估计?我常用的方法:
- 暗区估计:取图像中最暗的 5% 像素,计算其方差作为噪声基底。
- 差值法:用两帧相减,差值的方差 ≈ 2 * 噪声方差。
- 基于 sensor 模型:根据增益和曝光时间查表得到噪声参数。
| 方法 | 优点 | 缺点 | 我推荐的使用场景 |
|---|---|---|---|
| 暗区估计 | 简单、实时 | 暗区不一定代表全局噪声 | 快速原型验证 |
| 差值法 | 准确、无偏 | 需要两帧,且帧间不能有运动 | 静态场景标定 |
| sensor 模型 | 最准确、可预测 | 需要 sensor 标定数据 | 量产产品 |
核心结论:基于噪声方差的融合是「理论上限」,但实际中噪声方差估计不准反而会引入 artifacts。我通常把它作为 baseline,然后根据实际效果微调权重。
3.5 四种方法对比与选型指南
说了这么多,到底该用哪种?我整理了一张对比表,方便你快速决策:
| 方法 | 降噪能力 | 细节保留 | 计算开销 | 鲁棒性 | 实现难度 |
|---|---|---|---|---|---|
| 均值叠加 | ★★★★★ | ★★★☆☆ | ★☆☆☆☆ | ★☆☆☆☆ | ★☆☆☆☆ |
| 中值叠加 | ★★★★☆ | ★★★★☆ | ★★★★☆ | ★★★★★ | ★★☆☆☆ |
| 自适应加权 | ★★★★☆ | ★★★★★ | ★★★☆☆ | ★★★★☆ | ★★★★☆ |
| 噪声方差融合 | ★★★★★ | ★★★★☆ | ★★☆☆☆ | ★★★☆☆ | ★★★☆☆ |
我的个人建议:
- 刚入门或快速验证:先上均值叠加,简单有效。
- sensor 有坏点或热像素:中值叠加是首选。
- 手持拍摄或场景有轻微运动:自适应加权叠加最稳。
- 追求理论最优且能准确估计噪声:噪声方差融合值得一试。
3.6 实战中的避坑与调优
最后分享几个我踩过的坑,希望能帮你少走弯路:
- 帧数不是越多越好。超过 8 帧后,降噪收益递减,但计算量和存储开销线性增长。我一般用 4-8 帧。
- 运动补偿要谨慎。补偿不准还不如不补。我习惯先做粗对齐(全局仿射),再做细对齐(局部光流),最后用自适应加权兜底。
- 权重平滑很重要。自适应加权时,权重图如果变化太剧烈,输出帧会出现「块状感」。我会对权重图做高斯模糊,让权重过渡自然。
- 别忘了色彩空间。多帧降噪通常在 YUV 或 RAW 域做,不要在 sRGB 域做——因为 gamma 校正会破坏噪声的统计特性。
我曾经犯过的错:有一次在 sRGB 域做均值叠加,结果降噪后颜色偏暗,细节也丢了。后来才意识到是 gamma 的问题。从那以后,我所有多帧处理都在线性空间完成。