2026-07-01 18:16:18 +08:00

227 lines
14 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.

# 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.rknn` | NPU 模型 —— OBB 检测(精测+测距共用imgsz 1024FP16 |
| `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≈16002200mm
**★ 部分输出契约(去 all-or-nothing**:即使 `success==0`(数量不符 `count_mismatch`,无论检到的多还是少于 `expected`
`data.bolts[]` 仍含**所有干净测出的螺栓**(各带 height/top/foot/confidence`failure`reason + 完整 ROI + 配对状态)始终填充,能看出缺哪颗、为何缺。**别只看返回码就丢结果——照样遍历 `data.bolts[]`,按 `confidence` 自行取舍。**
**最简用法(`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 模型,自动检测旋转框);交付权重 FP16INT8 检出全废,不可用)。
---
## 高度测量模式(`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 内存 buffer12MP→3MP=2048×1500Mono8/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.32.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** |
| 定位 | 触发式"测得准" | 无人机实时定位反馈 |
> 测距实测于 RK3588best_obb_1024.rknndistance_153304_40321 帧):均值 153.146ms,距离均值 1652.360mm,跨度 0.491mm。
> 本交付为单模型 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.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.rknn L.bmp R.bmp
```