Add pose_test tool and harden solvePose; expose camera controls
- pose_test: verify the geometry chain (4 corners -> distance/yaw/pitch)
before any detector exists; modes: camera + mouse clicks, --image,
--corners (headless), --selftest (synthetic round-trip, no camera needed)
- solvePose: undistort corners first, then solvePnPGeneric(IPPE) and pick
the best candidate; reject solutions behind the camera (z<=0) or with
reprojection error > 8px
- fixes IPPE + distortion + in-plane rotation returning garbage
- 4 coplanar points: cyclic/mirrored orderings give the same quad and
the same pose (harmless); crossing orderings blow up reprojection
and are rejected
- camera_set: implement setAeState/setExposureTime/setAnalogGain(+-Times)/
setWbMode/setFrameSpeed; configs/camera_runtime.yaml drives them
- selftest passes all 6 synthetic cases; verified on 6 real photos
(chessboard outer rect 180x120mm): distance 0.44-0.69m, reproj <2.5px
This commit is contained in:
@@ -5,7 +5,7 @@ RoboMaster 视觉工程(MindVision 相机 + OpenCV)。
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
xmake # 产出三个程序(见下)
|
||||
xmake # 产出四个程序(见下)
|
||||
xmake run 27RM # 跑主程序
|
||||
```
|
||||
|
||||
@@ -26,12 +26,14 @@ xmake project -k compile_commands .vscode
|
||||
| `27RM` | 自瞄主程序 |
|
||||
| `capture_calib` | **相机标定图采集工具** |
|
||||
| `calibrate` | **标定计算工具**(照片 → 内参/畸变 → `configs/camera.yaml`) |
|
||||
| `pose_test` | **几何链路验证工具**(4 角点 → 距离/yaw/pitch,含合成自检) |
|
||||
|
||||
## 配置
|
||||
|
||||
```
|
||||
configs/
|
||||
└── camera.yaml # 相机内参 + 畸变 + 标定元信息(由 calibrate 生成,需入库)
|
||||
├── camera.yaml # 相机内参 + 畸变 + 标定元信息(由 calibrate 生成,需入库)
|
||||
└── camera_runtime.yaml # 运行时参数:曝光/增益/白平衡/帧率(手工维护,需入库)
|
||||
```
|
||||
|
||||
代码里这样用(`inc/camera_calib.hpp`):
|
||||
@@ -54,8 +56,52 @@ if (auto pose = calib.solvePose(corners, ArmorSize::small())) {
|
||||
}
|
||||
```
|
||||
|
||||
`solvePose` 内部已处理:去畸变 → `solvePnPGeneric`(IPPE) 取回全部候选解 →
|
||||
筛掉「相机后方 (z<=0)」「重投影 > 8px」→ 取最优。详情见源码注释。
|
||||
|
||||
相机参数设置(`inc/camera_set.hpp`,`initializeCamera` 之后调用):
|
||||
|
||||
```cpp
|
||||
cam.setAeState(false); // 手动曝光(比赛必须,否则画面亮度漂移)
|
||||
cam.setExposureTime(3000.0); // 曝光时间,微秒
|
||||
cam.setAnalogGainTimes(2.0); // 模拟增益,倍率(内部按 fAnalogGainStep 换算)
|
||||
cam.setWbMode(false); // 关自动白平衡(颜色阈值才稳定)
|
||||
cam.setFrameSpeed(2); // 帧率档位 0/1/2
|
||||
```
|
||||
|
||||
也可以直接由配置驱动:`applyRuntimeParams` 的示例见 `src/pose_test.cpp`。
|
||||
|
||||
> 程序必须在工程根目录运行(`configs/` 是相对路径),或自行传绝对路径。
|
||||
|
||||
## pose_test:几何链路验证
|
||||
|
||||
写检测器之前,先用它验证「标定 + 坐标约定 + PnP 解算」:
|
||||
拿真的装甲板(或打印 135mm 矩形)摆在相机前,鼠标点 4 个角,
|
||||
输出的距离/yaw/pitch 与卷尺、量角器核对。之后接检测器出问题必是检测的锅。
|
||||
|
||||
```bash
|
||||
./build/linux/x86_64/debug/pose_test # 相机 + 鼠标点角
|
||||
./build/linux/x86_64/debug/pose_test --image 照片.jpg # 图片模式
|
||||
./build/linux/x86_64/debug/pose_test --selftest # 合成自检(无需相机/显示器)
|
||||
# 脚本/无窗口:直接给 4 个角点(左下 左上 右上 右下),--size 自定义矩形(毫米)
|
||||
./build/linux/x86_64/debug/pose_test --image 照片.jpg --size 180x120 \
|
||||
--corners x1,y1 x2,y2 x3,y3 x4,y4
|
||||
```
|
||||
|
||||
- 相机模式按键:`r` 清除重选 | `b` 切换大小装甲 | `u` 切换去畸变显示 | `s` 截图 | `q` 退出
|
||||
- `--selftest` 自检已通过:正前方/右偏/上仰/复合/板内滚转均精确恢复,
|
||||
交叉乱序被重投影门限正确拒绝
|
||||
- 真实照片验证:6 张标定图(棋盘格外圈 180×120mm)距离 0.44–0.69m、
|
||||
重投影 0.3–2.5px,与卷尺真值一致
|
||||
|
||||
### 两个踩过的坑(写检测器时别重蹈)
|
||||
|
||||
1. **IPPE + 畸变 + 板内旋转 = 垃圾解**(OpenCV 4.x/5.x 都中招)。
|
||||
解法:角点先去畸变再喂 IPPE,重投影回原图算(`solvePose` 已内置)。
|
||||
2. **4 个共面点的顺序错误查不出来**:循环/镜像顺序 = 同一个四边形 =
|
||||
同一个解(无害);交叉乱序会被重投影门限拦下。真正需要 roll 门限的是
|
||||
「检测器给出假四边形」场景,等写检测器时照搬 jlu 的 `roll_thres 15°`。
|
||||
|
||||
## 相机标定流程
|
||||
|
||||
> **本工程标定板规格**:10 × 7 内角点、**方格 20.0 mm**(卡尺实测值,不是打印标称值)
|
||||
|
||||
Reference in New Issue
Block a user