2. 块匹配算法原理
块匹配,说白了就是给当前帧里的每个小块,在参考帧里找个最像的“双胞胎”。这个技术是多帧降噪的基石。我刚开始接触这行时,总觉得这步很简单——不就是找相似块嘛。后来踩了不少坑才发现,块大小、搜索范围、匹配准则,每个参数都藏着门道。
2.1 块匹配的基本思想
想象一下你在人群里找朋友。你不会盯着每个人的五官细节看,而是先记住他穿什么颜色的衣服、大概多高——这就是一个“块”的特征。块匹配也是这个逻辑:
- 把当前帧切成若干 N×N 的小块(比如 8×8 或 16×16)
- 在参考帧的某个 搜索窗口 内,滑动这个块
- 每滑动一次,算一次相似度
- 相似度最高的位置,就是匹配结果
嗯,这里要注意:块匹配假设块内所有像素做相同的运动。如果块内有运动边界(比如一半是车、一半是背景),这个假设就失效了。我在做车载视频降噪时就遇到过这个问题——车身上的块匹配到背景上去了,结果降噪后车尾出现鬼影。
核心思想一句话: 将图像分成独立小块,假设块内运动一致,在参考帧中寻找最佳匹配位置。
2.2 搜索窗口与块大小选择
这两个参数是块匹配的“双刃剑”。选大了,计算量爆炸;选小了,匹配不到真实位置。
搜索窗口
搜索窗口决定了算法能在多大范围内找匹配。一般用 [-R, +R] 表示,R 是搜索半径。
| 场景 | 推荐搜索半径 R | 说明 |
|---|---|---|
| 手持拍摄(轻微抖动) | 4 ~ 8 像素 | 运动幅度小,小窗口足够 |
| 车载/无人机(快速运动) | 16 ~ 32 像素 | 运动幅度大,需要大窗口 |
| 监控固定场景 | 2 ~ 4 像素 | 几乎无运动,小窗口即可 |
我个人习惯是先根据帧差法估算运动幅度,再定搜索半径。比如帧差法算出最大位移是 5 像素,我就设 R=8,留点余量。
避坑: 搜索窗口不是越大越好。我曾经在 4K 视频上设 R=64,结果一帧处理了 3 秒——用户直接投诉“卡成幻灯片”。
块大小
块大小直接影响匹配精度和计算量。常见的块大小有 4×4、8×8、16×16、32×32。
| 块大小 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 4×4 | 细节保留好,运动边界清晰 | 噪声敏感,匹配不稳定 | 高信噪比、纹理丰富场景 |
| 8×8 | 平衡性好,最常用 | 对中等噪声仍敏感 | 通用场景 |
| 16×16 | 抗噪声能力强 | 可能模糊细节 | 低光照、高噪声场景 |
| 32×32 | 非常鲁棒 | 严重模糊运动边界 | 极低光照、静态场景 |
你想想看,块越大,包含的像素越多,统计上越稳定——但代价是假设块内所有像素运动一致,这个假设在大块上更容易被打破。我做过一个实验:在 8×8 块上匹配准确率 92%,换成 32×32 后降到 78%,就是因为块内包含了运动边界。
我的经验: 多帧降噪中,我通常先用 8×8 块做粗匹配,再用 4×4 块做细匹配。这样既保证鲁棒性,又保留细节。
2.3 匹配准则
匹配准则就是“怎么算两个块最像”。常用的有三种:SAD、SSD、NCC。我一个个说。
SAD(差值和)
SAD 是最简单、最常用的准则。公式长这样:
SAD = Σ|I₁(i,j) - I₂(i,j)|
就是把两个块对应像素的灰度值相减,取值,再求和。值越小,说明越像。
- 优点: 计算快,只用加减法,没有乘法
- 缺点: 对光照变化敏感
- 硬件友好: 很多 FPGA 和 DSP 都有 SAD 指令加速
我在做手机夜景降噪时,默认就用 SAD。因为它快——一帧 1080p 图像,8×8 块、R=8,用 SAD 只要 15ms,换成 NCC 要 120ms。用户可等不了那么久。
SSD(差值平方和)
SSD 是 SAD 的“平方版”:
SSD = Σ(I₁(i,j) - I₂(i,j))²
- 优点: 对大差异更敏感,匹配更精确
- 缺点: 计算量稍大(有乘法),对噪声更敏感
- 适用: 高信噪比场景,追求亚像素精度时
为什么会这样?因为平方放大了差异。两个块差 10 个灰度级,SAD 贡献 10,SSD 贡献 100。这在大噪声场景下反而是缺点——噪声也会被放大。
NCC(归一化互相关)
NCC 是“正规军”,对光照变化不敏感:
NCC = Σ(I₁(i,j)-μ₁)(I₂(i,j)-μ₂) / √(Σ(I₁(i,j)-μ₁)² · Σ(I₂(i,j)-μ₂)²)
说白了,就是先把两个块减去各自的均值,再做相关。结果在 [-1, 1] 之间,1 表示完全正相关。
- 优点: 对光照变化、整体亮度偏移不敏感
- 缺点: 计算量大,需要多次乘法和开方
- 适用: 光照变化剧烈的场景(如日出日落、闪光灯切换)
注意: NCC 在平坦区域(如白墙)会失效——因为方差接近 0,分母趋近 0,结果不稳定。我曾经在监控视频里遇到大面积白墙,NCC 匹配结果全是 NaN,排查了半天才发现是这个问题。
三种准则对比
| 准则 | 计算量 | 光照鲁棒性 | 噪声鲁棒性 | 匹配精度 | 推荐场景 |
|---|---|---|---|---|---|
| SAD | 低 | 低 | 中 | 中 | 实时系统、硬件加速 |
| SSD | 中 | 低 | 低 | 高 | 高信噪比、亚像素匹配 |
| NCC | 高 | 高 | 高 | 高 | 光照变化大、离线处理 |
我个人习惯:实时系统用 SAD,离线处理用 NCC。如果场景光照稳定,SAD 完全够用;如果光照变化大,再上 NCC。别一上来就 NCC,计算量吃不消。
2.4 块匹配流程总览
下面这张图把整个块匹配流程串起来了:
流程其实不复杂:输入两帧 → 分块 → 设窗口 → 滑动匹配 → 输出运动矢量。但每个环节都有坑,我前面都提到了。
实用建议: 如果你刚开始做多帧降噪,先用 SAD + 8×8 块 + R=8 跑通流程。这个组合在大多数场景下效果不错,计算量也可控。等跑通了,再根据实际效果调参数。
块匹配的原理就这些。说白了,它就是个“暴力搜索”——在窗口内穷举所有位置,找最像的那个。虽然简单,但很有效。后面我们会看到,运动补偿就是基于这些运动矢量,把参考帧“对齐”到当前帧,然后才能做多帧降噪。