返回专辑
·Johan·4 分钟阅读

三角化:基线太短深度会炸

OpenCV triangulatePoints 在归一化坐标下线性三角化;depth 不确定度与视差角成反比,baseline 不足时像素噪声会被放大成米级 depth 误差。

三角化:基线太短深度会炸

1. 近处物体 depth 跳变,不是 triangulatePoints 的 bug

stereo baseline 5 cm、要看 10 m 处障碍;或 mono VO 两关键帧几乎纯旋转——triangulatePoints 输出 depth 方差大到没法做 obstacle stop。这不是 OpenCV 实现问题,是观测几何不可观:视差角 太小,1 px 视差误差按 放大成 metric 误差。现场若只调「深度滤波核大小」而不看 parallax 分布,往往在平滑不可观噪声。

2. 线性三角化机制

两相机投影 (3×4),齐次 3D 点 满足 。交叉乘消元得 ,SVD 取最小奇异值对应解。

python
pts4d = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T)
pts3d = (pts4d[:3] / pts4d[3]).T

输入点与 必须在 同一畸变模型层:同为 raw 像素 + dist,或同为 undistort 归一化坐标。rectified stereo 用 stereoRectify 输出的 P1/P2,别混 pre-rectify K。投影矩阵符号错时会出现大量 NaN,应先 synthetic 两点验符号再上大 bag。

3. 不确定度直觉

量级:baseline 小、距离远、视差小,depth 噪声爆炸。基线 5 cm、目标 5 m、disparity 10 px 时,1 px 噪声 → 约 10% depth 误差——几何下限,换公式救不了。向产品经理解释「加算法不如加 baseline」时,这条关系比堆公式直观。

4. 工程策略

关键帧策略:拉开 baseline 比换三角化公式常更有效。parallax 筛选: 的点 discard。cheirality:两相机 才保留。非线性 refine:VO 里 linear 够初始化,BA 用 reproj error refine;discard reproj > 2 px 再喂 BA。纯旋转 motion 时 ,三角化 depth 无意义——拒绝初始化。我会把 parallax 直方图写进 debug 面板,一眼看出「不可观帧」占比。

5. stereo vs mono 差异

stereo 固定 baseline,depth 误差主要随距离涨;mono VO depth 还受关键帧选帧策略支配。对 stereo 报 disparity 噪声与 triangulate depth 的 joint histogram;对 mono 报 parallax 角分布。两种 pipeline 的 验收阈值不能共用。mono 深度用于导航时,我倾向只用于相对障碍趋势,metric stop 交给激光或 stereo。

6. OpenCV 细节与 NaN

输出 4×N homogeneous,除以第四行;NaN/Inf 常来自错匹配或 P 符号错。Mid-point / optimal triangulation 在 OpenCV 主库无封装,Colmap/Ceres 里有;前端 linear + 后端 BA 是常见分工。persist triangulate inlier mask 进 map point 创建,避免错点污染全局 BA。

7. 与 obstacle stop 的验收

导航用 depth 做 stop 时,关心 最近障碍距离分位数,不是 mean depth。baseline 不足时 widen stop margin 或拒用 mono depth。有激光时 stereo/mono depth 与激光抽样对比,系统性 bias 查 K/baseline,随机噪声查 parallax 筛选。安全相关 stop 距离应留几何不确定性 margin,而不是 trust 滤波后的单点 depth。

8. 失败模式

现象原因
大量负 depth错匹配 / 错
depth 跳变匹配不稳 / baseline 突变
中心准边缘差畸变或 rectification 残余

9. 验收

triangulate 后 比例;inlier reproj(projectPoints);已知 baseline stereo 对比激光抽样。mono VO 看 depth 中位数是否随 baseline 增大而稳定。P1/P2 与点坐标层写进 yaml,启动 assert 分辨率与标定一致。改 keyframe 策略前后应用同一 bag 对比 depth 方差,有明确下降才合并 PR。

10. 案例:5 cm 基线看 8 m

小 baseline stereo 标定 RMS 很好,但 8 m 处 depth 跳变达米级,obstacle stop 误触发。加 parallax <2° 剔除 + 关键帧最小平移 0.3 m 后,有效 depth 比例降但 stop 误报消失。产品接受「远距不用 stereo depth 停障」比接受随机跳变更安全。硬件选型阶段就应算 与 pixel noise,而不是标定完才 discovery。

11. 与 BA 的衔接

线性三角化输出是 BA 的初值,不是终值。我会把 triangulate 的 reproj 阈值设得比 BA 松、比 outlier 紧——太松污染 map,太紧 map 点稀少。marginalization 丢掉的三维点,很多在三角化阶段本可剔除。改 keyframe 策略时同时看 map 点数量、平均 parallax、BA 迭代次数,三者应同向变化。mono 深度用于导航时要在文档里声明 不可观方向,避免安全同事误以为 triangulate 输出等同激光测距。stereo 与 mono 的 depth 验收表分开维护,禁止共用同一 RMS 阈值。

三角化是把像素误差放大成 metric 误差的步骤。基线设计不对,后面 BA 也救不了不可观方向。

← 全部文章

johan's blog