一、立体匹配概述
1.1 什么是立体匹配
立体匹配,说白了就是让计算机学会「双眼看世界」。
我们人类用两只眼睛看东西,能判断出远近。为什么?因为左右眼看到的画面有细微差别——这叫视差。物体离你越近,左右眼看到的偏移就越大。立体匹配要做的,就是让算法自动找到左右两张图片里「同一个点」在哪,然后算出它的深度。
我刚开始接触这个领域时,觉得这问题挺简单——不就是找对应点嘛。后来才发现,真实场景里到处都是坑:光照变化、纹理重复、遮挡区域……嗯,这活儿比想象中难得多。
从数学上讲,立体匹配的核心就是求解一个视差图。给定左图和右图,对左图中每个像素 (x, y),在右图中找到对应的像素 (x - d, y),这个 d 就是视差值。有了视差,深度就能算出来:
深度 Z = (焦距 f × 基线长度 B) / 视差 d
公式看着简单,但实际做起来,每一步都有讲究。
1.2 立体匹配的四个步骤
业内公认的经典流程,是 Scharstein 和 Szeliski 在 2002 年总结的四个步骤。我这些年做项目,基本都沿着这个框架走。来,一个个说。
第一步:匹配代价计算
这一步要回答一个问题:左图的像素和右图的像素,到底像不像?
常用的方法有:
- 绝对差(SAD):直接算像素值的差的绝对值。简单粗暴,但容易受光照影响。
- 平方差(SSD):差的平方。对噪声更敏感。
- 归一化互相关(NCC):抗光照变化能力强,我项目中常用这个。
- Census 变换:基于局部结构比较,对光照变化鲁棒性好。我在自动驾驶项目里特别喜欢用。
第二步:代价聚合
单像素的代价计算太「近视」了。你想想看,一个像素点很容易被噪声干扰。代价聚合就是让邻居像素「投票」,把局部信息融合进来。
常见方法:
- 局部窗口滤波:盒式滤波、高斯滤波。简单,但容易在边缘处模糊。
- 引导滤波:边缘保持能力强。我强烈推荐这个,效果好且速度快。
- 十字交叉聚合:自适应形状的窗口,适合处理纹理稀疏区域。
这一步是整个流程的关键。我见过不少同学把精力全花在代价计算上,结果聚合没做好,效果一样差。记住:代价聚合决定了视差图的平滑度和边缘保真度。
第三步:视差计算/优化
聚合完代价,就要选出每个像素的最佳视差了。最直接的方法是「赢家通吃」(WTA)——选代价最小的那个视差值。
但 WTA 有个问题:它不考虑相邻像素之间的视差关系。所以就有了全局优化方法:
- 动态规划:在扫描线上做优化。速度快,但有条纹效应。
- 图割(Graph Cut):全局能量最小化。效果好,但慢。
- SGM(半全局匹配):多方向动态规划。这是目前工业界最流行的方法,兼顾速度和精度。
第四步:视差细化
算出来的视差图,通常还有不少瑕疵。比如:
- 遮挡区域的视差是错的
- 边缘处有毛刺
- 亚像素精度不够
所以需要后处理:
- 左右一致性检查:左图到右图的视差,和右图到左图的视差应该一致。不一致的就是遮挡点,直接剔除。
- 亚像素插值:用二次曲线拟合,把视差精度从整数提升到亚像素级别。
- 中值滤波:去除孤立噪点。
- 加权中值滤波:保边去噪,效果更好。
1.3 立体匹配的应用场景
立体匹配不是实验室里的玩具。它在工业界有大量落地场景。我挑三个最典型的说说。
自动驾驶
车载双目相机通过立体匹配生成深度图,用来检测障碍物、判断可通行区域。我记得有一次在高速上测试,系统通过视差图提前 50 米检测到了路面上一个掉落的轮胎——单目相机根本做不到,因为缺乏深度信息。
自动驾驶对实时性要求极高。一般用 SGM 算法,配合 FPGA 或 GPU 加速,做到 30fps 以上。
机器人导航
机器人要在未知环境中移动,必须知道「前面有没有障碍物」「地面平不平」。立体匹配能提供稠密的深度信息,比激光雷达便宜得多。
我做过一个扫地机器人的项目,用双目相机做避障。一开始用的全局算法,算力不够,机器人经常撞墙。后来换成局部算法加快速聚合,才跑起来。嗯,算力和精度之间永远要 trade-off。
三维重建
从多视角图像重建三维模型,立体匹配是核心步骤之一。比如用手机拍一圈物体,通过立体匹配生成深度图,再融合成点云,最后生成 mesh。
这里要注意:三维重建对精度要求高,通常需要亚像素级别的视差。我建议用引导滤波做代价聚合,配合亚像素插值,效果会好很多。
1.4 本章知识体系
下面这张图,是我自己整理的立体匹配知识框架。你可以把它当作整个课程的地图。
这张图把整个流程串起来了。从左到右是四个步骤,从上到下是输入到输出。两侧分别是应用场景和关键技术。你学完这门课,应该能把这个框架烂熟于心。
小结
立体匹配的本质,就是「找对应、算深度」。四个步骤环环相扣,每一步都有它的意义。我个人觉得,初学者最容易忽略的是代价聚合和视差细化这两步——总觉得「算完代价就完事了」。其实不然,真正决定算法上限的,往往是这些「看起来不起眼」的环节。
下一章,我会深入讲匹配代价计算的各种方法,包括它们的数学原理和代码实现。到时候见。
公众号:蓝海资料掘金营,微信deep3321