228 lines
14 KiB
Markdown
228 lines
14 KiB
Markdown
# libstereo_bolt 交付说明(.so + 头文件)
|
||
|
||
你拿到的是**预编译的 aarch64 动态库 + C 头文件 + 模型 + 标定 + 示例**,不含算法源码。
|
||
运行时依赖中 **`libstereo_bolt.so`、OpenCV 4.5.0 `.so`、`librknnrt.so` 均已随包 `lib/`**;无需 apt 安装 OpenCV。NPU 驱动由板子系统提供。
|
||
|
||
> **本库导出两个独立的产品接口**(同一个 `.so`、同一个 `StereoBoltCtx`):
|
||
> 1. **精测(PRECISE)** `sb_process_bolt_module_buffers` / `_files` —— 12MP 高精度测量,
|
||
> 每颗螺栓高度 / 相邻间距 / 地平面 / 3D 中心轴 / 顶底 3D 坐标。**触发式"测得准"路径(板上约 400ms/帧,依输入和 QC 耗时波动)。**
|
||
> 2. **测距(RANGING)** `sb_range_bolt_binned` —— 2×2 binned(3MP) 实时测距,
|
||
> 输出相机→螺栓代表直线距离。**无人机实时路径(统一用 OBB@1024,当前 distance_153304_403 复测约 153ms/帧)。**
|
||
>
|
||
> **创建上下文推荐用内存接口 `sb_create_ex`**(见下节):标定、模型、参数全部经接口/buffer 传入,
|
||
> 库**零文件 IO、无路径假设、无安装目录读权限问题**。旧的 `sb_create(config.yaml)` 仍保留作向后兼容。
|
||
|
||
---
|
||
|
||
## ★ 创建上下文:`sb_create_ex`(推荐)vs `sb_create`(兼容)
|
||
|
||
两个产品接口共用同一个 `StereoBoltCtx`。创建它有两种方式:
|
||
|
||
### 推荐:`sb_create_ex` —— 全参数经接口传入,零文件 IO
|
||
```c
|
||
StereoBoltCtx* sb_create_ex(const StereoBoltCalibC* calib,
|
||
const StereoBoltModelC* model,
|
||
const StereoBoltParamsC* params);
|
||
StereoBoltParamsC sb_default_params(void); /* 预填默认值,再覆盖你关心的 */
|
||
```
|
||
- `StereoBoltCalibC`:标定 —— 左右 `K[9]`/`D[5]` + `R[9]`/`T[3]` + `baseline_mm` + 图像尺寸。**替代标定 XML。**
|
||
- `StereoBoltModelC`:模型 —— `.rknn` 字节流 `data`+`size` + `backend`(rk3588 用 `SB_YOLO_BACKEND_RKNN`) + `imgsz`/`conf`/`iou`。**替代 weights 文件路径。**
|
||
- `StereoBoltParamsC`:算法数值参数 —— 视差带(`wd_z_min/max_mm` 物理带,**或** `sgbm_min/num_disparities` 固定带,二选一必填)、`rectification`、`measurement.foot_rim`、`ranging.*`。**替代 config.yaml 数值键。** 带 `struct_size` 做前向兼容。
|
||
|
||
**这条路径库不碰磁盘**:标定/模型从哪来由你决定(你的标定流程、资源文件、相机 SDK);本包提供的 `calib/*.xml` 与 `weights/*.rknn` 只是**给你读进来填结构体**的现成数据。
|
||
|
||
### 兼容:`sb_create(const char* config_yaml_path)`
|
||
读 `config.rk3588.12mp.yaml`(其内部再按相对路径找标定 XML + 模型)。**有两文件依赖 + 工作目录/读权限要求**——正是 `sb_create_ex` 要规避的。仅在离线/快速测试时用。
|
||
|
||
> `sb_create` / `sb_create_ex` **只调一次**(载配置+标定+模型进 NPU,慢),之后每帧复用同一个 `ctx`。
|
||
> `sb_destroy` / `sb_last_error` 两接口共用。线程安全:同一 `ctx` 别多线程并发。
|
||
|
||
---
|
||
|
||
## 交付边界(职责划分)
|
||
|
||
**本交付物是一个"算法模块",不是完整软件系统。** 软件总体集成由你(接入方)负责。
|
||
|
||
| 项 | 由谁负责 |
|
||
|---|---|
|
||
| 双目螺栓**测量/测距算法**(`.so` + `.h` + 模型 + 标定 + 示例 + 文档) | **算法方(本包提供)** |
|
||
| 板子**运行时环境**:aarch64 + glibc、NPU 驱动;算法依赖的 OpenCV 与 `librknnrt.so` 已随包 `lib/` | **接入方** |
|
||
| **取图**(相机驱动 / Mono8 buffer 喂入)、上层业务、UI、调度、与上位机/无人机通信 | **接入方** |
|
||
| **标定数据来源**(填入 `StereoBoltCalibC`)、按 `c_api.h` 调用、对 height/distance/confidence 做业务决策 | **接入方** |
|
||
|
||
> 算法方只交付"喂进左右图 → 返回螺栓高度/距离"的纯算法能力(C ABI)。本库不碰相机、不碰网络、
|
||
> **不碰磁盘(`sb_create_ex` + buffer 接口)**、不做悬停/对中等业务决策。逐颗 `confidence`(trusted/suspect) + `status` 由接入方取舍。
|
||
|
||
## 包内容
|
||
| 路径 | 说明 |
|
||
|---|---|
|
||
| `lib/libstereo_bolt.so` | 预编译共享库(aarch64,含 `sb_create_ex` 内存接口) |
|
||
| `include/stereo_bolt/c_api.h` | C ABI 头文件(唯一对外接口) |
|
||
| `weights/best_obb_1024_0703_20260702.rknn` | NPU 模型 —— OBB 检测(精测+测距共用,imgsz 1024,FP16) |
|
||
| `calib/stereo_calib_20260621_202857_ascii.xml` | 12MP 双目标定(**0621 装配 baseline 482mm**,Halcon 位姿已修正) |
|
||
| `config/config.rk3588.12mp.yaml` | 仅 `sb_create`(兼容)用 + 作参数参考;**`sb_create_ex` 不需要它** |
|
||
| `lib/*.so` | 算法库、OpenCV 4.5.0 运行库、RKNN 运行时(aarch64 2.3.2),运行时通过 `LD_LIBRARY_PATH=./lib` 加载 |
|
||
| `INSTALL_3588.md` / `ABI_FINGERPRINT.txt` | 板上装环境说明 / .so 二进制指纹(**你的环境必须匹配**) |
|
||
| `example/` | C 调用示例(`main.c` 精测,**sb_create + buffer 接口**)+ CMakeLists |
|
||
|
||
---
|
||
|
||
## 编译期 vs 运行期
|
||
|
||
**你不需要重编这个库**(预编译成品,无源码)。你只编译*你自己*调用它的程序。
|
||
|
||
| 东西 | 编译你的调用程序 | 板上运行 |
|
||
|---|:---:|:---:|
|
||
| `c_api.h` | ✅ | — |
|
||
| `libstereo_bolt.so` | ✅(链接,带 `--allow-shlib-undefined`) | ✅ |
|
||
| OpenCV | 你的程序:❌ 不需要(C ABI 不暴露 cv 类型,相机直接给 Mono8 buffer)<br>本包 example:❌ 运行不需要系统 OpenCV | ✅ 已随包 `lib/`,无需 apt |
|
||
| `librknnrt.so` | ❌ | ✅ 已随包 `lib/`,`LD_LIBRARY_PATH=./lib` |
|
||
| NPU 驱动 + `/dev/rknpu` | ❌ | ✅ 必须(内核态) |
|
||
| 模型 / 标定 | ❌ | ✅(已在本包;`sb_create_ex` 由你读进来传,`sb_create` 由库读) |
|
||
|
||
> example 用 OpenCV 只是为了独立跑(读本包的标定 XML + 测试图)。**你的产品里相机直接给 Mono8 buffer、
|
||
> 标定来自你自己的来源,调用端无需 OpenCV,库也始终零文件 IO。**
|
||
|
||
---
|
||
|
||
## ⚠️ 必须匹配的 ABI 指纹
|
||
|
||
`.so` 二进制里写死了依赖的 so 名字和 glibc 版本。打开 `ABI_FINGERPRINT.txt` 确保板子满足:
|
||
- CPU = **aarch64**;**glibc ≥ 指纹版本**(GLIBC_2.32);
|
||
- **运行时优先使用本包 `lib/`**(内含标准 SONAME `libopencv_*.so.4.5`,无需系统 OpenCV);
|
||
- **librknnrt 版本** = 转 `.rknn` 的 toolkit 版本(**2.3.x**)。
|
||
- 指纹应列出 9 个导出符号,含 **`sb_create_ex` / `sb_default_params`**。
|
||
|
||
自检(应无任何 `not found`):`ldd lib/libstereo_bolt.so | grep "not found"`
|
||
|
||
---
|
||
|
||
## 公共错误码
|
||
|
||
`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` 不是崩溃,是算法判定该帧不满足 `expected` 颗(仅精测返回);**仍返回已测出的部分螺栓**(见下)。
|
||
|
||
---
|
||
|
||
## 接口 1 —— 精测(PRECISE)
|
||
|
||
**用途**:12MP 逐颗高精度测量。触发式"测得准"路径,板上 ~2.5Hz@1024。
|
||
**输入**:内存 Mono8 buffer(生产首选)或文件路径(离线)。buffer 尺寸**必须等于标定尺寸**,否则 `SB_ERR_IO`。
|
||
|
||
```c
|
||
sb_status_t sb_process_bolt_module_buffers(
|
||
StereoBoltCtx* ctx,
|
||
const uint8_t* left_data, int left_width, int left_height, int left_stride_bytes,
|
||
const uint8_t* right_data, int right_width, int right_height, int right_stride_bytes,
|
||
int channels, int expected_bolt_count, StereoBoltModuleResultC* out);
|
||
sb_status_t sb_process_bolt_module_files(StereoBoltCtx*, const char* left, const char* right,
|
||
int expected_bolt_count, StereoBoltModuleResultC* out);
|
||
void sb_free_bolt_module_result(StereoBoltModuleResultC* out); /* 用完必须释放 */
|
||
```
|
||
|
||
**输出 `StereoBoltModuleResultC`** —— 每颗 `data.bolts[i]`:
|
||
- **`height_mm`**(高度)
|
||
- **`top_xyz` / `foot_xyz`**(顶 / 底 3D 坐标)
|
||
- **`centerline`**(3D 中心轴:`point` + `direction`)
|
||
- `left_roi` / `right_roi`(左右图 2D 框 x,y,w,h,score)
|
||
- **`confidence`**(0=trusted / 1=suspect)+ `status`
|
||
另含 `adjacent_distances[]`(相邻 `distance_mm`)、`ground_plane`(`model[4]`/`rms_mm`/`inlier_count`)。
|
||
|
||
**坐标系/单位**:高度、间距、3D 坐标 = **mm**,**校正后左相机坐标系**(x 右 / y 下 / z=深度,典型 z≈1600–2200mm)。
|
||
|
||
**★ 部分输出契约(但不导出假高度)**:即使 `success==0`(数量不符 `count_mismatch`,无论检到的多还是少于 `expected`),
|
||
`data.bolts[]` 只包含**完整右目配对且测量干净的螺栓**(各带 height/top/foot/confidence)。`idx_R < 0` 的 left-only fallback 不作为产品高度输出,避免误导。`failure`(reason + 完整 ROI + 配对状态)始终填充,能看出缺哪颗、为何缺。
|
||
|
||
**最简用法(`sb_create_ex`)**:
|
||
```c
|
||
StereoBoltCalibC calib = {...}; /* 填 K/D/R/T/size/baseline */
|
||
StereoBoltModelC model = {.data=rknn_bytes, .size=n, .backend=SB_YOLO_BACKEND_RKNN, .imgsz=1024, .conf=0.5f};
|
||
StereoBoltParamsC p = sb_default_params(); p.wd_z_min_mm=1200; p.wd_z_max_mm=2800;
|
||
StereoBoltCtx* ctx = sb_create_ex(&calib, &model, &p); /* 一次 */
|
||
StereoBoltModuleResultC out;
|
||
sb_process_bolt_module_buffers(ctx, L,w,h,0, R,w,h,0, 1, /*expected=*/6, &out);
|
||
/* 遍历 out.data.bolts[i].height_mm / top_xyz / foot_xyz ... */
|
||
sb_free_bolt_module_result(&out); sb_destroy(ctx);
|
||
```
|
||
完整示例见 `example/main.c`。**imgsz 首选 1024**(OBB 模型,自动检测旋转框);交付权重 FP16(INT8 检出全废,不可用)。
|
||
|
||
---
|
||
|
||
## 高度测量模式(`measurement.height_from_plane`)
|
||
|
||
精测接口支持两种高度计算方式,通过 config 中 `measurement.height_from_plane` 切换:
|
||
|
||
| 模式 | config 值 | 高度定义 | 是否需要平面拟合 | 板上耗时(8颗场景) |
|
||
|---|---|---|---|---|
|
||
| **顶到底**(默认) | `height_from_plane: false` | 螺杆顶端到可见底端沿拟合轴的长度 | **不需要**(自动跳过) | ~400ms |
|
||
| **顶到平面** | `height_from_plane: true` | 螺杆顶端到支撑平面的法向距离 | 需要(StereoBM 拟合) | ~800ms |
|
||
|
||
**默认关闭平面测量**(`height_from_plane: false`),此时平面计算完全跳过,节省 300-550ms。
|
||
|
||
**开启平面测量**:在 `config.rk3588.12mp.yaml` 中修改:
|
||
```yaml
|
||
measurement:
|
||
height_from_plane: true # 开启:高度 = 螺杆顶端到支撑平面的法向距离
|
||
```
|
||
|
||
`sb_create_ex` 用户:当前 `StereoBoltParamsC` 不含此字段,默认为 false(顶到底)。如需平面模式,使用 `sb_create(config.yaml)` 并在 config 中设置。
|
||
|
||
---
|
||
|
||
## 接口 2 —— 测距(RANGING)`sb_range_bolt_binned`
|
||
|
||
**用途**:实时回答"左目光心→螺栓多远"。容忍部分可见:**绝不要求螺栓数**,≥1 颗即给距离。当前板上约 153ms/帧(~6.5Hz)@1024。
|
||
**输入**:2×2 binned 内存 buffer(12MP→3MP=2048×1500),Mono8/BGR。binned 内参**内部推导**,无需单独 binned 标定。
|
||
|
||
```c
|
||
typedef struct { double distance_mm; int left_x,left_y,right_x,right_y; double ncc_score,lrc_px; int confidence; } StereoBoltRangeBoltC;
|
||
typedef struct { int found; double distance_mm; int bolt_count; char status[32]; } StereoBoltRangeSummaryC;
|
||
sb_status_t sb_range_bolt_binned(
|
||
StereoBoltCtx* ctx,
|
||
const uint8_t* left_data, int left_width, int left_height, int left_stride_bytes,
|
||
const uint8_t* right_data, int right_width, int right_height, int right_stride_bytes,
|
||
int channels, StereoBoltRangeSummaryC* out, StereoBoltRangeBoltC* bolts, int max_bolts);
|
||
```
|
||
**输出**:主用 `out.distance_mm`(可见杆代表距离);`out.found` 每帧轮询;`bolts[]` 给出每颗候选的左右匹配点。OBB 轴路线下 `ncc_score` 为检测/匹配分数、`lrc_px` 为轴视差自洽度(字段名保留用于 ABI 兼容);NCC 回退路线下为 NCC/LRC 指标。精度目标 **±50mm**(稳定区 1.3–2.4m)。
|
||
**可选 `ranging.*` 参数**(`StereoBoltParamsC` 里 `rng_*`,都有默认):`z_min/max_mm` 视差带、`lrc_max_mm`/`lrc_trusted_mm` 物理同根门 等。完整示例见 `example/range_example.cpp`。
|
||
|
||
> 注:`sb_create_ex` 即使**只做测距**也要求提供精测视差带(`wd_z_*` 或 `sgbm_*`),因为同一 `ctx` 两接口共用。
|
||
|
||
---
|
||
|
||
## 该用哪个 + 板上实测吞吐
|
||
|
||
| | 精测 `sb_process_bolt_module_*` | 测距 `sb_range_bolt_binned` |
|
||
|---|---|---|
|
||
| 问题 | 每颗螺栓高度/间距/地平面/3D 坐标 | 相机离螺栓多远(代表距离) |
|
||
| 输入 | 12MP 原图(Mono8 buffer / 文件) | 2×2 binned 3MP buffer |
|
||
| 螺栓数 | 要 `expected`(不符=部分输出+`count_mismatch`) | **不要**,≥1 颗即 `found` |
|
||
| 板上吞吐@1024 | **约 400ms/帧** | **约 153ms/帧 ≈ 6.5Hz** |
|
||
| 定位 | 触发式"测得准" | 无人机实时定位反馈 |
|
||
|
||
> 测距历史基准于 RK3588(v4 旧模型 best_obb_1024.rknn,distance_153304_403,21 帧):均值 153.146ms,距离均值 1652.360mm,跨度 0.491mm。
|
||
> v5(0703 模型)板上测距复核 0702-12mp:8/8 螺杆 status=ok,逐杆距离 1.5–2.2m 连贯;整帧 ~450–475ms。
|
||
> 本交付为单模型 OBB@1024(精测+测距共用)。
|
||
|
||
---
|
||
|
||
## 编译你的调用程序 + 运行
|
||
|
||
示例用 C/C++,运行时库从本包 `lib/` 加载:
|
||
```bash
|
||
cd example
|
||
cmake -S . -B build -DSB_ROOT="$(cd .. && pwd)"
|
||
cmake --build build # -> bolt_demo(精测)+ range_demo(测距)
|
||
|
||
# ../lib 含 libstereo_bolt.so + OpenCV 4.5.0 + librknnrt.so
|
||
# 精测:传标定 XML + 模型 + 左右图 + 期望螺栓数
|
||
LD_LIBRARY_PATH=../lib:$LD_LIBRARY_PATH \
|
||
./build/bolt_demo ../calib/stereo_calib_20260621_202857_ascii.xml \
|
||
../weights/best_obb_1024_0703_20260702.rknn L.bmp R.bmp 6
|
||
|
||
# 测距:传标定 + 模型 + 左右图(demo 内部 2×2 binning;生产直接喂相机 binned buffer)
|
||
LD_LIBRARY_PATH=../lib:$LD_LIBRARY_PATH \
|
||
./build/range_demo ../calib/stereo_calib_20260621_202857_ascii.xml \
|
||
../weights/best_obb_1024_0703_20260702.rknn L.bmp R.bmp
|
||
```
|