当前位置: 首页 > news >正文

RK3588芯片NPU的使用:官方rknn_yolov5_android_apk_demo运行与解读

一、本文的目标

本文将完成两项任务:

  • 官方的调用摄像头动态目标识别例子运行在rk3588的开发板上。
  • 解读源码以增加对rknn开发的认识。

二、开发环境说明

  • 主机系统:Windows 11
  • 目标设备:搭载RK3588芯片的安卓开发板
  • 核心工具:Android Studio Koala | 2024.1.1 Patch 2,NDK 27.0

三、编译与运行

0. 源码位置

官方路径在rknn-toolkit2\rknpu2\examples\rknn_yolov5_android_apk_demo,找不到也可以找我。

1.目录结构

如下图:

2.编译与运行

自打开工程后,自动下载依赖,到点击运行,在rk3588开发板跑起来,一路没遇到阻碍。下图为运行效果,识别出来手机图片中的三巨头。

四、代码解读

1.核心问题

本案例是在相机预览实时进行目标检测,那么有以下几个核心问题要解决:

  1. 相机使用:案例中使用第一代Camera API,虽然API已不建议使用,但能工作就是好汉。
  2. 并发工作:相机一边预览,程序一边使用yolov5做目标检测。需要有一个专用来检测的推理线程。
  3. 图像格式转换:安卓中Camera API的预览帧是NV21格式,而瑞芯微NPU中需要换成RGB888格式。
  4. 需要有一个容器缓存预览帧:要设计一个图片缓存队列。

2.程序的主流程

建议从CameraPreviewActivity开始分析,逻辑逐渐在这里展开。

初始化阶段:

  • onCreate():
    • 初始化 UI 组件(FPS 显示、结果画布)。
    • 根据设备平台(如 RK3588/RK356x)加载预置的 YOLO 模型文件到缓存目录。
    • 初始化推理引擎 mInferenceWrapper 和目标检测结果处理器 mInferenceResult。
  • createPreviewView():
    • 创建 SurfaceView 用于相机预览,绑定 SurfaceHolder 回调。

相机与预览控制:

见流程图:

TSurfaceHolderCallback
  • surfaceCreated(): 调用 startCamera() 打开相机并启动预览。
  • surfaceDestroyed(): 停止预览并释放相机资源。
startCamera()
  1. 根据摄像头数量选择摄像头 ID(优先选择 ID=2)。
  2. 配置相机参数(分辨率、预览格式),设置预览缓冲区 mPreviewData0
  3. 通过 setPreviewCallbackWithBuffer 注册预览数据回调。
onPreviewFrame()
  • 接收 NV21 格式的预览帧。
  • 使用 RGA 硬件加速转换为 RGB 格式。
  • 推送到图像队列 mImageBufferQueue
    @Overridepublic void onPreviewFrame(byte[] data, Camera camera) {mCamera0.addCallbackBuffer(data);ImageBufferQueue.ImageBuffer imageBuffer = mImageBufferQueue.getFreeBuffer();if (imageBuffer != null) {// RK_FORMAT_YCrCb_420_SP -> RK_FORMAT_RGBA_8888// flip for CAMERA_FACING_FRONTRGA.colorConvertAndFlip(data, RK_FORMAT_YCrCb_420_SP, imageBuffer.mImage_handle,  RK_FORMAT_RGB_888,CAMERA_PREVIEW_WIDTH, CAMERA_PREVIEW_HEIGHT, this.flip);mImageBufferQueue.postBuffer(imageBuffer);}}

推理线程

见下图:

startTrack()
  • 初始化图像队列,启动推理线程 mInferenceRunnable
推理循环
  1. 从队列获取 RGB 图像。
  2. 调用 mInferenceWrapper.run() 运行 YOLO 模型推理。
  3. 计算 FPS 并通过 Handler 更新 UI。
  4. 检测结果存储在 mInferenceResult 中。

UI 渲染

见下图:

showTrackSelectResults()

  • Canvas 上绘制检测框和类别标签。
  • 通过 ImageView 显示结果。

Handler 消息机制

  • 主线程更新 FPS 数值和检测结果位图。

3.java层相关类

3.1 YOLO目标检测模型的核心封装类InferenceWrapper

此类负责与底层C++实现的RKNN推理引擎交互,完成模型初始化、推理执行和后处理全流程。
成员变量

OutputBuffer mOutputs; // 存储模型原始输出
DetectResultGroup mDetectResults; // 原生后处理结果容器
int OBJ_NUMB_MAX_SIZE = 64; // 最大检测对象数量限制

DetectResultGroup两个类(数据结构)在InferenceResult类中,稍后介绍。
模型初始化

    public int initModel(int im_height, int im_width, int im_channel, String modelPath) throws Exception {mOutputs = new InferenceResult.OutputBuffer();// 为YOLO的三层输出预分配内存:mOutputs.mGrid0Out = new byte[255 * 80 * 80];  // 80x80特征图mOutputs.mGrid1Out = new byte[255 * 40 * 40];  // 40x40特征图 mOutputs.mGrid2Out = new byte[255 * 20 * 20];  // 20x20特征图if (navite_init(im_height, im_width, im_channel, modelPath) != 0) {throw new IOException("rknn init fail!");}return 0; }

255 = 3(5+80) 对应YOLOv5的3个anchor,每个anchor预测5个参数+80个类别。
推理执行

public OutputBuffer run(long img_buf_handle, int camera_width, int camera_height) {native_run(img_buf_handle, camera_width, camera_height, mOutputs.mGrid0Out, mOutputs.mGrid1Out, mOutputs.mGrid2Out);return mOutputs;
}// jni接口
private native int native_run(long img_buf_handle, int cam_width, int cam_height, byte[] grid0Out, byte[] grid1Out, byte[] grid2Out);

参数img_buf_handle是图像缓冲区的native句柄。
通过JNI将结果直接写入预分配的Java层缓冲区。
后处理流程

public ArrayList<Recognition> postProcess(OutputBuffer outputs) {// 1. 初始化结果容器mDetectResults = new DetectResultGroup();mDetectResults.ids = new int[OBJ_NUMB_MAX_SIZE];mDetectResults.scores = new float[OBJ_NUMB_MAX_SIZE]; mDetectResults.boxes = new float[4 * OBJ_NUMB_MAX_SIZE];// 2. 调用原生后处理int count = native_post_process(outputs.mGrid0Out, outputs.mGrid1Out, outputs.mGrid2Out,mDetectResults.ids, mDetectResults.scores, mDetectResults.boxes);// 3. 转换为Recognition对象ArrayList<Recognition> recognitions = new ArrayList<>();for (int i = 0; i < count; ++i) {RectF rect = new RectF(mDetectResults.boxes[i*4+0], // leftmDetectResults.boxes[i*4+1], // topmDetectResults.boxes[i*4+2], // rightmDetectResults.boxes[i*4+3]  // bottom);recognitions.add(new Recognition(mDetectResults.ids[i],mDetectResults.scores[i], rect));}return recognitions;
}

native方法

方法签名功能描述
navite_init()初始化RKNN模型,加载指定路径的模型文件
native_deinit()释放模型资源
native_run()执行推理,结果写入Java层缓冲区
native_post_process()执行NMS等后处理,返回检测结果

InferenceWrapper与Camera线程和RKNN JNI时序图

与InferenceResult的关系

  • 提供原始输出(OutputBuffer)给InferenceResult存储
  • 执行postProcess()生成最终识别结果
    与ObjectTracker的配合
  • 产生的Recognition列表会传递给跟踪器进行ID关联

3.2 InferenceResult类

用于处理目标检测推理结果的工具类,主要功能包括存储推理输出、处理检测结果以及跟踪检测对象。
主要成员变量

OutputBuffer mOutputBuffer; // 存储推理输出的原始数据
ArrayList<

相关文章:

  • 【深度学习核心技术解析】从理论到实践的全链路指南
  • x-cmd install | brows - 终端里的 GitHub Releases 浏览器,告别繁琐下载!
  • Stack和Queue和deque的讲解(底层实现 手撕版)
  • ospf综合作业
  • 企业办公即时通讯软件BeeWorks,私有化安全防泄密
  • Java Agent 注入 WebSocket 篇
  • 移动通信行业术语
  • 去掉从网页粘贴到Word的“↓“(向下的箭头)符号的方法
  • SAIL-RK3588协作机器人运动控制器技术方案
  • java—13 RocketMQ
  • 理解欧拉公式
  • VBA技术资料MF300:利用Mid进行文本查找
  • linux 中断子系统 层级中断编程
  • SEO的关键词研究与优化 第二章
  • Python3 基础:函数定义与调用
  • (八)深入了解AVFoundation-采集:拍照功能的实现
  • PyTorch生成式人工智能实战(2)——PyTorch基础
  • day002
  • SpringAI+DeepSeek大模型应用开发实战视频教程,传统Java项目AI化转型必学课程
  • nfs服务原理、搭建手册、安全配置建议及异常定位手段
  • 国家市场监管总局:民生无小事,严打民生领域侵权假冒违法行为
  • 巴基斯坦召开国家安全委员会紧急会议,应对印方连环举措
  • 人民日报:外卖平台应保障好骑手就业权益,消除后顾之忧
  • 920余名在缅甸当阳等地实施跨境电信网络诈骗的中国籍犯罪嫌疑人被移交我方
  • AI时代的阅读——当今时代呼唤文学的思想实验和人文认知
  • 特朗普:无意解雇鲍威尔,但美联储应该降低利率