一、立体匹配概述

1.1 什么是立体匹配

立体匹配,说白了就是让计算机学会「双眼看世界」。

我们人类用两只眼睛看东西,能判断出远近。为什么?因为左右眼看到的画面有细微差别——这叫视差。物体离你越近,左右眼看到的偏移就越大。立体匹配要做的,就是让算法自动找到左右两张图片里「同一个点」在哪,然后算出它的深度。

我刚开始接触这个领域时,觉得这问题挺简单——不就是找对应点嘛。后来才发现,真实场景里到处都是坑:光照变化、纹理重复、遮挡区域……嗯,这活儿比想象中难得多。

从数学上讲,立体匹配的核心就是求解一个视差图。给定左图和右图,对左图中每个像素 (x, y),在右图中找到对应的像素 (x - d, y),这个 d 就是视差值。有了视差,深度就能算出来:

深度 Z = (焦距 f × 基线长度 B) / 视差 d

公式看着简单,但实际做起来,每一步都有讲究。

1.2 立体匹配的四个步骤

业内公认的经典流程,是 Scharstein 和 Szeliski 在 2002 年总结的四个步骤。我这些年做项目,基本都沿着这个框架走。来,一个个说。

第一步:匹配代价计算

这一步要回答一个问题:左图的像素和右图的像素,到底像不像?

常用的方法有:

  • 绝对差(SAD):直接算像素值的差的绝对值。简单粗暴,但容易受光照影响。
  • 平方差(SSD):差的平方。对噪声更敏感。
  • 归一化互相关(NCC):抗光照变化能力强,我项目中常用这个。
  • Census 变换:基于局部结构比较,对光照变化鲁棒性好。我在自动驾驶项目里特别喜欢用。
我的经验: 如果场景光照稳定,SAD 就够了,速度快。如果光照变化大,比如室外自动驾驶,Census 变换是首选。我曾经在一个项目中只用 SAD,结果阴天和晴天效果差很多,后来换成 Census 才稳定下来。

第二步:代价聚合

单像素的代价计算太「近视」了。你想想看,一个像素点很容易被噪声干扰。代价聚合就是让邻居像素「投票」,把局部信息融合进来。

常见方法:

  • 局部窗口滤波:盒式滤波、高斯滤波。简单,但容易在边缘处模糊。
  • 引导滤波:边缘保持能力强。我强烈推荐这个,效果好且速度快。
  • 十字交叉聚合:自适应形状的窗口,适合处理纹理稀疏区域。

这一步是整个流程的关键。我见过不少同学把精力全花在代价计算上,结果聚合没做好,效果一样差。记住:代价聚合决定了视差图的平滑度和边缘保真度。

第三步:视差计算/优化

聚合完代价,就要选出每个像素的最佳视差了。最直接的方法是「赢家通吃」(WTA)——选代价最小的那个视差值。

但 WTA 有个问题:它不考虑相邻像素之间的视差关系。所以就有了全局优化方法:

  • 动态规划:在扫描线上做优化。速度快,但有条纹效应。
  • 图割(Graph Cut):全局能量最小化。效果好,但慢。
  • SGM(半全局匹配):多方向动态规划。这是目前工业界最流行的方法,兼顾速度和精度。
重点: SGM 算法是我个人最推荐的入门算法。它不复杂,但效果能打。我在多个项目中都用它做 baseline,再针对场景做优化。

第四步:视差细化

算出来的视差图,通常还有不少瑕疵。比如:

  • 遮挡区域的视差是错的
  • 边缘处有毛刺
  • 亚像素精度不够

所以需要后处理:

  • 左右一致性检查:左图到右图的视差,和右图到左图的视差应该一致。不一致的就是遮挡点,直接剔除。
  • 亚像素插值:用二次曲线拟合,把视差精度从整数提升到亚像素级别。
  • 中值滤波:去除孤立噪点。
  • 加权中值滤波:保边去噪,效果更好。
避坑指南: 我曾经在一个项目中,视差细化做得太狠,结果把真实细节也抹掉了。后来我学乖了:先做左右一致性检查,只对遮挡区域做插值,其他区域保持原样。这样既去除了错误点,又保留了细节。

1.3 立体匹配的应用场景

立体匹配不是实验室里的玩具。它在工业界有大量落地场景。我挑三个最典型的说说。

自动驾驶

车载双目相机通过立体匹配生成深度图,用来检测障碍物、判断可通行区域。我记得有一次在高速上测试,系统通过视差图提前 50 米检测到了路面上一个掉落的轮胎——单目相机根本做不到,因为缺乏深度信息。

自动驾驶对实时性要求极高。一般用 SGM 算法,配合 FPGA 或 GPU 加速,做到 30fps 以上。

机器人导航

机器人要在未知环境中移动,必须知道「前面有没有障碍物」「地面平不平」。立体匹配能提供稠密的深度信息,比激光雷达便宜得多。

我做过一个扫地机器人的项目,用双目相机做避障。一开始用的全局算法,算力不够,机器人经常撞墙。后来换成局部算法加快速聚合,才跑起来。嗯,算力和精度之间永远要 trade-off。

三维重建

从多视角图像重建三维模型,立体匹配是核心步骤之一。比如用手机拍一圈物体,通过立体匹配生成深度图,再融合成点云,最后生成 mesh。

这里要注意:三维重建对精度要求高,通常需要亚像素级别的视差。我建议用引导滤波做代价聚合,配合亚像素插值,效果会好很多。

1.4 本章知识体系

下面这张图,是我自己整理的立体匹配知识框架。你可以把它当作整个课程的地图。

立体匹配知识体系 左右图像对 步骤一:匹配代价计算 SAD / SSD / NCC / Census 变换 步骤二:代价聚合 引导滤波 / 十字交叉 / 局部窗口 步骤三:视差计算/优化 WTA / 动态规划 / 图割 / SGM 步骤四:视差细化 左右一致性 / 亚像素插值 / 中值滤波 视差图 / 深度图 应用场景 🚗 自动驾驶 🤖 机器人导航 🏗️ 三维重建 📱 手机AR 🎬 影视特效 关键技术 极线校正 代价体构建 能量最小化 视差后处理 GPU加速

这张图把整个流程串起来了。从左到右是四个步骤,从上到下是输入到输出。两侧分别是应用场景和关键技术。你学完这门课,应该能把这个框架烂熟于心。

小结

立体匹配的本质,就是「找对应、算深度」。四个步骤环环相扣,每一步都有它的意义。我个人觉得,初学者最容易忽略的是代价聚合和视差细化这两步——总觉得「算完代价就完事了」。其实不然,真正决定算法上限的,往往是这些「看起来不起眼」的环节。

下一章,我会深入讲匹配代价计算的各种方法,包括它们的数学原理和代码实现。到时候见。


公众号:蓝海资料掘金营,微信deep3321