8.5 KiB
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):
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。有两个喂帧入口,生产用内存版:
① 生产路径 —— 内存版(不落盘,直接喂相机帧):
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 左右图):
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_mmground_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 中心轴 + 相邻间距 + 地平面,或失败原因 + 诊断。
编译你自己的调用程序 + 运行(都在包根目录执行)
# 在包根目录(与 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