
简介本资源是一套面向计算机视觉初学者与进阶学习者的立体匹配算法实践合集聚焦于深度估计核心任务覆盖SSD、SAD、ZNCC、BM和SGBM五种经典算法的Python完整实现适用于3D重建、自动驾驶感知、机器人导航等场景的算法理解与原型验证。压缩包共15个文件含5个核心算法脚本.py——分别封装各算法逻辑、参数配置与视差图生成流程以及10张可视化结果图.png包括各算法输出的灰度/伪彩色视差图直观对比匹配质量与细节表现。资源大小仅1.58MB轻量易用代码基于OpenCV实现注释清晰便于调试与二次开发。目前已有836人学习下载读者可直接运行获取端到端匹配结果深入理解代价计算、窗口搜索、归一化处理及半全局优化等关键机制并为后续改进或集成至实际系统提供可靠基线代码与可复现参考。1. 立体匹配项目要解决什么问题从视差图说起1.1 为什么需要立体匹配双目测距的核心环节如果你接触过双目视觉应该知道整个系统的最终目标往往是测出场景中每个点的深度。这个目标在工程上被拆成了几个环节相机标定、极线校正、立体匹配、三角测量。其中立体匹配是承上启下的核心——它负责在左右两张图像中找到同名点而视差图就是同名点匹配结果的直接产物。视差越大物体离相机越近视差越小物体越远。这个关系在矫正后的双目系统里是纯粹的几何关系所以视差图的准确性直接决定了后续深度计算的精度。我自己做双目测距项目时感受最深的一点是标定做得再准如果立体匹配这一步出来的是张斑驳陆离的视差图后面的三角测量再精确也救不回来。这也是为什么我把SAD、SSD、ZNCC、BM、SGBM这五个算法放在一起研究——它们是立体匹配最基础也最常用的一批方法其中前三个是代价计算算法后两个是完整的匹配算法。理解它们的原理和实现差异几乎就是理解立体匹配整个领域的钥匙。这篇文章我会把五个算法全部用Python落地给出可运行的代码、参数说明、实测效果对比以及我踩过的一些坑。适合的人群是正在做双目视觉入门、需要快速搭一个匹配算法跑通流程的开发者或者已经在用OpenCV但不太清楚底层在干什么的同学。1.2 五种算法的定位与整体选型思路先把这五个算法的关系理清楚。很多人刚开始容易混淆SAD和BM其实它们的层级完全不同。SAD、SSD、ZNCC是代价计算方法它们解决的是怎么衡量两个像素块像不像的问题BM和SGBM是完整的匹配算法它们在代价计算的基础上还包含代价聚合、视差选择、后处理等步骤。打个比方代价计算像是选材匹配算法才是完整的烹饪流程。从工程选型的角度看这五个算法的性能从低到高排序大致是SAD/SSD最基础自己实现方便→ ZNCC抗光照干扰更强→ BMOpenCV内置速度极快→ SGBM精度最高适用场景最广。我见过不少工业项目最终都用SGBM做主力算法主要是因为它在精度和速度之间取得了比较好的平衡。但如果你只是做实验室验证或者对实时性要求极高BM往往更合适。下面我会按照从代价计算到完整匹配算法的顺序逐个展开原理和代码实现。2. 基础代价计算SAD、SSD、ZNCC的原理与Python实现2.1 代价计算在立体匹配中的角色在立体匹配的流程里第一步是对左图像中的每个像素在右图像的同一条极线上搜索匹配点。搜索的依据就是计算当前像素周围一个窗口与候选像素周围窗口的相似度这个相似度的反义就是代价。代价越小说明两个窗口内容越接近匹配置信度越高。搜索范围内所有候选位置都会得到一个代价值这些代价值连起来就构成了一个代价体。这个代价体的质量决定了整个匹配管线的上限。代价计算如果能做到在不同光照、不同噪声条件下依然稳定区分正确匹配和错误匹配后面的聚合和优化步骤就能省很多力气。相反如果代价本身充满噪声后面无论用什么高级优化手段都容易把错误的匹配优化成一个局部一致但整体错误的视差图。SAD、SSD、ZNCC都是基于像素灰度值的窗口相似度度量。它们的共同点是计算流程相似左图取一块区域右图在搜索范围内取同样大小的区域逐像素作差再汇总。区别在于汇总的方式不同导致它们对光照变化、噪声的敏感程度完全不同。2.2 SAD与SSD最朴素的相似度度量SAD全称是Sum of Absolute Differences也就是绝对差之和。它的公式表达是C(x, y, d) Σ|L(xi, yj) - R(xi-d, yj)|这里(x, y)是左图像素坐标d是视差值(i, j)是窗口内的偏移量。SAD把窗口内每个像素的灰度差取绝对值再求和值越小说明两个窗口越相似。SSD全称是Sum of Squared Differences即差值的平方和C(x, y, d) Σ(L(xi, yj) - R(xi-d, yj))²SSD和SAD的差异在于差值被平方了。这个看似微小的改动带来几个实际影响首先大差值会被放大所以SSD对离群像素更敏感如果窗口内有一个像素因为噪声产生较大偏差它会显著拉高总代价其次平方运算让代价函数在最小值附近更加尖锐理论上视差选择的区分度更高但在噪声大的场景里这反而容易选到错误的极小值。这两个算法的Python实现非常直白。我用numpy写过一个滑动窗口版本的SAD核心逻辑是双层循环遍历视差范围每个视差下用np.abs和np.sum做窗口求和。这种写法虽然效率不高但胜在逻辑清晰适合理解算法本质。实际工程里可以用图像积分图或者卷积来加速后面我会专门讲。2.3 ZNCC抗光照变化的选择ZNCC全称是Zero-mean Normalized Cross-Correlation零均值归一化互相关。它和SAD/SSD有本质区别SAD/SSD度量的是差ZNCC度量的是相似——它的值越大说明两个窗口越相似。ZNCC的公式是C(x, y, d) Σ[(L(i) - L̄)(R(i) - R̄)] / (n · σ(L) · σ(R))其中L̄和R̄是窗口内灰度均值σ是标准差。这个公式做了两件关键的事情减均值消除了窗口整体的亮度偏移影响除以标准差消除了对比度差异的影响。这意味着即使左右相机曝光参数不同、或者场景光照不均匀ZNCC依然能保持相对稳定的匹配质量。代价是计算量明显增加。每个窗口不仅要算均值还要算标准差一帧图像下来累计的开销比SAD高出一截。我在实际项目里用ZNCC的场景是室内补光不均匀、左右相机白平衡有差异的场合这种环境下SAD和SSD的表现往往比较糟糕而ZNCC能撑住。2.4 三个算法的Python代码落地与实测对比下面是我自己写的一个基础实现用numpy完成SAD、SSD和ZNCC的代价计算。窗口大小我设为7x7搜索视差范围0到64。import numpy as np import cv2 def sad_cost(left, right, max_disp, win_size): h, w left.shape pad win_size // 2 cost_volume np.zeros((h, w, max_disp), dtypenp.float32) left_pad cv2.copyMakeBorder(left, pad, pad, pad, pad, cv2.BORDER_REPLICATE) right_pad cv2.copyMakeBorder(right, pad, pad, pad, pad, cv2.BORDER_REPLICATE) for d in range(max_disp): for i in range(h): for j in range(w): left_win left_pad[i:iwin_size, j:jwin_size] right_win right_pad[i:iwin_size, jd:jdwin_size] cost_volume[i, j, d] np.sum(np.abs(left_win.astype(np.float32) - right_win.astype(np.float32))) return cost_volume注意我从成本体开始存这个形状是(h, w, max_disp)。每层切片对应一个视差值下的代价图。SAD的实现里有个容易踩的细节图像要先转成float32再相减否则uint8的减法在负数时会出现截断导致代价全是0或者出奇怪的结果。SSD就是把np.abs换成平方。ZNCC的实现稍微复杂一些要提前算窗口的均值和方差。我一般用cv2.boxFilter做窗口求和来加速均值计算标准差的计算也是基于E(x²) - E(x)²这个恒等式def zncc_cost(left, right, max_disp, win_size): h, w left.shape pad win_size // 2 cost_volume np.zeros((h, w, max_disp), dtypenp.float32) # 计算窗口求和和窗口平方求和 box np.ones((win_size, win_size), dtypenp.float32) / (win_size * win_size) left_mean cv2.filter2D(left.astype(np.float32), -1, box) right_mean cv2.filter2D(right.astype(np.float32), -1, box) left_sq_mean cv2.filter2D(left.astype(np.float32)**2, -1, box) right_sq_mean cv2.filter2D(right.astype(np.float32)**2, -1, box) left_std np.sqrt(left_sq_mean - left_mean**2 1e-8) right_std np.sqrt(right_sq_mean - right_mean**2 1e-8) for d in range(max_disp): shifted np.zeros_like(right, dtypenp.float32) if d 0: shifted[:, d:] right[:, :-d] else: shifted right.astype(np.float32) # 计算互相关项的窗口求和 shifted_mean cv2.filter2D(shifted, -1, box) cross cv2.filter2D(left.astype(np.float32) * shifted, -1, box) cov cross - left_mean * shifted_mean denom left_std * np.sqrt(np.maximum(shifted_sq_mean - shifted_mean**2, 0) 1e-8) cost_volume[:, :, d] cov / denom return cost_volume注意这里存在一个重要的细节ZNCC的匹配结果是越大越相似所以在后续选择视差时要取argmax而不是argmin这个和SAD/SSD正好相反。很多人第一次实现ZNCC会在这一步搞反出来的视差图就是反的或者全黑的。实测下来在光照均匀的Middlebury数据集上SAD和SSD的精度差不太多SSD在边缘处偶尔更干净一点但如果对左图加了一个灰度偏移模拟左右相机曝光差异SAD和SSD的错误率会明显上升ZNCC基本不受影响。代价是ZNCC在纹理稀疏区域更容易出现噪声因为它对像素值变化太敏感平坦区域的归一化计算不稳定。3. BM与SGBM从代价聚合到全局优化3.1 BM算法的工作机制与参数解读BM的全称是Block Matching块匹配算法。它本质上就是SAD/SSD这类窗口代价计算加上一个简单的视差选择策略对每个像素在所有候选视差中选代价最小的那个作为最终视差。OpenCV的StereoBM实现还包含一些额外的预处理和后处理步骤比如中值滤波、唯一性检测、纹理过滤等但核心思想仍然是最小代价搜索。有一说一BM算法在理论层面的头脑非常简单它的特点就是快。因为每个像素的视差选择是独立的整个过程很容易并行化这也是为什么早期的实时双目系统几乎都用这个算法。我做过一个D435i相机的实时测距demo图像分辨率640x480BM在普通笔记本CPU上能跑到20ms左右一帧这个速度对于原型验证非常舒服。OpenCV中StereoBM的参数有几个关键项numDisparities最大视差值必须是16的倍数。这个值决定搜索范围。blockSize匹配窗口大小必须是奇数一般在5到21之间。preFilterType、preFilterSize预处理参数用于增强匹配区域的纹理。uniquenessRatio唯一性比率表示最小代价和次小代价的差异要超过这个百分比才接受匹配。设得越小算法越激进设得越大视差图越稀疏但越可靠。speckleWindowSize和speckleRange去斑参数用于过滤掉小的孤立噪声区域。我平时调BM的顺序是先定numDisparities根据场景最前景和最近景的视差范围选一个合适的值然后调blockSize纹理丰富的场景用小窗口比如5或7纹理稀疏的场景用大窗口比如15但窗口太大会丢失边缘细节最后调uniquenessRatio从10开始往下试。3.2 SGBM半全局匹配原理为什么它比BM稳SGBM的全称是Semi-Global Block Matching半全局块匹配。它在BM的基础上引入了一个极其关键的改进代价聚合阶段考虑了相邻像素视差的连续性约束。具体来说它沿着多条方向路径通常是8个方向或4个方向传播代价聚合时对相邻像素视差变化做惩罚如果相邻像素的视差差值为0不惩罚如果差值为1加上一个较小的惩罚P1如果差值大于1加上一个较大的惩罚P2。这个设计的直观理解是真实世界中大多数物体表面是连续的所以邻近像素的视差应该平滑变化。SGBM利用这个先验把孤立像素的错误匹配通过路径聚合修正掉输出的视差图在平滑区域更连续、边缘也更干净。SGBM还有一个重要的变体叫SGM它使用互信息作为代价度量而SGBM默认使用的是BT代价Birchfield-Tomasi这个代价对噪声鲁棒性更好。OpenCV的StereoSGBM接口同时支持这两种模式但默认用BT实际效果也很好。我在项目中用SGBM最大的感受是它输出的视差图块状感明显比BM小边缘轮廓更准确。但这不代表SGBM是万能的——它对参数很敏感尤其是P1和P2的设置。这两个参数如果设得太小视差图会碎噪声多设得太大视差图会过度平滑把物体的边缘细节抹掉甚至会在深度不连续区域产生膨胀现象。3.3 OpenCV中BM与SGBM的调用方式与调参下面是我的BM和SGBM调用代码直接跑就能用import cv2 import numpy as np def compute_bm(left_gray, right_gray): stereo cv2.StereoSGBM_create( minDisparity0, numDisparities64, blockSize11, P18 * 3 * 11 ** 2, P232 * 3 * 11 ** 2, disp12MaxDiff1, uniquenessRatio10, speckleWindowSize100, speckleRange32, preFilterCap63, modecv2.STEREO_SGBM_MODE_SGBM ) disparity stereo.compute(left_gray, right_gray).astype(np.float32) / 16.0 return disparity def compute_bm(left_gray, right_gray): stereo cv2.StereoBM_create(numDisparities64, blockSize11) stereo.setUniquenessRatio(10) stereo.setSpeckleWindowSize(100) stereo.setSpeckleRange(32) disparity stereo.compute(left_gray, right_gray).astype(np.float32) / 16.0 return disparity调参方面我最常用的套路是先用SGBM的默认方式跑一遍看视差图整体大概什么水平然后按下面的顺序做针对性调整如果视差图空洞太多优先加大blockSize或者适当调小uniquenessRatio。如果视差图有横向长条纹说明P2太大了试着把P2降到8 * 3 * blockSize²。如果物体边缘有光晕感把disp12MaxDiff从1调小到0同时检查是否有遮挡区域。如果小物体被抹掉了检查speckleWindowSize是否过大一般100以内比较合理。需要特别注意的是OpenCV的compute输出是定点数需要除以16.0才是真正的浮点视差值。这个细节教科书里很少提但实际用的时候如果忘了除视差图会整体偏亮数值全偏大测距结果全错。我第一次用SGBM就栽在这里后来排查了很久才发现是单位换算的问题。4. 实操完整流程与效果调优4.1 完整可运行的Python实现流程为了让你能直接上手我把完整流程整理成一个可运行的脚本。这里我用Middlebury数据集的Tsukuba图像作为示例你也可以替换成自己采集的左右图。整条流程包含图像读取、灰度转换、算法执行、视差图后处理、结果可视化五个步骤。import cv2 import numpy as np def load_images(left_path, right_path): left cv2.imread(left_path, cv2.IMREAD_GRAYSCALE) right cv2.imread(right_path, cv2.IMREAD_GRAYSCALE) assert left.shape right.shape, 左右图像尺寸不一致 return left, right def wls_filter(disparity, left, right, sigma1.5, lmbda8000.0): wls cv2.ximgproc.createDisparityWLSFilter( cv2.StereoSGBM_create(numDisparities64, blockSize11) ) wls.setLambda(lmbda) wls.setSigmaColor(sigma) right_matcher cv2.ximgproc.createRightMatcher( cv2.StereoSGBM_create(numDisparities64, blockSize11) ) disparity_left wls.filter(disparity, left, disparity_map_rightNone) return disparity_left def visualize(disparity, max_disp64, save_pathNone): disp_vis cv2.normalize(disparity, None, 0, 255, cv2.NORM_MINMAX) disp_vis cv2.applyColorMap(disp_vis.astype(np.uint8), cv2.COLORMAP_JET) if save_path: cv2.imwrite(save_path, disp_vis) return disp_vis left, right load_images(tsukuba_left.png, tsukuba_right.png) disparity_sgbm compute_sgbm(left, right) disparity_bm compute_bm(left, right) disparity_wls wls_filter(disparity_sgbm.astype(np.float32) * 16, left, right) visualize(disparity_sgbm, save_pathsgbm.png) visualize(disparity_bm, save_pathbm.png) visualize(disparity_wls, save_pathsgbm_wls.png)这段代码里我额外用了WLS滤波这个后处理对SGBM的效果提升很明显我会在下一节详细说。一个要注意的点是如果我只想单独跑SAD/SSD/ZNCC来对比效果可以直接用2.4节的代价体然后对代价体做以下转换# SAD/SSD: 取最小代价对应的视差 disp_sad np.argmin(cost_volume_sad, axis2) # ZNCC: 取最大相关性对应的视差 disp_zncc np.argmax(cost_volume_zncc, axis2)但直接用argmin选出来的视差图往往噪声很大。这是因为没有任何平滑约束每个像素独立决策一点微小的灰度扰动就会让视差跳到完全不同的值。这也是为什么BM和SGBM这类完整算法要做代价聚合和后处理——它们输出的视差图才有实际使用价值。4.2 视差图后处理WLS滤波与无效点修复这里我多说一句WLS滤波的原理。WLS是Weighted Least Squares的缩写中文叫加权最小二乘滤波。它的作用是让视差图在颜色相近的区域保持平滑在颜色梯度大的地方保留边缘。直观理解是如果左右图中同一物体表面的颜色连续那么这些位置的视差也应该连续变化WLS就利用这个先验来平滑视差图。我做过一个对比实验用SGBM直接输出视差图再用经过WLS滤波的视差图做测距测距误差大约能降低20%到30%尤其是在物体边缘和低纹理区域视觉上的改善非常明显。WLS的lambda和sigmaColor是两个核心参数lambda控制平滑强度越大越平滑sigmaColor控制颜色差多大算边缘越小越容易保留细节。我一般从lambda8000、sigma1.5开始调。视差图里经常出现的黑点无效视差也需要补全。最常见的原因是匹配失败或遮挡。一个工程上常用的修复方法是使用彩色图像做引导的中值滤波def fill_disparity(disparity, valid_threshold1): # 将无效视差标记为NaN disp_filled disparity.copy() invalid_mask disparity valid_threshold # 使用cv2.inpaint或者简单的中值替换 if np.sum(invalid_mask) 0: kernel np.ones((5, 5), np.uint8) dilated cv2.dilate(disparity, kernel) disp_filled[invalid_mask] dilated[invalid_mask] return disp_filled这个方法不算特别严谨但胜在简单。注意如果是为了做精确测距不建议随随便便填充无效视差——空洞区域本来就是因为遮挡或弱纹理导致的不可靠数据填充出来的数值只能作为一种视觉上的补全不能当作真实测量结果。但如果只是为了人眼查看或者做后续的物体分割补全一下会舒服很多。4.3 精度与耗时的权衡实测这里我把五种算法在同一对测试图像上的表现列一个表方便你做选型参考。测试环境是i5-8250U笔记本CPU图像分辨率768x432numDisparities64窗口大小为9x9针对SAD/SSD/ZNCC。算法平均耗时ms匹配质量抗光照能力适用场景SAD850一般弱教学演示、简单实时系统SSD820一般偏上弱教学演示、简单实时系统ZNCC1450较好强光照不均匀场景BM30中等中等实时测距、机器人导航SGBM120好较强高精度测距、三维重建注意SAD/SSD/ZNCC的耗时是我用纯numpy双层循环实现的结果所以非常慢。如果你用numba或者写成向量化卷积的形式可以把耗时降到几十毫秒级别。但即便如此在同样的图像上SGBM的精度一般还是优于它们的。从表格可以看到BM在速度上有压倒性优势SGBM用3到4倍的时间换取明显更好的质量。在我实际做三维重建项目时离线处理选SGBM实时导航选BM这是一个比较通用的经验法则。5. 常见问题与排查记录5.1 视差图出现大片黑色空洞这是大家在实现过程中遇到最多的现象。空洞最可能的原因是搜索范围设置得太小导致真正正确的匹配点不在搜索范围内算法找不到就把该点标记为无效。排查时先确认numDisparities是否覆盖了实际场景的视差范围。我通常会在场景中放一个已知距离的目标物反算它对应的视差值然后把numDisparities设为这个值的1.5倍左右留出余量。另一种常见情况是纹理太稀疏比如纯色墙面、天空、光滑地板。这一类区域无论哪个匹配算法都很难找到可靠对应点。应对方法是对图像做预处理增强纹理比如用直方图均衡化、CLAHE或者更换窗口大小试试。对于SGBM还可以调小P2来保留更多细节减少把平滑区域误判为遮挡造成的空洞。还有一种特殊情况是左右图没有做好极线校正。如果校正矩阵有问题左右两幅图的极线对不齐匹配就会大面积失败。这时候先检查OpenCV的undistort和remap是否正确执行在调试时可以把左右图上下拼在一起逐行检查对应目标是否在同一条水平线上。别忽略这一步很多空洞问题根源其实是校正没做好。5.2 边缘处视差跳变严重物体边缘的视差跳变是立体匹配的经典难题。原因在于匹配窗口跨越了深度不连续区域——窗口的一部分覆盖前景物体另一部分覆盖背景算出来的代价是混合的误差自然就大。窗口越大问题越明显所以如果你发现边缘特别毛糙可以适当减小blockSize。SGBM的P2参数也值得调整。P2太大时算法为了保持平滑性会惩罚视差突然变化导致物体边缘被压平看起来像前景和背景糊在一起。这种情况把P2减小一点边缘会锐利很多但代价是平坦区域的噪声会增加。你可以试试不同的P2并配合WLS滤波效果会平衡很多。还有一个容易被忽略的因素是左图和右图的一致性检查left-right check。OpenCV的disp12MaxDiff参数就是用来控制左右一致性检验的容差的。它通过计算右图到左图的视差再验证左右视差一致性来剔除错误点。将这个值设小一点比如1可以干掉大部分在边缘区域出现的错误匹配代价是视差图会变稀疏但这也是可以接受的因为被剔除的点比错误匹配更有价值。5.3 负视差和错误匹配怎么处理负视差指的是计算出来的视差小于minDisparity或者在某些区域视差为负数。这通常意味着匹配点被错误地对齐到了比实际更远的位置或者极线校正后视差范围的偏移没处理好。OpenCV中minDisparity默认是0也就是假设所有物体都在无穷远到某个近处范围内。如果你的场景包含极近的物体需要把minDisparity设为负值比如-16。错误匹配还有一种很常见的形式是周期性纹理干扰比如百叶窗、栅栏、布料纹理。这种场景里不同的位移周期对应的代价都很低算法很难区分哪个才是真实视差。SGBM对这种情况有一点改善但不彻底。我的建议是尽量不要在强周期纹理场景下依赖这些基础算法确实有需求的话需要引入更高级的形状先验或者多视角信息。另外如果发现视差图里出现明显的横向倾斜条纹多半是P2设置过大导致路径聚合时过度平滑把不同深度的平面连成了一条斜线。这时候把P2降低同时可以把mode从STEREO_SGBM_MODE_SGBM切换成STEREO_SGBM_MODE_HH试试。HH模式是更严格的全局变体速度更慢但精度更高。5.4 性能优化方向最后谈一下性能优化如果你需要把这套算法跑进实时系统这里有几个方向可以参考。第一是图像缩放。视觉匹配的时间复杂度随像素数量线性增长把图像缩放到原来的一半耗时基本上能降到四分之一。在机器人导航场景里1280x720的图缩放到640x360再用BM跑精度损失并不大但速度提升非常可观。第二是ROI裁剪。如果你的应用场景关心的只是画面中的某个区域比如传送带上的工件或者车辆前方的路面就只对这部分区域做匹配。这样既能减少计算量还能提高匹配可靠性因为ROI之外的复杂纹理不会再干扰搜索。第三是使用GPU加速。OpenCV的cuda模块里有cuStereoSGBM和cuStereoBM效果和CPU版本基本一致但速度快一个数量级。我自己在Jetson系列开发板上跑过640x480的SGBM大概能到30fps实用性很强。如果项目没有GPU条件还可以考虑把SAD/SSD用numba的jit或者Cython重写在CPU上也能提速10倍以上。还有一个很多人不知道的技巧是在视差搜索时可以使用上一帧的视差作为下一帧的先验缩小搜索范围。这个在视频序列里特别有效因为相邻帧的视差变化通常很小。实现起来也不复杂就是用一个稀疏光流或者简单的恒速模型把上一帧视差附近的一个小区间作为当前搜索范围。踩过的坑与个人体会我用了很长时间才真正把这些算法吃透最大的体会是立体匹配的难点从来不在公式理解上而在工程细节里。同一个SGBM算法有人调出来效果很好有人调出来就是一张大花脸区别往往就靠几个关键参数和对数据预处理的理解。建议你在学习时一定要动手跑一遍代码然后改参数去看视差图的变化把每个参数的影响都记下来。这个手感比看十篇原理文章都有用。另外分享一个我常用的调试小技巧在跑匹配之前先观察一下左右图的灰度直方图。如果两幅图的直方图差异很明显说明左右相机的曝光差异较大这时候优先选择ZNCC作为代价函数或者先用直方图匹配做一次预处理。这个操作我没见过有教程提但实测对匹配效果帮助很大。最后如果你打算把这篇文章里的算法用于具体项目我建议先想清楚你的瓶颈是精度还是速度。如果是精度重点研究SGBM的参数调优和WLS后处理如果是速度直接上BM并考虑缩小图像尺寸。基础算法虽然简单但当你真正理解了它们的优缺点就有了在复杂场景里做组合和改造的底气。本文还有配套的精品资源点击获取