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 块匹配流程总览

下面这张图把整个块匹配流程串起来了:

块匹配算法流程图 块匹配算法核心流程 输入:当前帧 + 参考帧 划分当前帧为 N×N 块 设置搜索窗口 [-R, +R] 滑动块,计算匹配代价(SAD/SSD/NCC) 输出:最小代价位置 → 运动矢量 关键参数 • 块大小:4×4 ~ 32×32 • 搜索半径:2 ~ 32 像素 • 匹配准则:SAD/SSD/NCC 输出 • 运动矢量 (dx, dy) • 匹配代价(用于后续权重计算)

流程其实不复杂:输入两帧 → 分块 → 设窗口 → 滑动匹配 → 输出运动矢量。但每个环节都有坑,我前面都提到了。

实用建议: 如果你刚开始做多帧降噪,先用 SAD + 8×8 块 + R=8 跑通流程。这个组合在大多数场景下效果不错,计算量也可控。等跑通了,再根据实际效果调参数。

块匹配的原理就这些。说白了,它就是个“暴力搜索”——在窗口内穷举所有位置,找最像的那个。虽然简单,但很有效。后面我们会看到,运动补偿就是基于这些运动矢量,把参考帧“对齐”到当前帧,然后才能做多帧降噪。