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

PnP:外点与初值

solvePnPRansac + EPnP 初值 + iterative refine 是工程默认;共面点用 SOLVEPNP_IPPE,错 flag 会 confident flip。

PnP:外点与初值

1. 一百八十度跳变不是玄学

AprilTag 位姿偶尔跳变一百八十度——角点亚像素滑到邻边,随机采样没开,迭代法掉进局部极小。透视 n 点是非线性且外点敏感;重投影阈值差一像素有时差整个演示。标志位、随机采样、细化是契约,不是默认值能扛的——写进配置并 A/B。共面四点加错算法是现场最高频 flip 原因之一。

2. 问题与 OpenCV 默认链

已知三维点与二维观测,求旋转平移使投影近似观测。至少四点超定,最小化重投影误差。工程默认:随机采样剔外点、快速 n 点初值、迭代法细化:

python
ok, rvec, tvec, inliers = cv2.solvePnPRansac(
    obj_pts, img_pts, K, dist,
    reprojectionError=3.0, confidence=0.99,
    iterationsCount=100, flags=cv2.SOLVEPNP_EPNP)
if inliers is not None and len(inliers) >= 4:
    rvec, tvec = cv2.solvePnP(
        obj_pts[inliers], img_pts[inliers], K, dist,
        rvec, tvec, useExtrinsicGuess=True,
        flags=cv2.SOLVEPNP_ITERATIVE)

重投影阈值是 L2 像素,通常二到五像素,匹配检测噪声。物点与平移同单位毫米或米,混用尺度静默错。OpenCV 文档明确物点和平移同单位。

3. 标志位选择

标志适用
快速 n 点通用初值,至少四点,快
迭代法需初值,列文伯格细化精度高
共面专用共面 AprilTag、棋盘
小点集专用点少时
三点法仅三点,多解需第四点消歧

共面加迭代法无好初值会多解翻转。AprilTag 务必用共面专用或板级多点估计——单标记四点共面是经典踩坑。OpenCV 四通用接口可同时试多种标志返回多解,共面场景值得开。

4. 失败模式

情况现象
共面加错标志一百八十度跳
点簇太小深度旋转不可观
内参畸变错低重投影仍错位姿
对称物体语义错配内点仍多

可视化画坐标轴,轴长与物体单位一致。多帧融合时旋转向量平移转四乘四再插值,避免欧拉跳变。板级估计比单标记点多,部分遮挡仍可用。

5. 时间与控制

单帧解算控机器人前至少扩展卡尔曼多帧融合——时间中值滤波防单帧翻转。内点数小于四或重投影均方根超阈值时保持上一帧或安全停止,别硬输出。与惯性或先验位姿差超阈值则拒绝该帧。720p 与 4K 不能共用同一像素阈值,阈值应与焦距像素成比例。

6. 案例:共面 flip

某次 AprilTag 定位偶尔反了——随机采样用迭代法无初值,共面四点多解。改共面专用加随机采样后 flip 消失。重投影从零点六升到零点九像素(正常——共面专用不保证全局最小),但时间稳定。低重投影的错位姿比高重投影的对位姿更危险。

7. 与 yaml 和录包

标志位、重投影阈值、迭代次数写进 yaml,启动摘要打印有效值。录包含解算参数快照,复盘 flip 时能对照是否用了错误标志。我会把内点率和重投影均方根打 log,异常先查单位再查算法。换镜头或分辨率时重投影阈值应与焦距像素成比例重标定,不能沿用上一台机的 yaml。

8. 验收

  • 内点数比例加内点重投影均方根(像素)
  • 与惯性或先验位姿差
  • 时间跳变检测或中值滤波日志
  • 共面场景标志 A/B
  • 阈值与分辨率成比例写进配置

透视 n 点是二维三维对齐枢纽。随机采样阈值、标志、细化写进配置——差一像素阈值有时差整个演示。

← 全部文章

johan's blog