针孔模型与内参:先把像素和射线对齐
内参 K 把像素映射为相机坐标系射线;fx/fy/cx/cy 与标定分辨率不一致时,PnP 和 stereo 会系统性偏,重投影 RMS 仍可能很小。

1. 重投影 0.2 px,抓取 Z 偏 8 mm
PnP 求 AprilTag 抓取位姿,重投影 RMS 0.2 px,现场 Z 系统性偏 8 mm——用的是旧标定 JSON,分辨率从 1080p 换 720p 但 cx/cy 没按 scale 更新。内参不是「标定一次写进 config」就结束;它是像素几何的 汇率,与当前帧尺寸、crop、镜头一一绑定。px RMS 小只说明 重投影自洽,不保证 metric 距离对——hold-out 实物尺寸验收不可省。
2. 针孔投影
单位是 pixel,不是镜头焦距毫米值。f_x = f_{\text{mm}} / \text{pixel_size}。projectPoints / undistortPoints 用同一套 和 dist。写 URDF 或 ROS camera_info 时别把 mm 焦距直接填进 fx——两层单位混用静默 scale 错。
3. 像素 ↔ 归一化射线
pts_norm = cv2.undistortPoints(pixels.reshape(-1, 1, 2), K, dist, P=None)PnP、triangulatePoints、E 分解都假设 同一套 K + dist。P=K 与 P=None 混用是 double-undistort 温床。pipeline 文档应写清:检测在 raw 还是 undistort、PnP 吃哪一层坐标——新人最容易在这里复制出「能跑但偏几厘米」的代码。
4. 分辨率与 crop
resize 或 crop 后:,。720p 检测 + 1080p ROI 精定位时,ROI crop 后 cx/cy 要减 crop offset,fx/fy 不变。pipeline 启动:assert frame.shape[1::-1] == (width, height) 与 intrinsics YAML 一致。只改 topic 分辨率不改 camera_info 是 ROS 经典坑,表现与「忘 scale K」相同。
5. ROS camera_info 对齐
sensor_msgs/CameraInfo 存 K 为 row-major 9 元组。cv_bridge 读 bag 时核对 width/height 与 cx/cy 对应当前 topic 分辨率。object points 单位任意,tvec 随 object 走;K 始终 pixel。launch 启动摘要打印 fx,fy,cx,cy,width,height 有效值,现场 ros2 param get / topic echo 可交叉验证。
6. stereoRectify 与 P 矩阵
双目标定后 stereoRectify 输出 P1/P2 与原始 K 不同——rectified 图像用 P 投影/triangulatePoints,别混 pre-rectify K。decomposeProjectionMatrix(P) 可拆 K/R/t debug。看重映射后同行对应点 标准差,工程上希望 < 0.5 px。y-disparity 有系统 offset 时,先查 rectification 与 cx/cy,再查 baseline 标定。
7. projectPoints 自检与 synthetic
rvec, _ = cv2.Rodrigues(R)
proj, _ = cv2.projectPoints(obj_pts, rvec, tvec, K, dist)
err = np.linalg.norm(proj.reshape(-1, 2) - img_pts, axis=1)用标定输出的 rvecs/tvecs 对第 i 张图检查,可定位「K 对但 dist 错」的单图 outlier。synthetic cube:obj_pts 单位 m,tvec 平移 0.5 m,project 后 solvePnP 恢复 pose 对比 ground truth。CI 里加一条 synthetic PnP round-trip,防 K 缩放回归。
8. 手眼与多环节链
手眼标定输出 camera-to-gripper 4×4,与 K 无关但 projection 链是 world → base → gripper → camera → pixel。任一环节 K 错,抓取 offset 线性放大到工作空间边缘。多相机 rig 每个 sensor 独立 K,别抄左目到右目。换 gripper 或换相机支架后,即使 K 文件未变也要重验 hold-out PnP。
9. 失败模式与验收
| 现象 | 常见原因 |
|---|---|
| reproj 小但 metric 偏 | K 与分辨率/crop 不匹配 |
| 边缘 reproj 大 | dist 与 K 不是同一标定 |
验收:calibrateCamera per-view RMS + 热图;已知尺寸 Tag hold-out PnP 测 metric 距离。SLAM 在线 refine fx 需 parallax,monitor 。K/dist 与 resolution 写进 launch YAML,启动打印有效 K 摘要。
10. 案例:720p 忘 scale cx
抓取 Z 偏 8 mm 那单,根因是产线从 1080p 改 720p 只 scale 了 fx,fy,cx/cy 仍用 1080p 值——reproj RMS 仍 0.2 px,因为 Tag 在图像中心附近,中心点对 cx 误差不敏感,metric Z 对 principal point 偏移敏感。fix 后 hold-out 杆长误差从 8 mm 降到 1.2 mm。教训:px RMS 不能替代 metric hold-out;改分辨率必须整包 K 重算或按公式 scale。
11. 与手眼标定的交叉验证
手眼标定求 camera-to-gripper,不直接改 K,但抓取链用同一 K 投影。手眼后抓取仍偏时,我会分两步:先用 Tag hold-out 验 K+Pnp,再验手眼——顺序反了会把手眼误差误归到内参。多工具共用同一 intrinsics yaml,版本 bump 时所有节点同步 reload,避免抓取用 v3、VO 仍 v2。calibrationMatrixValues 打印 FOV 与焦距 mm 时,文档里分开记录 pixel K 与镜头规格,避免后人用 mm 填 fx。在线 SLAM refine 焦距时,要同时 monitor 轨迹与 reproj,单看 小仍可能轨迹 drift。intrinsics 文件命名含 resolution 与 serial,禁止 camera.yaml 无版本裸奔。多相机 rig 标定日期与温度范围写入 metadata,现场 dispute 时可追溯标定条件。Release 前用 hold-out 杆长或 Tag 边长验 metric,与 px RMS 并列入库。Stereo baseline 与 focal length 写进 extrinsics 文档,勿与 K 混在同一「相机参数」表格 ohne 单位说明。AprilTag 尺寸单位与 object point 一致写进标定 SOP,mm/m 混用 silent scale 错。多分辨率 pipeline 的 K 版本与 node 名称绑定,launch 打印 intrinsics_version 便于 bag 复盘。Hold-out metric 与 px RMS 分歧时 trust metric,优先查 K/crop 而非调 PnP 迭代次数。Stereo baseline 与 focal 文档化,避免 extrinsics 表格缺单位。
内参是所有 3D 视觉的公因数。排查 weird 3D bug 第一问:这张图的 K 和 dist,跟生成它时一致吗?
相关
也可以看看
johan's blog