简介:这是一份面向计算机视觉、机器人导航与工业测量等领域开发者的三维重建实战资源,完整覆盖摄像头标定、双目立体校正、视差计算、点云生成与体积估算的关键流程。压缩包共5个文件,包含3个C++源文件、1个头文件及1份README说明,约12KB,代码结构精简,适合已掌握基础OpenCV用法、希望快速跑通双目视觉Pipeline的初中级工程师参考。当前已有136人学习下载。资源中的标定模块用于求解相机内参、畸变系数及外参;立体校正模块负责左右图像极线对齐与视差匹配;点云与体积计算部分则基于视差图生成三维坐标并估算目标占据体积。README对编译环境与调用步骤进行了说明,便于读者按顺序复现实验,省去从零搭建的摸索时间。
1. 三维重建资源拆解:一套 C++ 双目代码把标定、校正、点云、体积串成完整链路
这份压缩包拆开之后是四个 C++ 文件加一个 README:test.cpp、single_calib.h、single_calib.cpp、stereo_calib_match.cpp。名字起得很直白,但内容比名字值钱——它把三维重建里最容易卡住人的四个环节完整串了一遍:摄像头标定、双目立体校正、视差计算、点云生成与体积测量。多数教程讲到标定就停了,或者贴着原理讲完立体匹配就不管后续,这套代码是直接奔着"算出体积"去的,适合手里有双目相机、要做物体测量或机器人抓取的工程师,也适合拿来做毕业设计的完整框架。一个反直觉的结论先放在这:标定重投影误差做到 0.1 像素,重建出来的体积照样可能差 20%,问题往往出在立体校正和视差尺度转换这两个看起来不起眼的环节上。
2. 摄像头标定:single_calib.cpp 的内参求解与重投影误差检查
2.1 标定到底在解什么:内参、外参与畸变系数的物理含义
摄像头标定的输出是三样东西:内参矩阵、畸变系数、外参。内参矩阵里最关键的是fx、fy、cx、cy四个数。fx不是焦距的物理长度,而是焦距除以单个像素的物理尺寸,单位是像素——比如传感器单个像素 3.45μm、镜头焦距 8mm,那fx = 8000 / 3.45 ≈ 2318像素。cx、cy是主点,理想情况下在图像正中心,实测偏个几十像素都正常,但如果偏离到图像宽度的四分之一以上,基本可以判定标定数据有问题。
畸变系数这里常用的是k1、k2、p1、p2,分别对应径向畸变和切向畸变。径向畸变是镜头曲面造成的"桶形/枕形"变形,切向畸变是镜头与传感器不平行造成的。OpenCV 的calibrateCamera内部用的畸变模型还包含k3(有时到k6),对小视场镜头k3贡献很小,建议在标定时直接用CALIB_FIX_K3把它固定为 0,减少参数间的耦合,否则内参和畸变系数互相补偿,RMS 很漂亮但实际矫正效果是歪的。
单目标定这一步还有一个容易被忽略的产物:外参。每张标定板照片都会得到一组旋转向量rvec和平移向量tvec,表示拍摄瞬间棋盘格在相机坐标系下的位姿。单目标定里外参只服务于这张图,但如果后面要做双目,左右相机各自的标定误差会直接带进立体外参计算,所以单目标定这步的质量直接决定后续所有环节的上限。
2.2 single_calib.cpp 核心流程:从角点检测到 calibrateCamera
single_calib.cpp的流程和我在项目里常用的写法一致:对每张棋盘格图像做角点检测、亚像素细化,然后收集全部图像的内角点坐标和对应的三维物理坐标,一次性丢给calibrateCamera。核心代码可以浓缩成这样:
#include <opencv2/opencv.hpp> #include "single_calib.h" using namespace cv; using namespace std; // boardSize 是内角点数量,例如棋盘格是 10x7 的格子,这里传 (9, 6) vector<Point3f> generateObjectPoints(const Size& boardSize, float squareSize) { vector<Point3f> pts; for (int r = 0; r < boardSize.height; r++) for (int c = 0; c < boardSize.width; c++) pts.emplace_back(c * squareSize, r * squareSize, 0.0f); // Z=0 平面 return pts; } bool calibrateFromImages(const vector<string>& paths, const Size& boardSize, float squareSize, Mat& K, Mat& dist, vector<Mat>& rvecs, vector<Mat>& tvecs) { vector<vector<Point2f>> cornerList; vector<vector<Point3f>> objectList; Size imageSize; for (const auto& p : paths) { Mat gray = imread(p, IMREAD_GRAYSCALE); if (gray.empty()) continue; imageSize = gray.size(); vector<Point2f> corners; bool found = findChessboardCorners(gray, boardSize, corners); if (!found) continue; // 检测不到就跳过这张图,不强求 // 亚像素细化:角点精度从像素级提升到亚像素级 cornerSubPix(gray, corners, Size(5, 5), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.01)); cornerList.push_back(corners); objectList.push_back(generateObjectPoints(boardSize, squareSize)); } if (cornerList.size() < 10) return false; // 少于 10 张有效图,标定结果不可信 double rms = calibrateCamera(objectList, cornerList, imageSize, K, dist, rvecs, tvecs, CALIB_FIX_K3); // 固定 k3,减少参数耦合 printf("RMS = %.4f px\n", rms); return rms < 0.3; // 我一般以 0.3 像素为经验阈值 }这里的两个关键参数:boardSize必须传内角点数而不是格子数。10x7 格的标定板,内角点数是 9x6,传错的话findChessboardCorners大概率检测失败,或者标定出的内参严重失真。squareSize是棋盘格格子的物理边长,单位毫米,这个值决定外参平移向量的尺度,也间接影响双目基线的单位——如果标定板实际是 30mm 格子但你填了 25,重建出来的所有三维坐标会整体缩小,体积自然跟着错。
有效图像数量建议不少于 15 张,并且拍摄时要让标定板出现在画面的不同位置、不同倾角,尤其是画面边缘和四角。标定板要占画面面积的 20% 以上,太小了角点亚像素精度不够。整个流程跑完后打印一张表,列出每张图的角点数量和重投影误差,这张表比 RMS 更能反映问题出在哪张图。
2.3 用逐图重投影误差代替 RMS 判断标定质量
RMS 是calibrateCamera返回的全局平均,把所有图的角点误差揉在一起算了个均方根。实际踩过坑的都知道,这个数字有时候会骗人——某张图误差 0.8 像素,其余图误差 0.05,平均下来 RMS 可能只有 0.2,看着合格,但那张坏图如果恰好覆盖了画面左下角区域,畸变系数就会被带偏。
我一般标定完会把每张图的重投影误差单独算出来,逐个检查:
// 逐图计算重投影误差,定位是哪张图标定得差 for (size_t i = 0; i < cornerList.size(); i++) { vector<Point2f> projPts; projectPoints(objectList[i], rvecs[i], tvecs[i], K, dist, projPts); double err = 0.0; for (size_t j = 0; j < projPts.size(); j++) err += norm(cornerList[i][j] - projPts[j]); // 欧氏距离,单位像素 err /= cornerList[i].size(); printf("Frame %zu: mean reproj err = %.3f px\n", i, err); }projectPoints是把标定时算出的三维点,用当前的外参、内参、畸变系数重新投影回图像平面,和检测到的角点坐标做差。正常一张清晰的棋盘格图,平均误差应该在 0.1 像素以内,超过 0.3 像素就要警惕:要么这张图有运动模糊,要么标定板本身有轻微弯曲,要么角点检测时亚像素迭代没收敛。找出这几张坏图,从列表里剔除后重新标定,比闷头重拍 20 张图更高效。
3. 双目立体校正:stereo_calib_match.cpp 的极线对齐与 Q 矩阵构建
3.1 为什么单目标定完了还不够:左右相机之间的 R 和 T 决定深度精度
单目标定只解决"单个相机把三维点映射到像素"的问题。双目系统要恢复深度,必须知道左右两个相机之间的相对位姿——旋转矩阵R和平移向量T。T的模长就是基线baseline,它直接出现在深度公式的分母上:Z = f * baseline / d。基线测偏 1mm,近距离物体深度就偏出几个毫米到几厘米,这不是算法能弥补的,所以立体外参标定必须用stereoCalibrate做联合优化,而不是把左右两套单目外参拿来硬凑。
极线约束是立体匹配的理论基础:空间一点在左图上的投影点,它的同名点一定在右图的某一条直线上,这条线叫极线。如果两个相机完全没有校正,极线是倾斜的,搜索匹配点要在二维平面上扫,又慢又容易误匹配。立体校正的目的就是把左右图像重投影到一对虚拟的平行相机上,让同名点落在同一水平线上,这样匹配只在水平方向做一维搜索,效率和正确率都会好很多。
3.2 stereoRectify 的完整调用:从 stereoCalibrate 到 remap
stereo_calib_match.cpp里这一步值得细看,我把它拆成四个连续动作:先用stereoCalibrate算双目标定,再用stereoRectify计算左右相机的矫正旋转矩阵和新的投影矩阵,接着用initUndistortRectifyMap生成映射表,最后remap重采样输出校正后的左右图。
// 输入:左右单目标定得到的 K1/D1, K2/D2 // 输入:左右图像中棋盘格角点对应的像素坐标 lCorners[i], rCorners[i] stereoCalibrate(objectList, lCorners, rCorners, K1, D1, K2, D2, imageSize, R, T, E, F, CALIB_FIX_INTRINSIC, // 单目已定,只优化双目外参 TermCriteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 100, 1e-6)); // R1/R2: 左右相机矫正旋转;P1/P2: 矫正后投影矩阵;Q: 重投影矩阵 stereoRectify(K1, D1, K2, D2, imageSize, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, // 主点行对齐,Q 矩阵第3行第4列为0 0); // alpha: 0 裁剪黑边,1 保留全视场 // 生成映射表并执行重采样 Mat map11, map12, map21, map22; initUndistortRectifyMap(K1, D1, R1, P1, imageSize, CV_16SC2, map11, map12); initUndistortRectifyMap(K2, D2, R2, P2, imageSize, CV_16SC2, map21, map22); Mat leftRect, rightRect; remap(leftRaw, leftRect, map11, map12, INTER_LINEAR); remap(rightRaw, rightRect, map21, map22, INTER_LINEAR);CALIB_FIX_INTRINSIC的意思是左右相机的内参和畸变系数已经由单目标定确定,stereoCalibrate只优化 R、T、E、F。这是最稳妥的做法,因为单目和双目的目标函数不同,如果放开内参一起优化,内参和双目外参会互相拉扯,得到的结果未必更好。只有当左右单目标定明显不一致时才考虑去掉这个标志,让双目联合优化内参,但那样需要重投影误差也重新评估。
alpha参数是校正阶段最直观的调节钮:取 0 时 OpenCV 会把校正后图像中的无效区域(黑边)全部裁掉,输出图像变小但画面干净;取 1 时保留原始视场,黑边也保留,边缘物体可能因为旋转而超出图像。我一般调试阶段用alpha=1,因为能看到完整的图像内容,方便确认有没有裁掉有效区域;定稿后改成alpha=0再去跑匹配,减少无意义的黑边对匹配的干扰。
3.3 校正结果的验证:极线是否水平,一眼就能看出来
代码跑通了不等于校正对了。最简单的验证方法是在校正后的左右图上各画几条水平线,去同一行找棋盘格角点或者纹理清晰的点,看它们的 y 坐标是否一致。更定量的做法是把左右棋盘格角点的 y 坐标做差,统计均值:
// 对校正后的左右棋盘格角点做极线残差统计 double maxDY = 0.0, meanDY = 0.0; for (size_t i = 0; i < lCorners.size(); i++) { double dy = fabs(lCorners[i].y - rCorners[i].y); meanDY += dy; maxDY = std::max(maxDY, dy); } meanDY /= lCorners.size(); printf("Average row difference = %.3f px, max = %.3f px\n", meanDY, maxDY);这个meanDY正常应该小于 1 像素,如果能压到 0.3 像素以内,说明R1、R2校正到位,后面的 SGBM 才敢放心地把搜索范围限制在水平方向。如果这个值超过 2 像素且图像没有明显畸变残留,优先怀疑输入给stereoRectify的K1/D1、K2/D2与采集尺寸不匹配——比如标定用的是 1280x720,实际跑的是 1920x1080,映射表全部错位。
4. 点云生成与体积计算:SGBM 视差图到三维坐标的换算与两种体积算法
4.1 视差与深度的换算:Q 矩阵把这件靠手算容易错的事打包了
立体校正之后,同名点的视差d = x_left - x_right,视差越大物体越近。深度与视差是反比关系,公式是Z = f * baseline / d。stereoRectify输出的Q矩阵把这一步打包成了齐次坐标变换,用reprojectImageTo3D一条 API 就能把视差图变成三维点云。Q 矩阵的典型形式是:
Q = [1 0 0 -cx_l 0 1 0 -cy_l 0 0 0 f 0 0 -1/Tx (cx_l - cx'_r) / Tx]其中Tx是立体校正后的基线平移量,带符号。CALIB_ZERO_DISPARITY标志会让两个主点行对齐,此时cx_l与cx'_r近似相等,第四行第四列约等于 0。这里要特别注意符号:-1/Tx这一项决定了深度的正负,如果算出来的 Z 全是负值,检查是不是把左右图顺序搞反了。
4.2 SGBM 参数表:每个数字都对应一种典型问题
stereo_calib_match.cpp里用的是StereoSGBM,OpenCV 4.x 下的创建方式如下:
Ptr<StereoSGBM> sgbm = StereoSGBM::create( 0, // minDisparity: 最小视差,通常为 0 64, // numDisparities: 视差搜索范围,必须为 16 的倍数 11, // blockSize: 匹配窗口边长,推荐奇数 8 * 11 * 11, // P1: 视差平滑惩罚,通常取 8 * blockSize^2 32 * 11 * 11, // P2: 大梯度惩罚,通常取 32 * blockSize^2 1, // disp12MaxDiff: 左右一致性检查阈值,1~2 有效抑制误匹配 0, // preFilterCap: 预滤波截断值,默认 0 表示使用内置默认值 63 10, // uniquenessRatio: 唯一性比率,5~15,越大误匹配越少 100, // speckleWindowSize: 斑块滤波窗口,消除小噪声块 32, // speckleRange: 斑块内视差允许的最大跳变 StereoSGBM::MODE_SGBM); // MODE_HH 更慢但更准,MODE_SGBM 平衡速度这几个参数里最容易翻车的是P1、P2和blockSize之间的比例关系。P2会惩罚相邻像素视差不连续,太大会把物体边缘的细节磨平,太小小噪声多;P1太小会在平坦区域产生碎点。调参的正确顺序是:先定blockSize,用 7 或 11;再按8 * blockSize^2和32 * blockSize^2给 P1、P2 一个初始值;然后调numDisparities,让物体最近的表面和最远背景之间的视差范围都被覆盖——物体离相机越近、基线越长,需要的numDisparities越大,场景深的时候从 64 加到 128 是常态。
uniquenessRatio低于 5 时匹配结果里会出现大量横向条纹状噪声;speckleWindowSize在 50~200 之间,太大会把真实的小物体表面也当成噪声吃掉。
4.3 从视差图到点云:注意 CV_16S 的定点数陷阱
StereoSGBM::compute输出的视差图是CV_16S类型,每个像素值除以 16 才是真实的浮点视差。这一步是最容易被绕进去的地方,常见写法是直接用reprojectImageTo3D处理CV_16S的图,结果所有三维坐标被放大 16 倍。正确做法是先转成CV_32F再喂给重投影函数:
Mat disp16, disp32f; sgbm->compute(leftRect, rightRect, disp16); // CV_16S,值为真实视差 * 16 Mat disp32f; disp16.convertTo(disp32f, CV_32F, 1.0 / 16.0); // 关键:还原真实视差 Mat points3D; // 输出为 CV_32FC3 reprojectImageTo3D(disp32f, points3D, Q, true);handleMissingValues参数传true,OpenCV 会把视差无效的点在三维矩阵里标记为 Z 值极大或极小,方便后续过滤。遍历points3D生成点云时,我一般同时做两层过滤:把 Z 值不在合理范围内的点直接丢弃,比如小于 0 或大于 15m;再用直通滤波把背景中远距离的杂点去掉。Halcon 里有个算子叫depth_to_point_cloud,做的也是同一件事——把深度图(或视差图)结合相机内参转成 XYZ 点云,原理完全一样,只是 OpenCV 用 Q 矩阵,Halcon 用相机内参加基线手动展开。
生成的点云要落盘成文件方便可视化,最简单的格式是 PLY 或者 CSV。PLY 可以用 CloudCompare 直接打开,写一个最小可用的 ASCII PLY 头也就十几行代码,这一步对验证重建结果的价值极高——用眼睛看比对着数字猜强太多。
4.4 体积计算:凸包快但偏大,切片积分稳但慢
点云体积计算在资源里是压轴一步,做法主要有两种。第一种是对整片点云做凸包,然后求凸包体积,这个方法在物体表面没有大的凹陷时速度极快,但对于碗、盒、瓶子这类带内腔的物体,凸包会把凹进去的部分也当成实体体积包进去,结果系统性偏大。第二种是切片积分,沿某个坐标轴把点云切成薄片,每片在截面方向求二维凸包面积,乘以片厚再累加。对大多数工业测量场景,切片法更贴近"真实占据空间"的定义:
double calcVolumeBySlicing(const std::vector<cv::Point3f>& cloud, float slice = 2.0f) // 片厚 2mm,可调 { if (cloud.empty()) return 0.0; float zMin = 1e9f, zMax = -1e9f; for (const auto& p : cloud) { zMin = std::min(zMin, p.z); zMax = std::max(zMax, p.z); } double volume = 0.0; for (float z = zMin; z < zMax; z += slice) { std::vector<cv::Point2f> pts; pts.reserve(2048); // 取当前切片范围内的点:z 在 [z, z+slice) 之间 for (const auto& p : cloud) { if (p.z >= z && p.z < z + slice) pts.emplace_back(p.x, p.y); } if (pts.size() < 3) continue; // 不足 3 个点,忽略该片 std::vector<cv::Point2f> hull; cv::convexHull(pts, hull); // 每片做二维凸包 volume += cv::contourArea(hull) * slice; // 面积 * 片厚 } return volume; }片厚slice的选择直接影响结果:片厚太大,截面内的点分布被过度平滑,起伏细节消失;片厚太小,点云密度不够,空片增多,积分结果波动。我一般先统计点云沿 Z 方向的密度,保证每片内有 100 个以上有效点,再反推片厚。对一个大致的规则物体,这个方法的误差可以控制在 3% 以内,前提是点云完整覆盖了物体表面且没有大面积空洞——底部没有扫描到的情况,切片法只能算出可见部分的体积,这是物理限制,不是算法问题。
5. 避坑与排查:标定板、极线、视差和体积计算的四段翻车记录
5.1 角点数量填错,标定结果整体漂移
现象:findChessboardCorners频繁返回false,偶尔成功一两次;或者标定出来的cx、cy严重偏离图像中心,比如 1280x720 的图像主点跑到 (700, 500)。
原因:把棋盘格的格子数当成了内角点数传给boardSize。10x7 的格子,内角点是 9x6,这是 cornerSubPix 和 calibrateCamera 的前提,错一个数字整套计算就建立在错误假设上。另一个常见的诱因是标定板本身不平整,或者打印后贴在硬纸板上弯曲,角点沿曲面排布,检测倒是能检测到,但畸变系数会被拉偏去补偿弯板。
解决:统一用一个函数生成对象点矩阵,内角点数量直接从boardSize计算,不要手工填。每张图像检测前打印一下检测到的角点数量,和期望值比对。标定板最好用玻璃基底的瓷板或者铝板,打印纸贴硬纸板只适合验证流程,不适合严肃标定。
5.2 极线校正后图像斜带黑边,y 方向还有残差
现象:remap之后的左右图有明显斜向黑边,或者左右同名点在 y 方向上差了 2 像素以上,SGBM 匹配结果出现整行的错位条纹。
原因:最常见的是传给stereoRectify的imageSize和实际remap的图像尺寸不一致。标定用的是采集当时的图像分辨率,如果后续换了采集尺寸,映射表按旧尺寸生成,重采样时坐标全部错位。另一个常见原因是alpha参数设为 0 时黑边被裁剪,输出图像尺寸变了,但映射表还是按原尺寸算的。
解决:固定一套采集分辨率,标定和应用全程用同一个imageSize。调试时把alpha临时设成 1,确认黑边区域里没有有效内容后再切回 0。极线残差用 3.3 节的均值统计去量化,超过 1 像素就先回去查分辨率和内参,不要急着调 SGBM。
5.3 视差图一半是黑的,物体表面大面积缺数据
现象:StereoSGBM::compute跑完,视差图里物体表面全是黑点,只有边缘零星有效值;或者近距离物体能算出视差,但稍远一点的背景全部无效。
原因:numDisparities覆盖范围不够。视差范围取决于最近物体和最远物体的深度,近处物体视差大,如果搜索范围上限不够,近处表面就会失效;远处物体视差小,如果minDisparity设得太大,远处就匹配不到。另外P2如果设得太大,低纹理区域的视差平滑惩罚过高,也会被整体判为无效。
解决:先把numDisparities拉到 128,blockSize降到 5,看整体覆盖是否改善。P2先按32 * blockSize^2设,如果物体表面变成一块平板的形状,说明 P2 过大在区域间做了过度平滑,往下调。还缺数据就检查曝光是否过曝——双目匹配对纹理一致性极其敏感,左图过亮右图正常,匹配直接失败,这时候调参没用,先调相机曝光和白平衡。
5.4 体积算出来明显偏大,尤其是有凹槽的物体
现象:对一个有明显凹陷的瓶子或盒子做体积计算,结果比实际体积大 20%~40%,而且误差随物体形状变化没有规律。
原因:用了全局凸包。凸包的定义是最小凸集,它天然忽略凹陷,任何凹槽、内腔都会被当成实体补上。如果点云里还带了一部分背景点,比如墙面或桌面,凸包会把背景也包进去,体积进一步虚高。
解决:换成切片积分,并对点云先做一次直通滤波,把 Z 方向上超出物体范围的背景点全部切掉。切片内的二维凸包仍会略微高于真实截面,但对多数规则物体误差已经可以接受。如果物体是空腔结构,比如杯子,还需要先判断开口朝哪个方向,让切片的法向对齐开口方向,否则切出来的截面是环形,面积会被高估。
5.5 点云整体放大或深度值与实测不符
现象:重建出的物体宽度是对的,但深度方向明显拉长或压缩,或者所有三维坐标整体放大 16 倍。
原因:前者通常是Q矩阵和实际视差单位不匹配,后者几乎可以肯定是CV_16S的视差图没除以 16 就送进了reprojectImageTo3D。放大 16 倍这个错误非常隐蔽,因为物体形状完全不变,只有尺度不对,单看点云很难发现,拿尺子量一下才知道差在哪。
解决:定点数转浮点这步写成独立函数并加注释,不要顺手写在调参代码里。验证深度时找一个已知距离的平面,比如离相机 1m 的墙面,算重建点云的 Z 均值,和实测距离比对,偏差超过 2% 就回头查Q矩阵里的Tx单位和标定板的squareSize单位是否一致——这是另一个隐蔽坑,棋盘格尺寸填的是英寸还是毫米,全看generateObjectPoints里怎么写。
6. 进阶玩法:用已知尺寸物体验证体积,切面积分复核凸包结果
整条链路跑通之后,最难回答的问题是:算出来的体积到底准不准?我的习惯是先用一个已知尺寸的规则物体做基准验证,再决定要不要相信这套标定和匹配参数。找一个硬纸盒,量出长宽高,算好理论体积,放在相机视场中央拍一段,跑完整条管线,把重建点云直接拖进 CloudCompare 看形状对不对,再用calcVolumeBySlicing算体积。理论值与计算值偏差在 3% 以内,才算标定和匹配都通过了。
如果体积偏差偏大,我会把切片法当作复核工具去对比。给盒子的点云跑一次全局凸包体积(OpenCV 里可以对整个点云的 xyz 做convexHull后再用convexHullArea的思路推广到三维),再跑一次切片法,两者差多少暴露的是物体凹陷程度。凸包比切片大,物体就有不可忽略的凹结构;切片比理论值小,多半是某个表面没有重建出来,点云有洞。
再进一步,还可以在代码里加一个"合成点云自检":手工生成一个 100x80x50mm 的长方体点云,密度按真实点云的分布撒点,喂给体积函数,看算法本身有没有系统误差。这个自检建议放在每次修改完标定参数之后强制跑一遍,因为改一次内参或 SGBM 参数,重建尺度就可能变一次,靠肉眼在点云里看不出来,只有数值对不上时才意识到又动了哪根弦。从那以后我每次调整参数都强制走一遍合成点云体积加上真实盒子体积两个基线,数字不对就回头查映射表和视差转换,确实省下了大量在匹配参数里打转的时间。这套代码包的完整流程是从单目标定一路推到体积计算,照着stereo_calib_match.cpp的顺序读一遍再改自己相机的参数,希望帮到你。
本文还有配套的精品资源,点击获取