293 lines
9.1 KiB
Markdown
293 lines
9.1 KiB
Markdown
# yolov5-inference
|
||
|
||
本项目用于在 RK1808/aarch64 设备上运行 YOLOv5 RKNN 推理程序。程序从 RTSP 视频流或 `.h264` 文件读取 H264 数据,通过 FFmpeg 拉流、MPP 解码、RGA 转换为 `640x640 RGB`,再交给 RKNN 执行 YOLOv5 推理,最后将识别结果通过本地 HTTP 接口发给管理程序。
|
||
|
||
当前说明对应分支:
|
||
|
||
```text
|
||
time_period_P_r30_linaro
|
||
```
|
||
|
||
## 当前版本重点
|
||
|
||
本分支是在 `main` 分支基础上面向现场 RK1808 设备做的稳定性版本,重点解决:
|
||
|
||
- 目标设备运行库较旧,需要使用 Linaro GCC 7.4.1 交叉编译,避免引入高版本 `glibc/libstdc++` 依赖。
|
||
- 支持按时间段控制是否执行推理。
|
||
- 支持 workspace 区域过滤,默认只上传区域内目标,也可通过 `-R` 反向为只上传区域外目标。
|
||
- 优化识别结果上报逻辑,降低多进程运行时漏帧/低置信波动造成的漏报。
|
||
- 增加低置信度、过滤原因、上传决策等日志,便于现场复盘。
|
||
|
||
## 与 main 分支的区别
|
||
|
||
当前分支相对 `main` 的主要修改点:
|
||
|
||
- 交叉编译路线固定为 WSL + Linaro GCC 7.4.1。
|
||
- `CMakeLists.txt` 中直接指定 aarch64 Linaro 工具链。
|
||
- 新增 `--time-period` / `-P` 参数,用于配置推理生效时间段。
|
||
- `--threshold` / `-r` 阈值限制为 `30` 到 `90`,即 `0.30` 到 `0.90`。
|
||
- 新增低置信度检测日志和可选截图脚本 `low_conf_snapshot.sh`。
|
||
- 替换旧的连续帧去抖逻辑:
|
||
- 旧逻辑要求同一数量连续稳定多帧才上传,资源紧张或漏帧时可能上传 `number=0`。
|
||
- 当前逻辑检测到目标就上传正例 `number > 0`。
|
||
- 未检测到目标时只记录日志,不主动上传 `number=0`。
|
||
- 同一最终业务编码 `class_idx` 每 `500ms` 最多上传一次正例。
|
||
- `0.30 <= prop < threshold` 的弱命中也参与正例上传,用于降低漏报。
|
||
- 修复 h264 分段文件轮转时 `fpSave` 局部变量遮蔽风险,并在退出时关闭文件句柄。
|
||
|
||
## 模型文件
|
||
|
||
模型文件放在程序运行目录下,假设模型名为 `abc`,需要准备:
|
||
|
||
```text
|
||
./abc/abc.rknn
|
||
./abc/abc.txt
|
||
./abc/abc_code.txt
|
||
```
|
||
|
||
说明:
|
||
|
||
- `abc.rknn`:RKNN 模型文件。
|
||
- `abc.txt`:类别名称文件,一行一个类别。
|
||
- `abc_code.txt`:类别对应的业务编码,一行一个整数。
|
||
|
||
如果多个类别在 `abc_code.txt` 中配置成同一个编码,程序上传前会按同一个 `class_idx` 合并数量。
|
||
|
||
## 编译
|
||
|
||
详细交叉编译说明见:
|
||
|
||
```text
|
||
docs/cross_compile_wsl_linaro.md
|
||
```
|
||
|
||
推荐在 Windows PowerShell 中调用 WSL 编译:
|
||
|
||
```powershell
|
||
wsl -d Ubuntu bash -lc "rm -rf /home/smos/yolov5-linaro-build && mkdir -p /home/smos/yolov5-linaro-build && cd /home/smos/yolov5-linaro-build && cmake /mnt/c/Users/Smos.DESKTOP-6MT98U8/Desktop/yolov5-inference && make -j16 && file yolov5"
|
||
```
|
||
|
||
产物路径:
|
||
|
||
```text
|
||
/home/smos/yolov5-linaro-build/yolov5
|
||
```
|
||
|
||
验证产物:
|
||
|
||
```bash
|
||
file /home/smos/yolov5-linaro-build/yolov5
|
||
/home/smos/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf --version-info /home/smos/yolov5-linaro-build/yolov5 | grep -E 'GLIBC_2\.33|GLIBC_2\.34|GLIBCXX_3\.4\.29'
|
||
/home/smos/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf -d /home/smos/yolov5-linaro-build/yolov5 | grep rknn
|
||
```
|
||
|
||
预期:
|
||
|
||
- `file` 显示 `ELF 64-bit LSB executable, ARM aarch64`。
|
||
- 高版本 `GLIBC_2.33`、`GLIBC_2.34`、`GLIBCXX_3.4.29` 检查没有输出。
|
||
- RKNN 链接显示 `librknn_api.so`。
|
||
|
||
## 运行
|
||
|
||
常用参数:
|
||
|
||
```text
|
||
-s, --server RTSP 地址或 h264 文件路径
|
||
-m, --model 模型名,默认 yolov5s
|
||
-c, --camera-id 摄像头 ID,必填
|
||
-t, --type-id 管理程序事件类型
|
||
-p, --upload-port 管理程序本地 HTTP 端口
|
||
-w, --workspace 检测区域,多边形点坐标,逗号分隔
|
||
-r, --threshold 置信度阈值,整数 30 到 90
|
||
-P, --time-period 推理生效时间段
|
||
-R, --reverse-workspace 反向 workspace 过滤,上传 -w 区域外目标
|
||
```
|
||
|
||
示例:
|
||
|
||
```bash
|
||
./yolov5 \
|
||
-s rtsp://127.0.0.1/live \
|
||
-m abc \
|
||
-c camera001 \
|
||
-t 19 \
|
||
-p 8080 \
|
||
-r 60
|
||
```
|
||
|
||
workspace 示例:
|
||
|
||
```bash
|
||
./yolov5 -s input.h264 -m abc -c camera001 -t 19 -p 8080 -w 100,100,500,100,500,500,100,500
|
||
```
|
||
|
||
反向 workspace 示例:
|
||
|
||
```bash
|
||
./yolov5 -s input.h264 -m abc -c camera001 -t 19 -p 8080 -w 100,100,500,100,500,500,100,500 -R
|
||
```
|
||
|
||
开启 `-R` 后,`-w` 画出的区域会作为排除区域:区域内目标不上报,只上报区域外目标。`-R` 必须配合 `-w` 使用。
|
||
|
||
如果不传 `-w`,默认全画面有效。
|
||
|
||
time-period 示例:
|
||
|
||
```bash
|
||
./yolov5 -s input.h264 -m abc -c camera001 -t 19 -p 8080 -P 08:00:00-18:00:00
|
||
```
|
||
|
||
排除某些时间段:
|
||
|
||
```bash
|
||
./yolov5 -s input.h264 -m abc -c camera001 -t 19 -p 8080 -P '!00:00:00-06:00:00,22:00:00-23:59:59'
|
||
```
|
||
|
||
## 输出与日志
|
||
|
||
程序会创建摄像头目录:
|
||
|
||
```text
|
||
/usr/data/camera/<camera-id>/
|
||
/usr/data/camera/<camera-id>/picsave/
|
||
/usr/data/camera/<camera-id>/frames/
|
||
```
|
||
|
||
h264 分段文件会写到:
|
||
|
||
```text
|
||
/usr/data/camera/<camera-id>/<time>.h264
|
||
```
|
||
|
||
检测日志写在可执行文件同目录:
|
||
|
||
```text
|
||
.log/YYYY-MM-DD-yolov5.log
|
||
```
|
||
|
||
日志清理规则:
|
||
|
||
- 程序启动后第一次写日志会清理旧日志。
|
||
- 程序长期运行跨天后,第一次打开新日期日志时也会清理旧日志。
|
||
- 只清理 `.log` 目录下命名匹配 `YYYY-MM-DD-yolov5.log` 的文件。
|
||
- 默认保留最近约 7 天日志。
|
||
|
||
常见日志事件:
|
||
|
||
- `frame_seen`:本次推理帧序号和原始检测数量。
|
||
- `strong_present`:超过阈值且通过 workspace 过滤。
|
||
- `weak_present`:高于 `0.30`、低于阈值且通过 workspace 过滤。
|
||
- `filtered_low_conf`:低于 `0.30`。
|
||
- `filtered_workspace`:未通过 workspace 过滤。`workspace_mode=normal` 表示普通模式,`workspace_mode=reverse` 表示 `-R` 反向模式。
|
||
- `no_target`:本帧没有可上传目标。
|
||
- `upload_positive`:本帧触发正例上传。
|
||
- `upload_skip_throttle`:同一 `class_idx` 500ms 节流跳过。
|
||
- `upload_positive_payload`:实际组装进 JSON 的正例载荷。
|
||
|
||
如需低置信截图辅助排查,将 `low_conf_snapshot.sh` 放到可执行文件同目录,并确保有执行权限。脚本不存在或不可执行时,主程序仍可正常运行。
|
||
|
||
## 上报逻辑
|
||
|
||
推理结果业务包向本地管理程序发送:
|
||
|
||
```text
|
||
POST http://127.0.0.1:<upload-port>/video/post
|
||
```
|
||
|
||
JSON 结构:
|
||
|
||
```json
|
||
{
|
||
"message_type": "inference_result",
|
||
"schema_version": 1,
|
||
"serial": "camera001",
|
||
"type": 19,
|
||
"at": 1778826272,
|
||
"params": [
|
||
{
|
||
"class_idx": 23105,
|
||
"name": "play",
|
||
"number": 1
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `message_type` 固定为 `inference_result`,用于和心跳包区分。
|
||
- `schema_version` 当前为 `1`。
|
||
- `serial` 来自启动参数 `-c`,在管理程序中可作为推理进程身份。
|
||
- `type` 来自启动参数 `-t`。
|
||
- `at` 为推理端当前时间戳。
|
||
- `params[].class_idx` 来自模型目录下 `<model>_code.txt`。
|
||
- `params[].name` 来自模型目录下 `<model>.txt`。
|
||
- `params[].number` 为当前帧同一 `class_idx` 的检测数量;多个 label 映射到同一个 `class_idx` 时会合并数量。
|
||
|
||
当前版本只主动上传 `number > 0` 的正例。目标未检出时不上传 `number=0`,只写日志。业务包不会承担心跳职责。
|
||
|
||
## 心跳机制
|
||
|
||
推理程序新增独立心跳接口:
|
||
|
||
```text
|
||
POST http://127.0.0.1:<upload-port>/heartbeat
|
||
```
|
||
|
||
只有启动参数指定了有效 `-p <upload-port>`,并且 `-c <processUUID>` 非空时,才会发送心跳。当前心跳周期为 `HEARTBEAT_SECS = 60` 秒。
|
||
|
||
心跳包结构:
|
||
|
||
```json
|
||
{
|
||
"message_type": "heartbeat",
|
||
"schema_version": 1,
|
||
"serial": "camera001",
|
||
"process_uuid": "camera001",
|
||
"status": "running",
|
||
"timestamp": 1778826272
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `message_type` 固定为 `heartbeat`。
|
||
- `schema_version` 当前为 `1`。
|
||
- `serial` 来自启动参数 `-c`,必填且非空。
|
||
- `process_uuid` 同样来自启动参数 `-c`,用于管理程序校验端口对应的推理进程。
|
||
- `status` 当前固定为 `running`。
|
||
- `timestamp` 为推理端当前时间戳。
|
||
|
||
心跳发送点在解码帧完成 RGA 转换之后、`-P/--time-period` 时间段判断之前。因此即使当前时间段不执行识别,只要程序仍在正常读流解码,也会继续发送心跳。
|
||
|
||
管理程序建议按以下规则区分:
|
||
|
||
```text
|
||
/heartbeat + message_type=heartbeat -> 只刷新心跳,不进入业务判断
|
||
/video/post + message_type=inference_result -> 推理业务结果
|
||
```
|
||
|
||
## G1000 截图通知客户端
|
||
|
||
推理端的 G1000 主控截图通知客户端代码保存在本仓库根目录:
|
||
|
||
```text
|
||
snapshot_notify.h
|
||
snapshot_notify.cpp
|
||
```
|
||
|
||
这两个文件由 `CMakeLists.txt` 编译进 `yolov5`,在 `upload_positive` 日志产生时向主控截图服务发送轻量 UDP 事件。发送结果会追加到同一条检测日志:
|
||
|
||
```text
|
||
snapshot_notify=ok
|
||
snapshot_notify=failed reason=<err>
|
||
```
|
||
|
||
截图服务端代码不放在本仓库,独立保存在 `g1000-snapshot-service` 仓库中。
|
||
|
||
更详细的去抖优化记录见:
|
||
|
||
```text
|
||
docs/debounce_positive_upload_plan.md
|
||
```
|