Files
VSAG_AUTO_AIM_PRACTICE_27RM/README.md
T
mzxwww ca6891eef2 Add camera calibration toolchain and armor pose solver
- capture_calib: capture calibration images (MindVision / USB) with a live
  quality gate (Laplacian sharpness, 3x3 coverage, board auto-detect)
- calibrate: batch intrinsics from calib_images/, writes configs/camera.yaml
- camera_calib: CameraCalib loader (intrinsics + distortion, cached
  undistort remap) and solvePose() via IPPE with a reprojection gate
- configs/camera.yaml: MV-SUA131GC intrinsics, RMS 0.483 px over 31 images,
  ruler-verified distance error < 2%
- xmake: three targets sharing an rm_deps rule, C++17
- gitignore: keep calibration photos/videos and generated
  compile_commands.json out of the repo
2026-09-15 23:33:01 +08:00

132 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 27RM
RoboMaster 视觉工程(MindVision 相机 + OpenCV)。
## 构建
```bash
xmake # 产出两个程序(见下)
xmake run 27RM # 跑主程序
```
## 程序清单
| 程序 | 用途 |
|---|---|
| `27RM` | 自瞄主程序 |
| `capture_calib` | **相机标定图采集工具** |
| `calibrate` | **标定计算工具**(照片 → 内参/畸变 → `configs/camera.yaml`) |
## 配置
```
configs/
└── camera.yaml # 相机内参 + 畸变 + 标定元信息(由 calibrate 生成,需入库)
```
代码里这样用(`inc/camera_calib.hpp`):
```cpp
#include "camera_calib.hpp"
CameraCalib calib;
if (!calib.load("configs/camera.yaml")) return -1; // 启动时加载一次
cv::Mat undist;
calib.undistort(frame, undist); // 每帧去畸变
// 装甲板四角点(左下、左上、右上、右下)→ 位姿
std::array<cv::Point2f, 4> corners{lb, lt, rt, rb};
if (auto pose = calib.solvePose(corners, ArmorSize::small())) {
double yaw, pitch;
CameraCalib::poseToYawPitch(pose->tvec, yaw, pitch);
// pose->distance_mm / pose->reproj_error_px 可用于过滤坏帧
}
```
> 程序必须在工程根目录运行(`configs/` 是相对路径),或自行传绝对路径。
## 相机标定流程
> **本工程标定板规格**:10 × 7 内角点、**方格 20.0 mm**(卡尺实测值,不是打印标称值)
> **相机**:MV-SUA131GC(1/3" CMOS,3.75μm 像元)+ MV-LD-M12-2.8MM-C 镜头,输出 1280×1024
> ⚠️ M12 镜头**调焦会改变有效焦距**,标定和使用时必须保持对焦环位置一致
### 1. 采集标定图
```bash
# 用 MindVision 相机(机器人上那台)
./build/linux/x86_64/debug/capture_calib --square 20.0
# 或改用 USB 摄像头
./build/linux/x86_64/debug/capture_calib --usb 0 --square 20.0
```
按键:
| 键 | 功能 |
|---|---|
| 空格 | 保存当前帧(默认要求检测到棋盘格) |
| `f` | 强制保存(未检测到也存) |
| `d` | 删除上一张 |
| `c` | 开关实时角点检测显示 |
| `g` | 灰度预览(排查过曝/反光) |
| `q` / ESC | 退出 |
拍摄要求:
- 标定板出现在画面**中心、四角、边缘**(2.8mm 广角镜头边缘畸变最大)
- 姿态多样:正对、倾斜、旋转、俯仰
- 清晰不糊、光照均匀、无反光、板子贴平硬板
- **20~30 张**,保存于 `calib_images/`(已加入 .gitignore,不会入库)
### 2. 计算内参
```bash
./build/linux/x86_64/debug/calibrate --dir calib_images --square 20.0 # 只算顶层
./build/linux/x86_64/debug/calibrate --dir calib_all --square 20.0 # 全部 31 张(推荐)
./build/linux/x86_64/debug/calibrate --square 20.0 --show # 逐张查看角点与重投影
```
工具会输出重投影误差 RMS、内参 K、畸变系数、每张图误差排行,并写入 `camera_calib.yml`。
| 重投影误差 | 评价 |
|---|---|
| < 0.3 px | 很好 |
| 0.3 ~ 0.5 px | 可接受 |
| > 0.5 px | 建议重拍 |
> **当前标定结果**(`calib_all/` 31 张,20mm 方格):
> fx=657.47, fy=658.25, cx=625.64, cy=509.00,RMS **0.483 px**
> **距离验证**:卷尺 700mm vs 程序 687~697mm,误差 **< 2%** ✓
### ⚠️ 标定图必须同时具备「三种多样性」
| 维度 | 作用 | 不满足的后果 |
|---|---|---|
| **画面位置**(九宫格覆盖) | 约束**畸变系数** | 边缘畸变解不出来,RMS 偏高 |
| **倾角**(正对/上下倾/左右倾/大角度) | 约束**焦距与主点** | 参数耦合,精度下降 |
| **距离**(近/中/远,板子占画面 40%/20%/8%) | 约束**尺度** ⭐ | **fx 无法确定**:所有图同距离时,"焦距×距离"可整体缩放而图像不变,优化器会落到错误值,**且 RMS 依然很低**(最阴险的坑) |
> 实测教训:一套 19 张、覆盖 9/9 但**距离相近**的图,标出的 fx=883(实际 659,偏差 34%),距离误差直接 +32%;
> 与旧的 12 张(距离 24~65cm)合并后 fx 回到 657,误差 <2%。**距离多样性是 fx 的锚点,不可省。**
### 3. 使用内参
```cpp
cv::Mat K, D;
cv::FileStorage fs("camera_calib.yml", cv::FileStorage::READ);
fs["camera_matrix"] >> K;
fs["dist_coeffs"] >> D;
```
之后用 `cv::undistort` / `cv::solvePnP` 做去畸变与位姿解算。
### 4. 距离验证(改完参数一定要做)
```bash
~/yolo-env/bin/python ~/rm_vision/verify_distance.py 图片.jpg --square 20.0 --distance 647
```
用卷尺量出真实距离,与程序算出的距离对比:误差 < 2% 说明标定可用。