双目校正必须做,否则立体匹配输出全是噪声;需用stereoCalibrate和stereoRectify完成极线校正,再用reprojectImageTo3D结合Q矩阵获取真实深度。

双目校正必须做,否则 cv::stereoBM 或 cv::stereoSGBM 输出全是噪声
没做过极线校正(rectification)的左右图直接送进立体匹配算法,匹配点根本不在同一行上,算法会强行“拉平”找错位置,深度图看起来像电视雪花。OpenCV 要求输入必须是已校正图像——即左右图的扫描线严格对齐(epipolar lines = horizontal rows)。这步不能跳过,也不能靠后期滤波补救。
实操建议:
- 用
cv::stereoCalibrate一次性标定两相机内参 + 外参 + 旋转平移关系,再调cv::stereoRectify得到校正映射矩阵R1,R2,P1,P2 - 用
cv::initUndistortRectifyMap生成重映射图,再用cv::remap对每帧左右图实时校正 - 校正后务必用
cv::drawEpipolarLines叠加几条极线验证:所有线必须水平且左右一一对应 - 如果只有一组标定参数但需处理多组图像,保存
R1,R2,Q(重投影矩阵)到 YAML/JSON,避免重复计算
cv::StereoSGBM 比 cv::StereoBM 更可靠,但参数调不好反而更糊
cv::StereoBM 是块匹配(Block Matching),速度快但对纹理缺失、重复图案、倾斜面非常敏感;cv::StereoSGBM(Semi-Global Block Matching)通过跨方向代价聚合提升鲁棒性,是实际项目首选。但它对参数更敏感,尤其以下三项:
-
minDisparity:通常设为 0,但若基线大或最近物距远,可设为正数(如 32)避免无效近处匹配 -
numDisparities:必须是 16 的倍数(如 96、128),值越大理论深度分辨率越高,但内存和耗时剧增;室内场景 64–96 足够,室外建议 128+ -
disp12MaxDiff:左右一致性检查阈值,设太小(如 1)会砍掉大量有效点,设太大(如 50)则引入错误匹配;实测 10–16 较稳 - 别忽略
uniquenessRatio(默认 15):低于该值的次优匹配会被丢弃,弱纹理场景可降到 5,但会增加噪点
示例初始化:
立即学习“C++免费学习笔记(深入)”;
cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(
0, 96, 3, // minDisparity, numDisparities, blockSize
8 * 3 * 3, // P1: 视差变化平滑项(小图用 8*3*3,大图可升到 8*5*5)
32 * 3 * 3, // P2: 视差连续性惩罚项(一般为 P1 的 4 倍)
1, 10, // disp12MaxDiff, uniquenessRatio
1000, 32 // speckleWindowSize, speckleRange
);深度图不是直接输出,要靠 cv::reprojectImageTo3D + Q 矩阵换算
立体匹配返回的是视差图(disparity map),单位是像素,不是毫米或米。想得到真实世界 XYZ 坐标,必须用校正阶段得到的 Q 矩阵(4×4 重投影矩阵)做转换。漏掉这步,所谓“深度图”只是伪彩色视差图,数值无物理意义。
-
cv::reprojectImageTo3D(disparity, xyz, Q)输出的是三维点云(CV_32FC3),其中第三通道xyz.at<:vec3f>(y,x)[2]</:vec3f>才是 Z(深度,单位与标定时的棋盘格尺寸一致,如 mm) - 若只要单通道深度图(Z 值),提取第三通道后注意:OpenCV 默认把无效点(视差 ≤0)设为
std::numeric_limits<float>::quiet_NaN()</float>,后续用cv::isfinite()过滤或用cv::threshold清洗 -
Q中的Q[2][3]和Q[3][2]隐含了焦距和基线乘积(f×B),若标定时棋盘格单位是 cm 但你要 mm 输出,得手动缩放整个Q矩阵
实际部署时,CPU 上跑 StereoSGBM 很慢,别硬扛
在 640×480 图像上,cv::StereoSGBM 默认参数在普通 i5 CPU 上约 300–500ms/帧,无法满足实时(≥15fps)需求。优化不是调低 blockSize 就完事——那会直接崩精度。
- 先降分辨率:用
cv::pyrDown缩到 320×240 再匹配,结果用cv::resize上采样,速度提升 3–4×,深度图质量损失可控 - 禁用
speckleFilter(设speckleWindowSize=0):该滤波在 CPU 上极耗时,后处理用形态学开运算或中值滤波替代更高效 - 若硬件支持 OpenCL,编译 OpenCV 时打开
WITH_OPENCL,并确保输入 Mat 用cv::UMat,部分步骤可加速 2× - 真正要上产品,考虑用 CUDA 加速版(如
cv::cuda::StereoBM),但需 NVIDIA GPU 和额外移植成本
校正和匹配之间存在强耦合:改一个标定参数,整个 Q 矩阵变,深度尺度就偏。调试时一定固定标定流程,不要边调匹配边动相机位置。


















