双目立体视觉实战:SAD、SSD与SGBM算法原理与OpenCV调优指南
1. 项目概述从“看见”到“感知”的立体世界在机器视觉的世界里让计算机像人眼一样“看见”并“理解”三维空间一直是一个充满魅力与挑战的终极目标。双目立体视觉作为实现这一目标的核心技术路径其热度从未消退。说它“热”是因为这项技术几乎是我们迈向通用人工智能感知层不可或缺的一环从自动驾驶汽车精准判断前车距离到工业机器人灵巧地抓取无序摆放的零件再到手机上的AR特效和3D建模背后都离不开双目立体视觉的身影。说它“难”则是因为从两个二维图像中反推出三维信息本质上是一个病态问题充满了各种不确定性光照变化、纹理缺失、遮挡、计算资源限制每一个都是横在工程师面前的现实难题。我接触双目视觉有几年了从最早在实验室里摆弄两个USB摄像头到后来在产品中集成高精度工业相机踩过的坑不计其数。很多人一上来就直奔各种复杂的深度学习网络但在我看来不理解双目视觉的几大经典基础算法就像盖楼不打地基遇到问题根本无从调试和优化。今天我就结合自己的实战经验抛开复杂的数学推导用最直白的方式带你彻底搞懂双目立体视觉的三大基石算法SAD、SSD和SGBM。我会详细拆解它们的原理、手把手展示基于OpenCV的C实现并分享那些在官方文档里找不到的参数调优心得和避坑指南。无论你是正在入门的学生还是需要在项目中快速应用的工程师这篇文章都能给你提供一份可直接“抄作业”的立体匹配实战手册。2. 双目立体视觉的核心思路与算法选型逻辑在深入代码之前我们必须先建立起一个清晰的物理图像和问题模型。双目立体视觉模仿的是人眼的“视差”原理。想象一下当你交替闭上左眼和右眼时近处的物体会发生明显的左右跳动而远处的物体比如月亮则几乎不动。这个跳动量就是“视差”。双目系统就是用两个摄像头模拟你的左右眼通过计算同一个物理点在左右两个图像平面上的像素位置差即视差再利用简单的三角几何关系就能算出该点的深度距离。2.1 问题拆解立体匹配是核心整个双目三维重建的流程可以简化为相机标定 - 图像校正 - 立体匹配 - 三维重建。其中立体匹配是绝对的技术核心与性能瓶颈。它的任务很简单对于左图上的每一个像素点在右图上找到与之对应的同一个物理点的像素位置。听起来简单做起来却异常困难因为图像中存在大量重复纹理、弱纹理区域以及因遮挡导致在某些视角下根本不可见的点。立体匹配算法主要分为两大类局部匹配算法和全局匹配算法。SAD和SSD属于典型的局部匹配算法它们只利用像素点周围一个小窗口内的信息来计算匹配代价速度快但抗干扰能力弱在纹理重复或弱纹理区域容易出错。SGBM则属于半全局匹配算法它试图在局部算法的效率和全局算法的精度之间取得平衡通过沿多个路径进行动态规划聚合相邻像素的约束信息从而得到更平滑、更准确的视差图。在实际项目中选型不是拍脑袋决定的它基于一个清晰的决策链首先明确你的应用场景对实时性和精度的权重要求其次评估待处理图像的纹理丰富度和光照条件最后考虑可供使用的计算资源。注意不要盲目追求最先进的算法。对于室内结构光扫描这类对精度要求极高、可以离线计算的任务可能会采用更复杂的全局算法。但对于机器人实时避障或VR头盔渲染SGBM甚至优化后的局部算法往往是更务实的选择因为必须在几十毫秒内完成计算。2.2 算法核心思想对比与适用场景为了让你快速建立直观认识我用一个表格来概括这三大基础算法的核心思想与特点算法全称核心匹配准则优点缺点典型适用场景SAD绝对误差和计算左右图像对应窗口内像素灰度值差的绝对值之和计算非常简单速度快硬件实现容易对噪声敏感在亮度不一致区域匹配效果差对实时性要求极高、硬件资源有限如早期FPGA、场景亮度均匀的嵌入式系统SSD平方误差和计算左右图像对应窗口内像素灰度值差的平方和相比SAD对较大的误差惩罚更重理论上对某些噪声更鲁棒计算量稍大于SAD同样受亮度差异影响且对异常值如噪声点更敏感与SAD场景类似但期望对均匀噪声有稍好表现的场合实际中使用频率低于SAD和NCC归一化互相关SGBM半全局块匹配定义包含数据项和平滑项的全局能量函数并通过多路径动态规划求近似最优解精度显著高于局部算法视差图更平滑、完整能较好地处理弱纹理区域计算复杂度远高于SAD/SSD需要调节的参数较多绝大多数对精度有要求的实时或准实时应用如自动驾驶、机器人导航、三维测量、中间件输出从表格中可以清晰看出演进路线SAD/SSD是“快但糙”的起点而SGBM则是工程应用中的“性价比之王”。在OpenCV等成熟库中SGBM已经过高度优化是入门和解决实际问题时首选的算法。接下来我们就进入实战环节我会带你逐一剖析它们的实现细节并分享我调参过程中积累的那些“血泪教训”。3. 核心算法解析与OpenCV实战实现这一部分我们将把理论落地。我会假设你已经完成了双目摄像头的标定和立体校正得到了“行对准”的左右视图。这是所有立体匹配算法正确工作的前提校正后的图像其匹配点只存在于同一水平线上将二维搜索降为一维搜索极大降低了计算量和歧义性。3.1 SAD算法原理、实现与性能瓶颈分析SAD算法的思想直观得像用一把尺子去度量相似度。对于左图上的一个像素点称为锚点我们以其为中心取一个winSize x winSize例如7x7的小窗口。然后在右图的同一水平行上在一定视差搜索范围DSR内例如0-30个像素滑动同样大小的窗口。每滑动一次就计算一次左窗口和右窗口内所有对应像素灰度值的绝对差之和。这个和就是匹配代价。代价越小说明两个窗口越相似。遍历完所有候选位置后代价最小的那个位置其对应的视差值就是我们想要的结果。3.1.1 SAD算法代码逐行解读与性能陷阱让我们结合你提供的代码看看一个朴素的SAD实现是怎样的以及其中暗藏的效率陷阱。// SAD_Algorithm.h #include iostream #include opencv2/opencv.hpp #include iomanip using namespace std; using namespace cv; class SAD { public: SAD() : winSize(7), DSR(30) {} // 默认构造函数窗口7x7视差范围30 SAD(int _winSize, int _DSR) : winSize(_winSize), DSR(_DSR) {} // 参数化构造函数 Mat computerSAD(Mat L, Mat R); // 核心计算函数 private: int winSize; // 匹配窗口半径实际窗口大小为 2*winSize1但代码中当作边长使用需注意 int DSR; // 视差搜索范围 }; Mat SAD::computerSAD(Mat L, Mat R) { int Height L.rows; int Width L.cols; // 创建两个临时窗口用于存储当前正在比较的图像块 Mat Kernel_L(Size(winSize, winSize), CV_8U, Scalar::all(0)); Mat Kernel_R(Size(winSize, winSize), CV_8U, Scalar::all(0)); // 创建视差图初始化为0类型为8位无符号后续视差会乘以16保存 Mat Disparity(Height, Width, CV_8U, Scalar(0)); // 遍历左图的每一个像素锚点 for (int i 0; i Width; i) { for (int j 0; j Height; j) { // 提取左图锚点处的窗口。注意边界处理代码中当锚点靠近图像边缘时 // Rect可能越界这是一个严重的BUG if (i - winSize / 2 0 j - winSize / 2 0 i winSize / 2 Width j winSize / 2 Height) { Kernel_L L(Rect(i - winSize/2, j - winSize/2, winSize, winSize)); } else { continue; // 简单跳过边界点导致视差图边缘有黑边 } Mat MM Mat::zeros(1, DSR, CV_32F); // 存储每个候选视差下的SAD代价 // 在右图同一行上滑动搜索窗口搜索范围为 [i - DSR, i] for (int k 0; k DSR; k) { int x i - k; // 右图候选列坐标 if (x - winSize / 2 0) { // 同样需要边界检查 Kernel_R R(Rect(x - winSize/2, j - winSize/2, winSize, winSize)); Mat Dif; absdiff(Kernel_L, Kernel_R, Dif); // 计算绝对差 Scalar ADD sum(Dif); // 对矩阵所有元素求和 float a ADD[0]; // 获取和值 MM.atfloat(k) a; // 存储在代价数组中 } } // 找到最小代价对应的索引即视差值 Point minLoc; minMaxLoc(MM, NULL, NULL, minLoc, NULL); int loc minLoc.x; // 将视差值0~DSR-1映射到0~255显示这里乘以16是为了放大差异便于观察 Disparity.atuchar(j, i) loc * 16; } // 打印进度 double rate double(i) / (Width); cout 已完成 setprecision(2) rate * 100 % endl; } return Disparity; }这段代码清晰地展示了SAD的流程但它存在几个关键问题在实际项目中必须解决边界处理粗糙直接continue跳过边缘像素会导致视差图尺寸小于原图且边缘信息丢失。正确做法是给输入图像进行边界填充如复制边缘像素或者计算时只遍历有效的中心区域并将视差图初始化为一个特殊值如-1。效率极低四层嵌套循环图像宽、高、视差范围、窗口像素是计算灾难。在CPU上即使处理640x480的图像winSize7, DSR50其计算量也难以满足实时性要求。未考虑亚像素精度找到的视差是整数像素级的精度有限。可以通过在最小代价点附近进行二次曲线拟合来获取亚像素级视差。没有唯一性约束如果搜索范围内有两个或多个位置代价非常接近算法会随机选择一个导致误匹配。通常需要加入“唯一性检测”比如要求最小代价比次小代价小一个比例阈值。3.1.2 SAD算法效果评估与实战心得运行你提供的代码需修复边界BUG后得到的视差图通常噪声很大在纹理平坦的区域会出现条带状或随机噪声在遮挡区域物体只在其中一个视图可见会完全失效。这是因为SAD只依赖于局部灰度的一致性对光照变化、噪声和纹理缺失没有任何鲁棒性。实操心得SAD算法在今天几乎不会直接用于最终的立体匹配但它有两个重要用途第一作为代价计算的基础单元被集成在更复杂的算法如SGBM中第二在硬件加速如FPGA、ASIC的早期设计中由于其计算规则简单非常适合用流水线实现用于对速度要求苛刻但精度要求不高的场景。在软件层面我们更需要关注如何优化它。一个立竿见影的优化是使用积分图像。我们可以预先计算好图像的积分图这样对于任意矩形窗口内像素值的求和操作都可以在O(1)时间内完成从而将计算复杂度从O(winSize^2)降为O(1)这是实现实时SAD的关键技巧。3.2 SSD算法一个理论上的改进SSDSum of Squared Differences原理与SAD几乎一致只是将代价计算从绝对值之和改为平方和。其数学公式为Cost Σ (L(x,y) - R(x-d, y))^2其中d为视差。理论上平方操作会对较大的差异给予更大的惩罚这有时能抑制一些偶然的大噪声点的影响。但在实际中由于平方计算更耗时且对亮度线性变化同样敏感其整体表现并不比SAD有质的提升甚至可能因为平方放大噪声而更差。因此在OpenCV等库中很少提供独立的SSD匹配器它更多是作为一种代价函数存在于理论讨论和某些定制化算法中。其代码实现只需将absdiff和sum步骤替换为对应像素差值的平方和即可此处不再赘述。3.3 SGBM算法工程应用的黄金标准当我们需要一个“开箱即用”且效果不错的立体匹配算法时OpenCV中的StereoSGBM类几乎是首选。它实现了Heiko Hirschmüller提出的半全局匹配思想。SGBM的核心在于它不再孤立地看待每个像素的匹配代价而是定义了一个考虑邻域平滑性的全局能量函数E(D) Σ C(p, Dp) Σ P1 * T[ |Dp - Dq| 1 ] Σ P2 * T[ |Dp - Dq| 1 ]这个公式是理解SGBM的钥匙Σ C(p, Dp)数据项。即所有像素p在其视差为Dp时的匹配代价之和通常用SAD或BT等计算。这部分追求每个点自身匹配代价最小。Σ P1 * T[ |Dp - Dq| 1 ]平滑项小惩罚。对相邻像素p和q如果它们的视差相差1则施加一个较小的惩罚P1。这允许视差图存在斜坡如倾斜表面。Σ P2 * T[ |Dp - Dq| 1 ]平滑项大惩罚。如果相邻像素视差变化大于1则施加一个较大的惩罚P2。这抑制视差的剧烈跳跃保持视差图的平滑但允许在物体边缘处视差不连续P2通常远大于P1。直接最小化这个全局能量函数是NP难问题。SGBM的巧妙之处在于使用多路径动态规划来近似求解。它沿着图像的多个方向通常为8或16个进行一维的动态规划然后将所有路径得到的代价相加最后为每个像素选择总代价最小的视差。这种“半全局”的策略在可接受的计算开销内极大地提升了匹配的鲁棒性和精度。3.3.1 OpenCV SGBM参数详解与调优指南下面我们深入你提供的SGBM代码每一个参数都直接影响最终效果。我将结合大量实测经验告诉你它们背后的含义和调优策略。// SGBM_Algorithm.h (核心参数设置部分) void calDispWithSGBM(Mat Img_L, Mat Img_R, Mat imgDisparity8U) { Size imgSize Img_L.size(); // 视差范围必须为16的整数倍。这里是一个自适应计算确保覆盖所需范围。 int numberOfDisparities ((imgSize.width / 8) 15) -16; PtrStereoSGBM sgbm StereoSGBM::create(0, 16, 3); // minDisparity, numDisparities, blockSize int cn Img_L.channels(); // 图像通道数灰度图为1彩色图为3 int SADWindowSize 9; // SAD窗口大小即blockSize int sgbmWinSize SADWindowSize 0 ? SADWindowSize : 3; // 1. 基础视差设置 sgbm-setMinDisparity(0); // 最小视差。如果相机有共面外的校正可设为负数。 sgbm-setNumDisparities(numberOfDisparities); // 视差搜索范围 numberOfDisparities // 2. 惩罚系数P1, P2 - 调参关键 sgbm-setP1(8 * cn * sgbmWinSize * sgbmWinSize); sgbm-setP2(32 * cn * sgbmWinSize * sgbmWinSize); // P1、P2控制平滑度。P2 P1。公式是经验值P18*cn*SADWindowSize^2, P232*cn*SADWindowSize^2是一个很好的起点。 // 增大P2会使视差图更平滑但可能模糊边缘减小P2能更好地保留边缘但噪声增多。 // 3. 后处理参数 - 消除错误匹配的利器 sgbm-setDisp12MaxDiff(1); // 左右一致性检查最大容差。检查左视差图与右视差图的对称性大于此值则视为无效。通常设为1或-1关闭。 sgbm-setPreFilterCap(31); // 预滤波器截断值。预处理阶段像素值被限制在[-preFilterCap, preFilterCap]内用于增强纹理。值越大保留的纹理越多但噪声也可能增多。典型值31或63。 sgbm-setUniquenessRatio(10); // 唯一性比率。这是抑制模糊匹配的关键参数 // 假设最佳匹配代价为C_min次佳匹配代价为C_sec。 // 只有当 C_sec C_min * (1 uniquenessRatio/100) 时最佳匹配才被接受。 // 增大该值如15匹配更严格视差图更稀疏很多点无效减小该值如5匹配更宽松视差图更稠密但错误可能增多。 sgbm-setSpeckleWindowSize(100); // 斑点滤波器窗口大小。视差连通区域小于此像素数的区域被视为噪声斑点将被剔除。 sgbm-setSpeckleRange(32); // 斑点滤波器视差变化阈值。在判断连通区域时相邻像素视差变化超过此值则认为不连通。 // 这对去除小的孤立噪声块非常有效。 // 4. 算法模式与窗口大小 sgbm-setMode(0); // 模式选择0SGBM, 1HH (使用更耗内存但可能更精确的方式) sgbm-setBlockSize(sgbmWinSize); // SAD代价计算窗口大小。这是最重要的参数之一 // 窗口小如3视差图细节丰富但噪声大。 // 窗口大如15视差图平滑噪声小但会损失细节且在物体边缘产生“膨胀”或“空洞”。 // 需要根据图像分辨率和纹理在速度和精度间权衡。通常5, 7, 9, 11是常用值。 // 计算视差16位有符号实际视差值为计算值/16.0 Mat imgDisparity16S Mat(Img_L.rows, Img_L.cols, CV_16S); sgbm-compute(Img_L, Img_R, imgDisparity16S); // 转换为8位无符号用于显示视差值被归一化到0-255 imgDisparity16S.convertTo(imgDisparity8U, CV_8U, 255 / (numberOfDisparities * 16.)); }3.3.2 SGBM参数调优实战经验调参是使用SGBM的必修课。没有一套参数放之四海而皆准必须根据你的具体场景调整。以下是我的经验总结blockSize(SAD窗口大小)这是首要调整参数。它直接决定了匹配的尺度。纹理丰富、高频细节多的图像如室内场景、树叶使用较小的窗口5或7以保留边缘和细节。纹理较弱、平滑区域多的图像如白墙、天空、路面使用较大的窗口9或11通过聚合更多像素信息来抑制噪声。但窗口太大会导致计算变慢并在前景物体边缘产生“前景膨胀”现象前景物体像晕开一样侵占了背景区域。你的实验完全验证了这一点从你提供的效果图对比可以看出SADWindowSize5时视差图噪声明显但物体轮廓相对清晰SADWindowSize15时噪声减少平面变得平滑但物体边缘变得模糊且背景出现了更多空洞黑色区域。SADWindowSize9是一个不错的折中点。P1和P2(惩罚系数)它们控制视差图的平滑度。保持比例通常P2是P1的3-5倍。OpenCV的默认公式P24*P1是一个安全的起点。调整绝对值如果视差图看起来“碎噪声”很多可以同时增大P1和P2比如按比例乘以1.5。如果物体边缘过于模糊或者不同深度物体边界粘连可以适当减小P2。通道数cn如果输入是彩色图像cn3P1和P2的计算会自动乘以3因为彩色图像每个像素的代价计算量更大需要相应增加惩罚力度以保持平滑效果。uniquenessRatio(唯一性比率)这是清理错误匹配最有效的参数。在纹理重复的区域如百叶窗、砖墙很容易出现匹配歧义产生“鬼影”或噪声。增大uniquenessRatio如调到15-20可以强制算法只接受那些匹配代价显著优于其他候选的像素从而让这些模糊区域变为无效点黑色得到更干净但可能更稀疏的视差图。如果你需要尽可能稠密的视差图即使有些错误可以减小此值如5。speckleWindowSize和speckleRange(斑点滤波)用于后处理去除小的孤立噪声区域非常有效。speckleWindowSize100意味着任何小于100个像素的连通视差区域都会被移除。如果你的图像中确实有小物体小于100像素这个值需要调小否则它们会被误删。speckleRange32意味着在判断连通性时相邻像素视差相差超过32乘以16之前的数值就认为不连通。这个值通常设置为视差范围numDisparities的1/4到1/2。避坑指南SGBM计算出的imgDisparity16S是16位有符号整数其真实视差值 像素值 / 16.0。这是因为算法内部为了保持亚像素精度将视差放大了16倍。如果你需要用于精确的三维坐标计算务必记得这个转换。直接使用imgDisparity8U进行显示没问题但用于计算会损失精度。4. 算法效果对比与场景化选型建议经过前面的原理剖析和代码实战我们已经对这三个算法有了深刻的理解。现在让我们站在更高的视角进行横向对比并给出在不同应用场景下的选型建议。4.1 三大算法综合性能对比为了更直观地展示我将它们的关键特性总结如下表特性维度SADSSDSGBM匹配原理局部窗口绝对差和局部窗口平方差和半全局能量函数最小化聚合多路径代价计算速度极快适合硬件并行快略慢于SAD中等比局部算法慢1-2个数量级但已高度优化匹配精度低噪声多弱纹理区失效低与SAD类似或略差高视差图完整、平滑抗噪声能力弱弱对高斯噪声稍好对椒盐噪声更差强依赖聚合与平滑约束纹理适应性依赖强纹理依赖强纹理能较好处理弱纹理区域参数复杂度少窗口大小、搜索范围少同SAD多窗口大小、P1/P2、唯一性比率等需精细调参输出视差图稀疏、噪声大稀疏、噪声大稠密、平滑OpenCV集成需手动实现或使用StereoBM基于SAD的变种无直接对应可手动实现StereoSGBM类功能完整从这个对比可以清晰地看到SGBM在精度和鲁棒性上全面碾压传统的局部算法。SAD/SSD更像是一种基础的代价度量工具而SGBM则是一个完整的、可用于实际产品的解决方案。4.2 不同应用场景下的算法选型策略如何为你的项目选择最合适的算法这完全取决于你的需求优先级。追求极致实时性对精度要求不高如机器人粗略避障、视频通话背景虚化的深度估计原型首选优化后的SAD算法结合积分图加速并运行在GPU或FPGA上。可以将图像金字塔下采样与之结合先在低分辨率图像上快速估计大范围视差再在高分辨率上细化。备选使用OpenCV的StereoBMBlock Matching它也是基于局部块匹配的快速算法并做了一些优化。精度要求高允许一定的计算延迟如自动驾驶的障碍物检测、工业三维尺寸测量、无人机地形重建绝对首选SGBM。这是目前工业界在CPU上实现实时或准实时立体视觉的事实标准。你需要花费主要精力在标定、校正和SGBM参数调优上。对于自动驾驶这类场景通常会在FPGA或专用ASIC上实现SGMSGBM的硬件友好版本算法以达到更高的帧率。离线处理追求最高精度如文物扫描、数字孪生城市建模、电影特效制作首选全局匹配算法或基于深度学习的立体匹配。例如OpenCV中的StereoVar变分法或学术界的ELAS、ADCensus等算法。近年来深度学习模型如GC-Net, PSMNet, RAFT-Stereo在多个公开数据集上达到了远超传统方法的精度虽然计算量大但对于离线任务是完全可行的选择。角色SGBM在这里可以作为快速生成初始视差图或作为深度学习网络后处理的一个参考。重要心得在真实项目中算法本身只占成功的一半。双目系统的硬件选型相机分辨率、基线距离、镜头质量、标定精度和立体校正效果往往更能决定最终三维重建的质量。一个常见的误区是花了大量时间调参却收效甚微最后发现是相机标定的重投影误差太大或者镜头存在严重的畸变未校正。务必确保前端几何校正的准确性这是所有立体匹配算法有效工作的基础。5. 双目立体视觉的现状、挑战与个人实战思考双目立体视觉走过了几十年的发展历程从实验室走向了广阔的产业应用但前路依然漫长。正如你文中提到的目标是达到“类似于人眼的通用双目立体视觉”这依然是一个巨大的挑战。5.1 当前面临的四大核心挑战从我个人的项目经验来看传统算法在落地时主要面临以下四个“拦路虎”弱纹理与重复纹理区域这是传统基于灰度/梯度方法的阿喀琉斯之踵。面对一面白墙、一片天空或规则排列的窗户SAD、SSD甚至SGBM都难以找到唯一的匹配点导致视差图出现大面积空洞或错误。目前主要通过引入特征点匹配、基于分割的区域增长或转向深度学习特征来缓解。遮挡问题由于视角差异场景中的某些部分只在一个相机中可见。对于被遮挡的点根本不存在正确的匹配任何算法都会给出错误结果。这需要通过左右一致性检查LR-Check来检测并剔除这些点但会导致视差图更稀疏。光照变化与反射左右相机曝光不一致、场景中有镜面反射或光源会导致同一物体在左右图中灰度值差异巨大严重破坏基于亮度恒定的假设。使用更鲁棒的代价函数如Census变换、归一化互相关NCC或预处理如直方图均衡化有一定帮助。实时性与精度的平衡SGBM在CPU上处理高清图像1080p仍难以达到高帧率如30fps。为了实时性往往需要降低分辨率、缩小视差搜索范围这必然损失精度。这推动了硬件加速GPU、FPGA、ASIC和算法并行化的研究。5.2 技术发展趋势与个人见解我认为双目立体视觉的未来发展将呈现软硬结合、多技术融合的态势算法层面深度学习正在彻底改变这个领域。基于端到端网络的方法如RAFT-Stereo不仅能学习更鲁棒的特征还能隐式地学习平滑约束和遮挡推理在困难场景下的表现远超传统方法。未来的方向可能是轻量化的网络设计以适应嵌入式设备的部署需求。系统层面多传感器融合是必然趋势。纯视觉在极端光照强光、黑夜、无纹理环境下会失效。将双目与IMU惯性测量单元、激光雷达或毫米波雷达融合利用IMU提供短时精准的运动预测利用雷达提供稀疏但绝对准确的深度点作为补充和校正可以构建更可靠、更鲁棒的感知系统。你文中提到的INDEMIND将视觉与多种传感器集成在一体化模组中正是这一趋势的体现。应用层面从“三维重建”走向“三维理解”。早期的双目视觉主要输出一张深度图或点云。现在和未来的重点是结合语义分割和实例分割让系统不仅能知道“哪里有什么”还能知道“那是什么”从而实现更高级的导航、避障和交互。例如机器人不仅能避开一个障碍物还能识别出它是一个椅子、一个人还是一只猫并采取不同的策略。在我自己的机器人导航项目中最终采用的方案是使用经过良好标定的工业双目相机在CPU上运行精心调参的SGBM算法获取稠密深度图同时运行一个轻量化的深度学习模型进行语义分割。将深度信息与语义信息叠加我们得到了一个“语义化的3D场景”机器人借此不仅能规划无碰撞路径还能识别出充电桩、门等特定物体大大提升了系统的智能性和实用性。这个过程充满了调试参数、处理异常数据和融合多源信息的挑战但当你看到机器人流畅地穿梭在复杂的室内环境中时那种成就感是无与伦比的。双目立体视觉这门让机器“睁开双眼”感知深度的技术其魅力与挑战正在于此。