3、匹配代价计算(上):绝对差(AD)、平方差(SD)、归一化互相关(NCC)、Census变换
各位同学,欢迎来到代价计算的上半场。
匹配代价计算,说白了就是回答一个问题:左图的像素点,跟右图的候选点,到底像不像?
我刚开始做立体匹配的时候,觉得这步很简单——不就是比一比像素值嘛。后来踩的坑多了才发现,选对代价函数,项目就成功了一半。今天咱们就把四种最经典的代价计算方法掰开揉碎讲清楚。
3.1 绝对差(AD)—— 最朴素的直觉
AD 的思路非常直接:两个像素的灰度值差多少,代价就是多少。
公式长这样:
C_AD(p, d) = |I_left(x, y) - I_right(x-d, y)|
其中 p=(x,y) 是左图像素,d 是视差值。
举个例子:左图某点灰度值 128,右图候选点 120,代价就是 8。越小说明越相似。
优点:计算量极小,硬件实现友好。
缺点:对光照变化、噪声极其敏感。我在项目中遇到过,室内灯光稍微不均匀,AD 就崩了,匹配结果全是噪点。
我个人习惯:AD 只用在受控环境,比如工业流水线上的零件检测。户外场景?别想了。
3.2 平方差(SD)—— 放大差异
SD 跟 AD 很像,只是把绝对值换成了平方:
C_SD(p, d) = (I_left(x, y) - I_right(x-d, y))²
为什么要平方?说白了就是惩罚大误差。两个像素差 10,SD 代价是 100;差 20,代价是 400。差距越大,惩罚越狠。
嗯,这里要注意:SD 对异常值更敏感。我曾经在项目中用 SD,结果一个反光点就让整个视差图出现大片空洞。
| 方法 | 计算量 | 抗噪性 | 适用场景 |
|---|---|---|---|
| AD | 极低 | 差 | 受控环境 |
| SD | 低 | 更差 | 几乎不用 |
避坑指南:我曾经在纹理丰富的场景同时测试 AD 和 SD,结果 SD 的误匹配率比 AD 高了 15%。原因就是平方放大了传感器噪声。所以现在除非有特殊理由,我基本不用 SD。
3.3 归一化互相关(NCC)—— 光照鲁棒
NCC 是经典中的经典。它不直接比像素值,而是比局部区域的灰度变化模式。
公式:
C_NCC(p, d) = Σ[(I_left - μ_left)(I_right - μ_right)] / √[Σ(I_left - μ_left)² · Σ(I_right - μ_right)²]
其中 μ 是窗口内的灰度均值。
结果范围在 [-1, 1] 之间,越接近 1 越相似。
为什么 NCC 能抗光照变化?你想想看,如果整个区域亮度整体提高 50,减去均值后,差值基本不变。这就是归一化的威力。
我个人的经验:NCC 在室内场景表现极好,尤其是光照渐变的情况。但计算量是 AD 的几十倍,实时应用需要优化。
不过 NCC 也有短板——对重复纹理和弱纹理区域效果差。比如一面白墙,NCC 算出来所有候选点都是 0.99,根本分不清。
3.4 Census变换 —— 二值化的智慧
Census 变换的思路很巧妙:不比较灰度值本身,而是比较邻域内像素与中心像素的大小关系。
步骤:
- 取中心像素 p 周围的一个窗口(比如 3x3)
- 窗口内每个像素与 p 比较:大于 p 记 1,小于等于记 0
- 得到一个二进制串(比如 10110010)
- 左右图对应点的二进制串做汉明距离(不同位的个数)
举个例子:左图 Census 串是 10110010,右图是 10100010,不同位有 1 个,代价就是 1。
为什么 Census 这么流行?因为它对光照变化几乎免疫。只要光照变化不改变像素间的相对大小关系,Census 结果就不变。我在户外项目中用 Census,效果吊打 AD 和 NCC。
但 Census 也有代价:窗口大小选择很关键。窗口太小,区分度不够;窗口太大,计算量飙升,而且会丢失细节。
3.5 四种方法对比总结
咱们用一张表来收尾:
| 方法 | 核心思想 | 光照鲁棒性 | 计算量 | 我的推荐场景 |
|---|---|---|---|---|
| AD | 直接比灰度差 | 极差 | 极低 | 受控环境、硬件实现 |
| SD | 平方放大差异 | 差 | 低 | 几乎不用 |
| NCC | 归一化相关性 | 好 | 高 | 室内、光照渐变 |
| Census | 二值化比较 | 极好 | 中 | 户外、光照剧烈变化 |
3.6 知识体系总览
下面这张图帮你理清四种方法的定位和关系:
从这张图可以清楚看到:AD 和 SD 属于同一类,简单但脆弱;NCC 和 Census 是进阶方案,各有千秋。我个人建议,新项目起步直接用 Census,除非你有明确的理由用别的。
最后说一句:代价计算只是第一步。算出来的代价怎么聚合、怎么优化,才是真正拉开差距的地方。这部分咱们后面几章慢慢聊。