Files
yolov5-inferrence/README.md
T
2026-07-08 18:35:44 +08:00

284 lines
8.6 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.
# 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 区域过滤,只上传区域内目标。
- 优化识别结果上报逻辑,降低多进程运行时漏帧/低置信波动造成的漏报。
- 增加低置信度、过滤原因、上传决策等日志,便于现场复盘。
## 与 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 推理生效时间段
```
示例:
```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
```
如果不传 `-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 内。
- `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
```