把NPU检测直接嵌进采集终端|RK3576 AI采集终端全链路拆解教程-上

很多项目里"相机"和"AI 识别"是两套程序:相机管拍,识别另起进程跑。

本文基于触觉智能RK3576开发板Purple Pi OH2开发板制作的采集终端(RkDataTerminal)Demo里做的另一种结合方式------把NPU检测直接嵌进采集链路 :相机取帧→模型出框→框烧进照片→连同当时的通道数据一起归档上报;值守时更是1fps持续检测,人/动物经过就自动拍下带框的留证照片 。

采集终端演示视频:
https://www.bilibili.com/video/BV1Y2pr6aE2X/
深圳触觉智能
,赞107

本文给出链路、关键代码、实测数据,以及"AI 如何部署上板"的完整步骤

目标:不是"拍照 + 识别",而是"拍下即判"

传统做法:相机拍一张图存盘,再让另一个程序读图去推理------两者时间对不上、数据也对不上。

我们要的是一次采集完成三件事 :

  1. 拍摄:拿到现场画面(拍照 4K / 值守低帧率取帧);
  2. 判断:同一时刻送 NPU 推理,得到目标类别与位置;
  3. 留寸:把检测框和当时的采集数据烧进同一张图并入库,附带结构化 JSON。

一句话:证据自证 ------图上既有现场,也有判定,还有当时的数据。

总体设计:三条链路,一张图看懂

三条链路的分工 :

链路 取帧方式 推理频率 用途
拍照留证 Camera2 抓 4K JPEG 每次拍照 1 次 手动/定时/被触发时的证据
值守检测 预览挂 YUV ImageReader ~1fps 持续 决定"什么时候该拍"
远程查看 复用值守帧压 JPEG ~1--2fps 浏览器看现场

相机侧:两条取帧路径

3.1 拍照路径:会话重建(预览 → 拍照 → 回预览)

Camera2 下"预览 / 拍照 / 录像"通常不能同会话共存(尤其这套 legacy 包装的 HAL),所以拍照采用按需重建会话 :

复制代码
预览会话(preview + 值守YUV)
   └─ takePhoto → 换成 still 会话(preview + JPEG ImageReader)
        └─ 出图后 restorePreview() → 回到预览会话

代价是每次重建约1.2s(HAL实测),所以拍照不能太频繁 ------这也是后面"值守 15s冷却"的由来之一。

3.2 值守路径:给预览挂一路 YUV,且必须"随到随清"

值守要在不打断预览的前提下持续拿帧。做法是给预览会话再挂一个720p的YUV ImageReader ,作为重复请求的第二个target。

这里有个极易踩的坑 :如果回调里觉得"没到检测节奏"就直接return、不取帧 ,两个缓冲很快占满,相机侧没有空 buffer 就会停摆------实测帧率掉到~6 秒一帧。

正确写法是每回调必排空,节奏另判 :

复制代码
// CameraController.onWatchFrame()
image = reader.acquireLatestImage();      // 先取走最新帧 → 缓冲永远有空位
if (now - mLastWatchMs < MIN_INTERVAL) {  // 到了节奏才往下送
    return;                               // 已经 drain,直接丢不影响相机
}
mLastWatchMs = now;
mWatchListener.onWatchFrame(w, h, nv21);  // 交给检测线程

一句话记住:ImageReader 必须"随到随清",节流逻辑放后面。

另外两条相机侧硬约束:

  • 预览分辨率必须 ≤1080P:试过 4K 预览,会把 legacy HAL 直接拖崩(device error 3);
  • 拍照/录像期间值守暂停:会话被占用,恢复预览后值守自动续上。

AI 侧:从一帧图像到一组框

4.1 预处理:letterbox 到 640×640(且必须记住缩放与偏移)

模型输入固定640×640,而相机画面是16:9(如1280×720)。直接拉伸会变形,所以用letterbox :等比缩放+居中补边(补灰色114)。

关键是把缩放比和补边量记下来 ,后面才能把模型输出的框坐标反算回原图 :

复制代码
float scale = Math.min(640f / w, 640f / h);   // 等比
int nw = round(w * scale), nh = round(h * scale);
int padX = (640 - nw) / 2, padY = (640 - nh) / 2;   // 补边量
// ...缩放绘制到 640x640,再把像素读成 byte[] RGB 喂给 native

4.2 模型与 runtime 随身带,不依赖固件

不假设固件预装了 NPU 运行时,把两样东西直接打进 APK:

  • librknnrt.so(RKNN runtime,引用树内 hardware/rockchip/rknpu2 模块);

  • yolov5s-640-640.rknn(COCO80 模型,8MB)放在 assets/,首次运行时解包到私有目录再 rknn_init。

Android.bp 里真正关键的两行:

复制代码
cc_library_shared {
    name: "librkdt_yolo",
    stl: "c++_static",     // 必须静态 libc++:App 命名空间没有动态 libc++.so
}
android_app {
    name: "RkDataTerminal",
    jni_libs: ["librkdt_yolo", "librknnrt"],   // 两个 .so 一起内嵌进 APK
}

4.3 推理与后处理:三头 int8 + NMS

native 侧(jni/Detector.cpp + 移植自官方 demo 的 postprocess.cc)职责很单一:

复制代码
rknn_inputs_set(uint8 RGB, NHWC)  →  rknn_run  →  三头 int8 输出        →  反量化(zp/scale) + 置信度过滤 + NMS  →  出框 class/score/box

出框坐标先在 640 坐标系 里,再用 4.1 记下的 scale/padX/padY 反算回原图:

复制代码
原图坐标 = (框坐标 − pad) / scale

这就是"结合"的第一处细节:相机给的尺度和模型要的尺度不一样,中间的 letterbox + 逆映射是必须补齐的一环。

4.4 两条推理入口:位图 与 NV21

  • 拍照链路:detect(Bitmap) ------ 从4K JPEG 采样解码 (decodeSampled(path, 1920))再 letterbox;

  • 值守链路:detectNv21(w,h,byte\[\]) ------ YUV 帧直接 转RGB并letterbox,免一次JPEG解码 。

两条入口共用一套"letterbox→native→逆映射"逻辑,仅喂进去像素来源不同。

复制代码
takePhoto → JPEG(4K)
   ├─ 送 NPU 检测 → dets[]
   ├─ 画水印:站点/SN/时间/8 路通道值 + dets 的框与类别
   └─ 入库:记录 JSON 里追加 detections[],图为带框的 _wm.jpg

结合点:什么时候让 AI 干活

5.1 拍照即判:一次拍照,两种产物

复制代码

检测在原始大图上算,水印在JPEG上 ,两者坐标系一致⇒图上的框就是真实位置。

5.2 值守触发:AI 决定"什么时候按快门"

值守每秒判一帧,命中就自动走上面的"拍照即判":

复制代码
// handleWatchDetections()
if (best != null && best.score >= TRIGGER_SCORE          // 0.55
        && now - mLastAlertMs > ALERT_COOLDOWN_MS) {     // 15s 冷却
    mLastAlertMs = now;
    mAutoNote = label(best.cls) + " " + best.score;      // 写进水印/摘要
    triggerCapture();                                    // 自动留证
}
参数 取值 说明
触发类别 person + 10 类动物 COCO80 里 person 与 bird/cat/dog/horse/sheep/cow/elephant/bear/zebra/giraffe
置信度阈值 0.55 太低误报、太高漏检,实测取中
冷却时间 15s 目标站着不动时不会连拍
检测频率 ~1fps NPU 单帧 0.1--0.2s,够用省电

触发后的记录摘要会带上 值守 person 0.88 前缀------翻记录时一眼就知道"为什么拍了这张"。

相关推荐
comyccccc1 小时前
STM32F103C8T6核心板电路深度解析学习笔记
单片机·嵌入式硬件
专注仿真1 小时前
多智能体强化学习实战:从 Dec-POMDP 到 QMIX/MADDPG/MAPPO 的可运行 PyTorch 实现
人工智能·pytorch·python
IT大白鼠3 小时前
彭大帅的AI运维助手——怎么给AI写运维SOP:提示词设计实战
运维·人工智能·彭大帅
xsd202411188 小时前
3D双目相机 vs 面阵激光雷达:机器人的“眼睛“到底怎么选?
人工智能
智购科技无人售货机厂家9 小时前
压缩机一启动设备就重启,排查发现是电源功率选小了~YH
单片机·嵌入式硬件
2601_965619699 小时前
把开源项目Changelog自动做成更新视频,AI工作流
人工智能·开源·音视频
ACP广源盛139246256739 小时前
Type-C 扩展坞方案选型笔记:DP1.4 转 HDMI2.0 桥接方案评估@ACP
笔记·硬件架构·hdmi·国产芯片·扩展坞
Json____9 小时前
PHP 突发严重安全漏洞,AI 开始改变网络安全的攻防方式
人工智能·web安全·php·it学习·wwwoop.com
fxss10 小时前
我用AI给娃写了个拼音闯关大冒险
人工智能