RV1106 YOLOv5s部署:OpenCV优化实现20FPS边缘推理(无大量硬件加速)

序言

基于RV1106平台开展YOLOv5模型移植过程中,发现RKNN官方参考代码存在两大技术瓶颈:其一,算法实现深度依赖RK底层硬件加速模块,导致代码架构与硬件强耦合;其二,原始实现仅支持单帧图像推理模式,无法满足实际应用场景需求。尽管参考了幸狐LockFox团队的视频流推理方案,但其数据采集端仍固守mipi摄像头专用传输协议,在非标准硬件环境下缺乏可移植性。

针对上述技术痛点,本研究提出基于OpenCV通用框架的端到端视频流推理方案。通过将摄像头数据采集模块重构为OpenCV标准接口实现,成功解耦硬件依赖关系。在保证算法完整性的前提下,将预处理、后处理等环节全部替换为OpenCV标准函数库操作。经实验验证,在输入分辨率320×320条件下,系统达到20FPS的推理性能。性能分析显示,OpenCV的图像操作消耗的性能较大,成为当前系统主要瓶颈。通过将输入分辨率再次降低,推理帧率可再次提升。

YOLOV5目标检测

本章节基于 Lockzhiner Vision Module 和 YOLOv5 目标检测模型,实现实时目标检测功能。

1. 基本知识简介

1.1 目标检测简介

目标检测是计算机视觉领域中的一个关键任务,它不仅需要识别图像中存在哪些对象,还需要定位这些对象的位置。具体来说,目标检测算法会输出每个检测到的对象的边界框(Bounding Box)以及其所属类别的概率或置信度得分。

  • 应用场景:目标检测技术广泛应用于多个领域,包括但不限于安全监控、自动驾驶汽车、智能零售和医疗影像分析。

1.2 YOLOv5简介

YOLOv5 是 Ultralytics 在 2020 年基于 PyTorch 开发的一种高效目标检测模型,属于 YOLO 系列。它通过一次前向传播即可预测目标的类别和位置,适用于实时检测任务。YOLOv5 提供了多种模型大小(如 YOLOv5s、m、l、x),适应不同硬件条件。其结构包括骨干网络 CSPDarknet、特征融合层和检测头,支持多尺度预测和自定义训练,广泛用于各种检测场景。

2. API 文档

2.1 YOLOv5模型类

2.1.1 头文件
#include "yolov5.h"
2.1.2 模型初始化函数
int init_yolov5_model(const char* model_path, rknn_app_context_t* ctx);
  • 作用:加载YOLOv5 RKNN模型并初始化推理上下文
  • 参数
    • model_path:RKNN模型文件路径
    • ctx:模型上下文指针
  • 返回值:
    • 0:初始化成功
    • -1:初始化失败
2.1.3 模型推理函数
int inference_yolov5_model(rknn_app_context_t* ctx, 
                         object_detect_result_list* od_results);
  • 作用:执行模型推理并获取检测结果
  • 参数:
    • ctx:已初始化的模型上下文
    • od_results:检测结果存储结构体指针
  • 返回值:
    • 0:推理成功
    • -1 :推理失败
2.1.4 模型释放函数
void release_yolov5_model(rknn_app_context_t* ctx);
  • 作用:释放模型相关资源
  • 参数:
    • ctx:待释放的模型上下文
  • 返回值:无

2.2 图像处理函数

2.2.1 Letterbox处理
cv::Mat letterbox(cv::Mat& image);
  • 作用:保持图像比例进行缩放,添加灰边填充
  • 参数:
    -image:输入图像(RGB格式)
  • 返回值:
    • 返回预处理图像
2.2.2 坐标映射函数
void mapCoordinates(float& x, float& y);
  • 作用:将模型输出坐标映射回原始图像坐标系
  • 参数:
    • x/y:模型输出坐标(输入输出参数)
  • 返回值:无

2.3 结果处理函数

2.3.1 后处理初始化
void init_post_process();
  • 作用:加载类别标签文件
  • 参数:无
  • 返回值:无
2.3.2 结果绘制函数
void draw_detections(int count, 
                    object_detect_result* results,
                    cv::Mat& frame,
                    void (*mapFunc)(float&, float&));
  • 作用:在图像上绘制检测框和标签
  • 参数:
    • count:检测结果数量
    • results:检测结果数组
    • frame:目标图像帧
    • mapFunc:坐标映射函数指针
  • 返回值:无

3. 代码解析

3.1 流程图

main函数
├─ 参数检查与提示
│  └─ 检查参数数量是否为4,否则打印用法
├─ 初始化YOLOv5模型
│  ├─ 创建rknn_app_context结构体
│  ├─ 调用init_yolov5_model()加载RKNN模型
│  └─ 错误处理:模型加载失败时退出
├─ 加载标签文件
│  └─ 调用init_post_process()
├─ 初始化视频输入
│  ├─ 创建Edit对象并建立连接
│  ├─ 设置摄像头参数(640x480)
│  └─ 打开摄像头设备
├─ 主处理循环
│  ├─ 帧计时开始
│  ├─ 读取视频帧
│  │  └─ 空帧检查
│  ├─ 图像预处理
│  │  ├─ 调整尺寸至320x320
│  │  └─ 执行letterbox处理
│  ├─ 模型推理
│  │  ├─ 将数据复制到模型输入内存
│  │  ├─ 调用inference_yolov5_model()执行推理
│  │  └─ 获取检测结果列表
│  ├─ 结果可视化
│  │  ├─ 调用draw_detections()绘制检测框
│  │  └─ 使用mapCoordinates坐标映射
│  ├─ 显示输出
│  │  └─ 调用edit.Print()显示处理后的帧
│  ├─ 性能计算
│  │  ├─ 记录结束时间
│  │  └─ 计算并打印帧处理时间
│  └─ 循环继续条件
└─ 资源释放
   ├─ 调用release_yolov5_model()释放模型
   ├─ 调用deinit_post_process()释放后处理
   └─ 释放摄像头资源

3.2核心代码解析

  • 模型初始化
rknn_app_context_t rknn_app_ctx;
init_yolov5_model("yolov5s.rknn", &rknn_app_ctx);
  • 图像预处理
cv::Mat letterboxImage = letterbox(frame); // 保持比例缩放
memcpy(rknn_app_ctx.input_mems[0]->virt_addr, 
       letterboxImage.data, 
       model_width * model_height * 3);
  • 模型推理
object_detect_result_list od_results;
inference_yolov5_model(&rknn_app_ctx, &od_results);
  • 结果可视化
draw_detections(od_results.count, 
               od_results.results,
               frame,
               mapCoordinates);

3.3 完整代码实现

👉 点击获取完整源码

4. 编译过程

4.1 编译环境搭建

4.2 Cmake介绍

# CMake最低版本要求  
cmake_minimum_required(VERSION 3.10)  

project(test-find-blobs)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 定义项目根目录路径
set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../..")
message("PROJECT_ROOT_PATH = " ${PROJECT_ROOT_PATH})

include("${PROJECT_ROOT_PATH}/toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake")

# 定义 OpenCV SDK 路径
set(OpenCV_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/opencv-mobile-4.10.0-lockzhiner-vision-module")
set(OpenCV_DIR "${OpenCV_ROOT_PATH}/lib/cmake/opencv4")
find_package(OpenCV REQUIRED)
set(OPENCV_LIBRARIES "${OpenCV_LIBS}")
# 定义 LockzhinerVisionModule SDK 路径
set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk")
set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module")
find_package(LockzhinerVisionModule REQUIRED)

set(RKNPU2_BACKEND_BASE_DIR "${LockzhinerVisionModule_ROOT_PATH}/include/lockzhiner_vision_module/vision/deep_learning/runtime")
if(NOT EXISTS ${RKNPU2_BACKEND_BASE_DIR})
    message(FATAL_ERROR "RKNPU2 backend base dir missing: ${RKNPU2_BACKEND_BASE_DIR}")
endif()

add_executable(yolov5_main
    main.cc
    postprocess.cc
    yolov5.cc
    yolov5.h  
    postprocess.h
)
target_include_directories(yolov5_main PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS} ${rknpu2_INCLUDE_DIRS} ${RKNPU2_BACKEND_BASE_DIR})
target_link_libraries(yolov5_main PRIVATE ${OPENCV_LIBRARIES} ${LOCKZHINER_VISION_MODULE_LIBRARIES})

install(
    TARGETS yolov5_main
    RUNTIME DESTINATION .  
)

4.3 编译项目

使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目

# 进入Demo所在目录
cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/Cpp_example/D10_yolov5
# 创建编译目录
rm -rf build && mkdir build && cd build
# 配置交叉编译工具链
export TOOLCHAIN_ROOT_PATH="/LockzhinerVisionModuleWorkSpace/arm-rockchip830-linux-uclibcgnueabihf"
# 使用cmake配置项目
cmake ..
# 执行编译项目
make -j8 && make install

在执行完上述命令后,会在build目录下生成可执行文件。

5. 例程运行示例

5.1 运行

chmod 777 yolov5_main
# 在实际应用的过程中LZ-Picodet需要替换为下载的或者你的rknn模型
./yolov5_main ./voc320.rknn 20 label

5.2 结果展示

  • 可以看到我们可以正确识别多种类别的

在这里插入图片描述

🚀 开发者生态

🔧 问题反馈

遇到技术问题?请到凌智视觉模块官方仓库**凌智视觉模块** 提交Issue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值