基于OpenCV的立体光流开发与3D坐标重建坐标系整合问题求助
基于OpenCV StereoCalibrate标定结果实现统一笛卡尔坐标重建的步骤
你通过cv.stereoCalibrate完成标定后,已经拿到了两个相机的内参、畸变系数,以及右相机相对于左相机的外参(旋转矩阵R、平移向量T),直接按以下流程操作即可得到统一坐标系下的3D笛卡尔坐标:
1. 确定统一基准坐标系
直接选择左相机的相机坐标系作为全局统一笛卡尔坐标系即可,90°的相机夹角不需要额外做适配,cv.stereoCalibrate输出的R、T已经完整描述了右相机相对于左相机的位姿关系,所有后续重建结果默认都在左相机坐标系下。
如果你需要以其他世界坐标系为基准,直接叠加左相机相对于该世界坐标系的外参(虚拟相机部署时可直接获取该参数)做坐标转换即可。
2. 执行极线校正
调用cv.stereoRectify生成校正参数,将两个相机的成像平面校正到平行极线状态,同时得到统一坐标系下的投影矩阵和重投影矩阵:
# 输入stereoCalibrate输出的标定参数,image_size为输入图像的宽高 R1, R2, P1, P2, Q, roi1, roi2 = cv.stereoRectify( mtx1, dist1, mtx2, dist2, image_size, R, T, flags=cv.CALIB_ZERO_DISPARITY, alpha=0 ) # 生成校正映射表,对输入的左右图像做去畸变+校正 map1x, map1y = cv.initUndistortRectifyMap(mtx1, dist1, R1, P1, image_size, cv.CV_32FC1) map2x, map2y = cv.initUndistortRectifyMap(mtx2, dist2, R2, P2, image_size, cv.CV_32FC1) img1_rect = cv.remap(img1, map1x, map1y, cv.INTER_LINEAR) img2_rect = cv.remap(img2, map2x, map2y, cv.INTER_LINEAR)
3. 基于匹配结果重建3D坐标
根据你做立体光流的需求,分稀疏重建和稠密重建两种场景处理:
稀疏光流场景(特征点级重建)
如果你用cv.calcOpticalFlowPyrLK等稀疏光流算法得到了左右图的匹配特征点,调用cv.triangulatePoints做三角化得到3D坐标:
# pts1为左图匹配特征点,shape为(N,1,2);pts2为右图对应匹配特征点 pts1_norm = cv.undistortPoints(pts1, mtx1, dist1, R=R1, P=P1) pts2_norm = cv.undistortPoints(pts2, mtx2, dist2, R=R2, P=P2) # 三角化得到齐次坐标 points_4d = cv.triangulatePoints(P1, P2, pts1_norm, pts2_norm) # 转为左相机坐标系下的3D笛卡尔坐标,shape为(N,3) points_3d = (points_4d[:3,:] / points_4d[3,:]).T
稠密光流/全图重建场景
如果你需要得到全图所有像素对应的3D坐标,先计算稠密视差图再调用cv.reprojectImageTo3D:
# 用SGBM算法计算稠密视差,参数可根据实际场景调整 sgbm = cv.StereoSGBM_create( minDisparity=0, numDisparities=16*5, blockSize=9, P1=8*3*9**2, P2=32*3*9**2 ) disparity = sgbm.compute(img1_rect, img2_rect).astype(np.float32) / 16 # 得到全图3D坐标,无效点的Z值为负,可直接过滤 points_3d = cv.reprojectImageTo3D(disparity, Q)
验证建议
可以先用标定用的棋盘格角点做重投影误差校验,确认标定得到的R、T参数正确:将已知3D坐标的棋盘格角点分别投影到两个相机的成像平面,和实际检测到的角点坐标做对比,误差小于1像素说明标定参数可用。
内容的提问来源于stack exchange,提问作者Walid
相关产品推荐
相关产品推荐

