167 lines
8.5 KiB
Markdown
167 lines
8.5 KiB
Markdown
# libstereo_bolt 交付说明(.so + 头文件)
|
||
|
||
你拿到的是**预编译的 aarch64 动态库 + C 头文件**,不含算法源码。
|
||
OpenCV 4.5.4、RKNN runtime 及全部传递依赖(约 131 个 `.so`)**已随包内置于 `lib/`**,
|
||
无需在目标板上安装任何软件包(NPU 内核驱动由固件提供,不在用户态包内)。
|
||
|
||
> **本包标定 = 12MP 生产相机(4096×3000)。** 喂进来的左右图必须是该相机的 **4096×3000** 帧
|
||
> (`config` 里 `image.width=4096 / height=3000` 已配好,指向 `calib/stereo_calib_20260607_211135.xml`)。
|
||
> **包内不含测试图** —— 请用你自己这套 12MP 相机拍的左右图。
|
||
> ✅ **已在板上实测**:本 12MP 标定**加载 + rectify 通过**(4096×3000,stereo_rms=0.373、baseline=200.19、f_rect=3330)。
|
||
> ⚠️ 但**检测 + 测量在该相机上还没用真实螺杆图验过**(包内无螺杆图)。
|
||
> ⚠️ 本标定单相机 RMS=**0.373**(5MP 那套是 0.19),已把 `calibration.max_single_rms` **放宽到 0.40** 才放行;
|
||
> 0.373 偏松会折损测量精度,建议后续**重标到 <0.20** 再收回此闸。首次上机务必用真实螺杆图核对结果。
|
||
|
||
## 包内容
|
||
| 路径 | 说明 |
|
||
|---|---|
|
||
| `lib/libstereo_bolt.so` | 预编译共享库(aarch64) |
|
||
| `lib/librknnrt.so` 等(共 ~131 个) | OpenCV 4.5.4 + 全部传递依赖(**已随包,无需 apt**) |
|
||
| `include/stereo_bolt/c_api.h` | C ABI 头文件(唯一对外接口) |
|
||
| `weights/best_1280_20260621.rknn` | NPU 模型(精测 + 测距共用,imgsz 1280) |
|
||
| `calib/stereo_calib_20260621_202857_ascii.xml` | 出厂标定(0621 装配,baseline 482 mm) |
|
||
| `config/config.rk3588.12mp.yaml` | 配置文件(兼容 `sb_create` 接口用) |
|
||
| `example/` | 最小 C 示例(精测 + 测距) + CMakeLists |
|
||
| `INSTALL_3588.md` | 安装与运行说明(**从这里开始**) |
|
||
| `DEPENDENCIES.md` | 依赖库详细清单及说明 |
|
||
| `ABI_FINGERPRINT.txt` | 二进制 ABI 指纹 |
|
||
|
||
---
|
||
|
||
## 你什么时候需要什么(编译期 vs 运行期)
|
||
|
||
**重点:你不需要重编这个库**(它是预编译好的成品,你也没有源码)。你只编译*你自己*
|
||
调用它的小程序,那一步几乎零依赖。OpenCV / librknnrt 是**运行那一刻**才需要的。
|
||
|
||
| 东西 | 编译你自己的调用程序 | 在板上**运行** |
|
||
|---|:---:|:---:|
|
||
| `c_api.h` | ✅ | — |
|
||
| `libstereo_bolt.so` | ✅(链接,带 `--allow-shlib-undefined`) | ✅ |
|
||
| OpenCV 4.5.4 | ❌ 不需要(C ABI 不暴露 cv 类型) | ✅ **已随包 `lib/`,无需安装** |
|
||
| `librknnrt.so`(RKNN 运行时) | ❌ | ✅ **已随包 `lib/`** |
|
||
| NPU 驱动 + `/dev/rknpu` | ❌ | ✅ 必须(内核态) |
|
||
| `.rknn` 模型 + 标定 XML + `config` | ❌ | ✅ 必须(**已在本包** weights/ config/ calib/) |
|
||
|
||
> **“YOLO 依赖”在板上很轻**:就是 `librknnrt.so` + NPU 驱动 + `.rknn` 文件。
|
||
> **不需要** Python / PyTorch / ultralytics / ONNXRuntime / rknn-toolkit2 —— 那些是 PC 上把
|
||
> `.onnx` 转成 `.rknn` 用的,转完板上就用不到。
|
||
|
||
---
|
||
|
||
## ⚠️ 必须匹配的 ABI 指纹(动态链接的硬约束)
|
||
|
||
这个 `.so` 在某个具体环境里编出来,二进制里**写死了**它依赖的 so 名字和 glibc 版本。
|
||
**“自己准备 OpenCV” 不等于随便哪个 OpenCV 都行——必须是指纹里那个 major.minor。**
|
||
|
||
打开 `ABI_FINGERPRINT.txt`,确保你的板子满足:
|
||
|
||
- CPU 架构 = **aarch64**
|
||
- **glibc ≥ 指纹里的版本**(低于它,加载即 `GLIBC_x.xx not found`)
|
||
- **OpenCV soname 与指纹一致**(本包指纹 = `libopencv_core.so.4.5d` ⇒ 装 **OpenCV 4.5.x**;其它版本 soname 不通用)
|
||
- **librknnrt 版本** = 转换 `.rknn` 所用 toolkit 版本(**2.3.x**)
|
||
|
||
一条命令自检(应当**没有任何** `not found`):
|
||
|
||
```bash
|
||
ldd lib/libstereo_bolt.so | grep "not found"
|
||
```
|
||
|
||
---
|
||
|
||
## 板子上需要准备的
|
||
|
||
| 依赖 | 状态 |
|
||
|---|---|
|
||
| OpenCV 4.5.4 + 传递依赖(131 个 .so) | ✅ **已随包 `lib/`**,无需 apt |
|
||
| `librknnrt.so`(RKNN 运行时 2.3.2) | ✅ **已随包 `lib/`** |
|
||
| `.rknn` 模型 + 标定 XML + config | ✅ **已随包** `weights/` `calib/` `config/` |
|
||
| NPU 内核驱动 + `/dev/rknpu` | ⚠️ **板子固件提供**,出厂 RK3588 一般已有 |
|
||
| glibc ≥ 2.32(Ubuntu 22.04 自带 2.35) | ✅ 系统自带,无需操作 |
|
||
|
||
> 完整依赖说明见 `DEPENDENCIES.md`。
|
||
|
||
---
|
||
|
||
## 怎么用(C ABI)
|
||
|
||
完整示例见 `example/main.c`。有**两个**喂帧入口,生产用内存版:
|
||
|
||
**① 生产路径 —— 内存版(不落盘,直接喂相机帧):**
|
||
```c
|
||
StereoBoltCtx* ctx = sb_create("config/config.rk3588.yaml"); // 一次:载配置/标定/RKNN 模型
|
||
while (抓帧) {
|
||
const uint8_t* L = camera_left_frame(); // 相机 SDK 给的 Mono8 缓冲(W*H 字节,在内存)
|
||
const uint8_t* R = camera_right_frame();
|
||
StereoBoltModuleResultC out;
|
||
sb_process_bolt_module_buffers(ctx,
|
||
L, W, H, 0, // stride=0 表示行紧凑排列(每行 W 字节)
|
||
R, W, H, 0,
|
||
1, // channels: 1=Mono8(灰度), 3=BGR 也接受(内部转灰度)
|
||
8, &out); // 8 = 期望螺栓数
|
||
/* out.success==1: out.data.bolts[i].height_mm / foot_xyz / top_xyz + adjacent_distances + ground_plane
|
||
out.success==0: out.failure.reason + left_rois/right_rois/pairs(诊断用) */
|
||
sb_free_bolt_module_result(&out);
|
||
}
|
||
sb_destroy(ctx); // 一次
|
||
```
|
||
> `W`/`H` **必须等于标定分辨率**(`config` 的 `image.width`/`image.height`),否则返回 `SB_ERR_IO`。
|
||
> 内存版**全程不碰磁盘**(已实测:删掉源文件后内存版照常出结果)。
|
||
|
||
**② 离线/测试路径 —— 文件版(读磁盘图,用你自己的 12MP 左右图):**
|
||
```c
|
||
sb_process_bolt_module_files(ctx, "your_left.bmp", "your_right.bmp", 8, &out);
|
||
```
|
||
> 图必须是本套 12MP 相机的 4096×3000(灰度或彩色均可),格式 .bmp/.tiff/.png。本包不含测试图。
|
||
|
||
错误码:`SB_OK=0` / `SB_ERR_INVALID_CONFIG=-1` / `SB_ERR_IO=-2` /
|
||
`SB_ERR_ALGORITHM_REJECTED=-3` / `SB_ERR_INTERNAL=-99`。
|
||
> `SB_ERR_ALGORITHM_REJECTED` 不是崩溃,是算法判定该帧不可测,`out.failure` 里有原因 + ROI + 配对状态。
|
||
|
||
---
|
||
|
||
## 输入 / 输出(契约)
|
||
|
||
**输入**
|
||
- 一次性(`sb_create`):`config/config.rk3588.yaml`(内部指向 `calib/*.xml` 与 `weights/best.rknn`)。
|
||
- 每帧(生产用 `sb_process_bolt_module_buffers`):左/右 Mono8 内存缓冲 + 宽/高/stride、通道数、期望螺栓数(int)、`&out`。
|
||
- 每帧(离线用 `sb_process_bolt_module_files`):左图路径、右图路径、期望螺栓数(int)、`&out`。
|
||
|
||
**输出**(`StereoBoltModuleResultC out` + 返回码)
|
||
- 成功 `out.success==1` → `out.data`:
|
||
- `bolts[]` 每颗:`bolt_id` / `left_roi`,`right_roi`(x,y,width,height,score) / **`height_mm`** /
|
||
**`foot_xyz`,`top_xyz`**(底/顶 3D 点) / `centerline`(3D 轴 = point+direction)
|
||
- `adjacent_distances[]`:`bolt_id_i`,`bolt_id_j`,**`distance_mm`**
|
||
- `ground_plane`:`model[4]`(ax+by+cz+d=0)、`rms_mm`、`inlier_count`
|
||
- 失败 `out.success==0` → `out.failure`:`reason` + `left_rois[]`/`right_rois[]` + `pairs[]`(配对诊断)
|
||
|
||
**单位 / 坐标系**:高度、间距 = **mm**;3D 坐标(foot/top/centerline) = **mm,校正后左相机坐标系**
|
||
(x 右 / y 下 / z=深度,典型 z≈1600–2200mm)。`score`=YOLO 置信度。
|
||
|
||
输出格式示例(**仅示意字段结构**,数值来自早先 5MP 验证机,非本包 12MP 相机):
|
||
|
||
```
|
||
success=1 bolts=8 distances=8
|
||
bolt 0 height=151.2mm top=(-191.9,-122.9,1995.3) foot=(-204.3,2.9,2078.3)
|
||
...
|
||
dist 0-1=268.3mm dist 1-2=254.4mm ... dist 7-0=335.8mm
|
||
```
|
||
|
||
> 一句话:**入 = 一对左右图 + 期望螺栓数(配置/标定/模型初始化时给一次);
|
||
> 出 = 每颗螺栓 高度 + 顶/底 3D + 3D 中心轴 + 相邻间距 + 地平面,或失败原因 + 诊断。**
|
||
|
||
---
|
||
|
||
## 编译你自己的调用程序 + 运行(**都在包根目录执行**)
|
||
|
||
```bash
|
||
# 在包根目录(与 lib/ config/ calib/ 同级)编译
|
||
cmake -S example -B example/build -DSB_ROOT="$(pwd)"
|
||
cmake --build example/build
|
||
|
||
# 在包根目录运行(config 里 calib/、weights/ 是相对路径,按当前目录解析)
|
||
# example 走【内存接口】: 读 raw Mono8 裸数据(W*H 字节)喂 sb_process_bolt_module_buffers,
|
||
# 库全程不见文件路径。your_left/right.raw = 你 12MP 相机帧 dump 的 Mono8(4096*3000 字节)
|
||
LD_LIBRARY_PATH=lib:/usr/lib:$LD_LIBRARY_PATH \
|
||
./example/build/bolt_demo config/config.rk3588.yaml your_left.raw your_right.raw 4096 3000 8
|
||
```
|