NanoTrack C++ — RK3588 实时目标跟踪

NanoTrack C++ --- RK3588 实时目标跟踪

基于 Rockchip RK3588 芯片的纯硬件加速 NanoTrack 单目标跟踪器。利用 MPP 硬解码 + RGA 格式转换 + 三核 NPU 并行推理,实现对 H.264 视频流的实时目标跟踪。

项目地址:https://github.com/jiangguolong/NanoTrack-C-for-RK3588/tree/main

演示效果

  • 输入: H.264 裸码流 (1920×1080)
  • 输出: 逐帧绘制跟踪框的图片序列
  • NPU 三核并行: T-backbone (Core 0) + X-backbone (Core 1) + Head (Core 2)

整体架构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        main.cpp (双线程)                         │
│                                                                 │
│  线程1: 解码线程                   线程2: 推理线程                │
│  ┌──────────────────┐            ┌──────────────────┐           │
│  │ MPP 硬解码 H.264 │            │ NanoTracker      │           │
│  │   (NV12 帧)      │            │                  │           │
│  │       ↓          │   队列     │  init() 模板分支  │           │
│  │ RGA 硬转换       │  ───→     │    T-backbone    │           │
│  │  (NV12→RGB888)   │  ←───     │    (NPU Core 0)  │           │
│  │       ↓          │  条件变量  │       ↓          │           │
│  │ DMA 缓冲池(×4)   │           │  track() 搜索分支 │           │
│  │ push → queue     │           │    X-backbone    │           │
│  └──────────────────┘           │    (NPU Core 1)  │           │
│                                 │       ↓          │           │
│                                 │    Head 融合网络  │           │
│                                 │    (NPU Core 2)  │           │
│                                 │       ↓          │           │
│                                 │  后处理 → bbox   │           │
│                                 │       ↓          │           │
│                                 │  画框 + 保存图片  │           │
│                                 └──────────────────┘           │
└─────────────────────────────────────────────────────────────────┘

特性

  • 全硬件加速: MPP 硬解码 → RGA 硬转换 → NPU 硬推理,CPU 仅做轻量级后处理
  • 三核 NPU 并行: T-backbone / X-backbone / Head 分别部署在 NPU Core 0/1/2
  • DMA 零拷贝: 解码→RGA→NPU 全程使用 DMA-BUF 传递,避免 CPU 拷贝
  • 多线程流水线: 解码线程和推理线程通过有界队列异步协作
  • 边界 Padding: 当目标靠近图像边缘时,用通道均值填充,保证模型输入一致性
  • EMA 平滑: 指数移动平均更新跟踪框,抑制抖动
  • 尺度+长宽比惩罚: 抑制跟踪框大小和形状的剧烈突变

硬件要求

组件 要求
芯片 Rockchip RK3588
NPU 三核 (Core 0/1/2),每个至少 1 TOPS
内存 ≥ 4 GB
系统 Linux (aarch64),Glibc ≥ 2.29

软件依赖

用途
RKNN2 NPU 推理运行时
MPP 硬件视频解码
librga RGA 硬件图像处理
OpenCV 4.x 图像裁剪/缩放/绘制 (CPU)
GCC 9+ (aarch64交叉编译) C++17 编译

快速开始

1. 克隆仓库

bash 复制代码
git clone https://github.com/YOUR_USERNAME/NanoTrack-Cpp.git
cd NanoTrack-Cpp

2. 准备模型文件

将 RKNN 模型放入 weights/ 目录:

复制代码
weights/
├── track_backbone_T.rknn    # 模板分支 backbone
├── track_backbone_X.rknn    # 搜索分支 backbone
└── head.rknn                # 融合 head 网络

3. 交叉编译

修改 CMakeLists.txt 中的 RKNN_MODEL_ZOO_ROOT 为你的实际路径,然后:

bash 复制代码
mkdir build && cd build
cmake .. && make -j$(nproc)

4. 运行

bash 复制代码
./nanotrack_demo test.h264 ./output_frames/

参数说明:

参数 默认值 含义
argv[1] test.h264 H.264 裸码流路径
argv[2] ./output_frames 输出图片目录

项目结构

复制代码
.
├── CMakeLists.txt                 # CMake 构建配置 (交叉编译)
├── README.md
├── include/
│   ├── bbox.h                     # 辅助边界框函数
│   ├── config.h                   # 超参数配置
│   ├── dma_alloc.h                # DMA 缓冲区分配 API
│   ├── mpp_decoder.h              # MPP 硬件解码器
│   ├── nanotrack.h                # NanoTrack 跟踪器
│   └── rknn_model.h               # RKNN 模型封装
├── src/
│   ├── main.cpp                   # 主程序 (双线程框架)
│   ├── nanotrack.cpp              # 跟踪器实现 (预处理 + 后处理)
│   ├── rknn_model.cpp             # RKNN 推理封装
│   └── hw_decoder/
│       ├── dma_alloc.cpp          # DMA 缓冲区分配实现
│       └── mpp_decoder.cpp        # MPP 解码器实现
└── weights/                       # RKNN 模型文件 (需自行准备)
    ├── track_backbone_T.rknn
    ├── track_backbone_X.rknn
    └── head.rknn

NanoTrack 算法流程

NanoTrack 是一种基于 Siamese 网络的单目标跟踪算法,分为两个阶段:

初始化阶段 (init)

复制代码
用户框选目标 (x, y, w, h)
        ↓
计算上下文裁剪区域 s_z (含 50% 背景扩展)
        ↓
Crop + Resize → 127×127 BGR 图像
        ↓
T-backbone NPU 推理 → 模板特征图 [48×8×8]
        ↓  存储为 t_output_feature,后续帧复用

跟踪阶段 (track)

复制代码
当前帧 + 上一帧目标位置 → 计算搜索区域 s_x
        ↓
Crop + Resize → 255×255 BGR 图像
        ↓
X-backbone NPU 推理 → 搜索特征图 [48×16×16]
        ↓
Head 融合 (模板特征 + 搜索特征) NPU 推理
        ↓
        ├─ Score 输出 [2×16×16] → Softmax → 前景概率
        └─ BBox 输出  [4×16×16] → 解码 → 边界框坐标
        ↓
尺度惩罚 + 长宽比惩罚 + Hanning 窗权重
        ↓
选最高分 → 反归一化 → EMA 平滑 → 边界裁剪
        ↓
输出最终跟踪框 (x, y, w, h, score)

关键公式

Softmax 置信度:

复制代码
p_score = exp(s1) / (exp(s0) + exp(s1))

边界框解码 (相对于锚点):

复制代码
x1 = px - dx1      y1 = py - dy1
x2 = px + dx2      y2 = py + dy2

尺度惩罚:

复制代码
s_c = max(sz_pred / sz_orig, sz_orig / sz_pred)
penalty = exp(-(r_c × s_c - 1) × PENALTY_K)

EMA 平滑更新:

复制代码
lr = penalty × p_score × LR
new_size = old_size × (1 - lr) + pred_size × lr

多线程设计

复制代码
解码线程 (Producer)              推理线程 (Consumer)
       │                                │
  MPP 解码一帧                     等待队列非空 (wait)
       │                                │
  队列满? ──wait──→ (休眠)          取出队首帧
       │                                │
  push 到队列                      init / track 推理
       │                                │
  notify 消费者                     画框 + 保存图片
       │                                │
       ↓                           notify 生产者
     循环                               ↓
                                     循环
  • MAX_QUEUE_SIZE = 2: 限制缓存,防止内存膨胀
  • g_is_running: 全局退出信号,协调两个线程安全退出
  • std::condition_variable: 条件变量实现阻塞等待/唤醒

配置参数

include/config.h 中可调整跟踪行为:

参数 默认值 含义
POINT::STRIDE 16 锚点步长
TRACK::EXEMPLAR_SIZE 127 模板裁剪尺寸
TRACK::INSTANCE_SIZE 255 搜索区域裁剪尺寸
TRACK::BASE_SIZE 7 score 图基础尺寸
TRACK::CONTEXT_AMOUNT 0.5 上下文扩展比例
TRACK::PENALTY_K 0.15 尺度/长宽比惩罚强度
TRACK::WINDOW_INFLUENCE 0.49 中心偏好权重
TRACK::LR 0.385 EMA 平滑学习率

代码统计

复制代码
语言: C++17
总行数: ~1100 行
文件数: 7 头文件 + 5 源文件
文件 行数 职责
src/nanotrack.cpp 283 核心跟踪算法
src/main.cpp 134 主线程框架
src/hw_decoder/mpp_decoder.cpp 173 MPP 硬解码 + RGA 转换
src/hw_decoder/dma_alloc.cpp 150 DMA 物理内存分配
src/rknn_model.cpp 84 RKNN 模型加载/推理

致谢

License

MIT License

相关推荐
ysa0510301 小时前
【并查集】判环
c++·笔记·算法
持力行2 小时前
C/C++ 中的 char*:它标识数组吗?为什么能用下标访问?
c语言·c++
汉克老师3 小时前
GESP2026年6月认证C++六级( 第三部分编程题(2、满二叉树))精讲
c++·深度优先·树形dp·满二叉树·gesp六级·树形dfs
踮起脚看烟花4 小时前
多人聊天室实现v2.0
c++·信息与通信
梦帮科技4 小时前
UE5 GAS 实战:用 Gameplay Ability System 搭建「赛博修真」境界与技能体系
c++·人工智能·python·ue5·c#
旖-旎4 小时前
QT系统篇(5)(下)
开发语言·c++·qt
99乘法口诀万物皆可变4 小时前
PcanToVectorXL_V01:打通 Vector 与 PCAN 的双向 CAN/CAN‑FD 桥梁
c++·学习
liulun5 小时前
C++ WinRT中的事件
开发语言·c++
whitelbwwww5 小时前
c++运行onnx模型
开发语言·c++