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

RKNN_C++版本-YOLOV5

1.背景

        为了实现低延时,所以开始看看C版本的rknn的使用,确实有不足的地方,请指正(代码借鉴了rk官方的仓库文件)。

2.基本的操作流程

1.读取模型初始化

    // ======================= 设置基本信息 ===================// 在postprocess.h文件中定义,详见include/postprocess.h文件const float nms_threshold = NMS_THRESH;      // 默认的NMS阈值const float box_conf_threshold = BOX_THRESH; // 默认的置信度阈值// 默认的模型输入输出信息letterbox,默认使用LetterBox的预处理std::string option = "letterbox";// 默认的图片输出路径,根据路径设置std::string out_path = "/home/ubuntu/unet/unet_rknn_c++/rknn_api_test/result/out.png";// 默认的模型路径,根据路径设置const char model_path[] = "../weights/yolov5s-640-640.rknn";// ======================= 设置rknn模型的基本信息 ===================//初始化rknn_context对象,数据类型:rknn_context,成员变量:ctxrknn_context ctx = 0;int ret;// RKNN模型的二进制数据或者RKNN模型路径。当参数size大于0时,model表示二进制数据;当参数size等于0时,model表示RKNN模型路径。int model_len = 0;unsigned char *model;// ======================= 初始化RKNN模型 ===================model = load_model(model_path, &model_len);ret = rknn_init(&ctx, model, model_len, 0, NULL);if (ret < 0){printf("rknn_init fail! ret=%d\n", ret);return -1;}else{printf("model load success\n");}if (ctx == 0){printf("rknn_init fail! ret=%d\n", ret);return -1;}rknn_core_mask core_mask = RKNN_NPU_CORE_0_1_2;ret = rknn_set_core_mask(ctx, core_mask);

 2.获取输入和输出的相关信息

// ======================= SDK的版本信息 ===================rknn_sdk_version version;ret = rknn_query(ctx, RKNN_QUERY_SDK_VERSION, &version, sizeof(rknn_sdk_version));if (ret < 0){printf("rknn_init error ret=%d\n", ret);return -1;}printf("sdk version: %s driver version: %s\n", version.api_version, version.drv_version);// ======================= 获取模型输入输出信息 ===================/*调佣rknn_query接口查询tensor输入输出个数*/rknn_input_output_num io_num;ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));if (ret != RKNN_SUCC){printf("rknn_query fail! ret=%d\n", ret);return -1;}printf("model input num:%d,output num:%d\n",io_num.n_input,io_num.n_output);// =======================结构体rknn_tensor_attr表示模型的tensor的属性 ===================// (1)input的tensor信息rknn_tensor_attr input_attrs[io_num.n_input];memset(input_attrs, 0, sizeof(input_attrs));for (int i = 0; i < io_num.n_input; i++){input_attrs[i].index = i;ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(input_attrs[i]), sizeof(rknn_tensor_attr));if (ret < 0){printf("rknn_init error ret=%d\n", ret);return -1;}dump_tensor_attr(&(input_attrs[i]));}//(2)output的tensor信息rknn_tensor_attr output_attrs[io_num.n_output];memset(output_attrs, 0, sizeof(output_attrs));for (int i = 0; i < io_num.n_output; i++){output_attrs[i].index = i;ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr));dump_tensor_attr(&(output_attrs[i]));}

3.设置输入格式

// 查看模型的输入格式NCHW或者NHWC,获取输入的宽高和通道数int channel = 3;int width = 0;int height = 0;if (input_attrs[0].fmt == RKNN_TENSOR_NCHW){printf("model is NCHW input fmt\n");channel = input_attrs[0].dims[1];height = input_attrs[0].dims[2];width = input_attrs[0].dims[3];}else{printf("model is NHWC input fmt\n");height = input_attrs[0].dims[1];width = input_attrs[0].dims[2];channel = input_attrs[0].dims[3];}printf("model input height=%d, width=%d, channel=%d\n", height, width, channel);// ======================= 设置模型输入 ===================// rknn_input 结构体,用于描述输入数据,包括索引、类型、大小、格式等。1表示输入的数量,可换成io_num.n_inputrknn_input inputs[1];memset(inputs, 0, sizeof(inputs));// 该输入的索引位置inputs[0].index = 0;// 输入数据的类型inputs[0].type = RKNN_TENSOR_UINT8;// 输入数据所占内存大小inputs[0].size = width * height * channel;// 输入数据的格式inputs[0].fmt = RKNN_TENSOR_NHWC;// 输入数据是否透传inputs[0].pass_through = 0;

4.读取图片进行预处理

    string input_path= "../images/bus.jpg";// ======================= 读取图片 ===================printf("Read %s ...\n", input_path.c_str());cv::Mat orig_img = cv::imread(input_path, 1);if (!orig_img.data){printf("cv::imread %s fail!\n", input_path.c_str());return -1;}cv::Mat img;cv::cvtColor(orig_img, img, cv::COLOR_BGR2RGB);int img_width = img.cols;int img_height = img.rows;printf("img width = %d, img height = %d\n", img_width, img_height);// 这里去除了rga的操作,// 指定目标大小和预处理方式,默认使用LetterBox的预处理BOX_RECT pads;memset(&pads, 0, sizeof(BOX_RECT));cv::Size target_size(width, height);cv::Mat resized_img(target_size.height, target_size.width, CV_8UC3);// 计算缩放比例float scale_w = (float)target_size.width / img.cols;float scale_h = (float)target_size.height / img.rows;if (img_width != width || img_height != height) {if (option == "letterbox") {printf("resize image with letterbox\n");float min_scale = std::min(scale_w, scale_h);scale_w = min_scale;scale_h = min_scale;letterbox(img, resized_img, pads, min_scale, target_size);// 保存预处理图片cv::imwrite("letterbox_input.jpg", resized_img);} else {fprintf(stderr, "Invalid resize option. Use 'resize' or 'letterbox'.\n");return -1;}inputs[0].buf = resized_img.data;}else{inputs[0].buf = img.data;}

5.模型输入和推理

    // 使用rknn_inputs_set函数设置模型输入ret = rknn_inputs_set(ctx, io_num.n_input, inputs);if (ret < 0){printf("rknn_input_set fail! ret=%d\n", ret);return -1;}// ======================= rknn模型推理 ===================printf("rknn_run\n");ret = rknn_run(ctx, nullptr);if (ret < 0){printf("rknn_run fail! ret=%d\n", ret);return -1;}

6.获取输出

    // 多输出rknn_output outputs[io_num.n_output];memset(outputs, 0, sizeof(outputs));// 为每个输出设置属性,这里假设我们希望所有输出都转换为浮点数for (int i = 0; i < 3; ++i) {// want_float标识是否需要将输出数据转为float类型输出,0表示不需要,1表示需要outputs[i].want_float = 0;}// 使用rknn_outputs_get函数获取模型输出ret = rknn_outputs_get(ctx, 3, outputs, NULL);if (ret < 0) {printf("rknn_outputs_get fail! ret=%d\n", ret);return -1;}/***int8数据格式(int占用1字节),查看模型输出的shape: (1*255*80*80),(1*255*40*40),(1*255*40*40)output[0] shape: 1632000output[1] shape: 408000output[2] shape: 102000float数据格式(float占用4字节),查看模型输出的shape: (1*255*80*80),(1*255*40*40),(1*255*40*40)output[0] shape: 1632000*4output[1] shape: 408000*4output[2] shape: 102000*4***/
//    int8_t *pblob[3];
//    for (int i = 0; i < io_num.n_output; ++i)
//    {
//        cout << "output[" << i << "] shape: " << outputs[i].size << endl;
//        pblob[i] = (int8_t*)outputs[i].buf;
//    }

7.后处理

    // 后处理detect_result_group_t detect_result_group;std::vector<float> out_scales;std::vector<int32_t> out_zps;// rknn量化的零点和缩放因子for (int i = 0; i < io_num.n_output; ++i){out_scales.push_back(output_attrs[i].scale);out_zps.push_back(output_attrs[i].zp);}// 后处理post_process((int8_t *)outputs[0].buf, (int8_t *)outputs[1].buf, (int8_t *)outputs[2].buf, height, width,box_conf_threshold, nms_threshold, pads, scale_w, scale_h, out_zps, out_scales, &detect_result_group);// 画框和概率char text[256];for (int i = 0; i < detect_result_group.count; i++){detect_result_t *det_result = &(detect_result_group.results[i]);sprintf(text, "%s %.1f%%", det_result->name, det_result->prop * 100);printf("%s @ (%d %d %d %d) %f\n", det_result->name, det_result->box.left, det_result->box.top,det_result->box.right, det_result->box.bottom, det_result->prop);int x1 = det_result->box.left;int y1 = det_result->box.top;int x2 = det_result->box.right;int y2 = det_result->box.bottom;rectangle(orig_img, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(256, 0, 0, 256), 3);putText(orig_img, text, cv::Point(x1, y1 + 12), cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(255, 255, 255));}imwrite(out_path, orig_img);printf("save detect result to %s\n", out_path.c_str());

8.资源释放

    // 释放rknn_outputs_get函数得到的输出的相关资源ret = rknn_outputs_release(ctx, io_num.n_output, outputs);// 释放传入的rknn_context及其相关资源ret = rknn_destroy(ctx);if (model){free(model);}

3.后记

详细的内容我已经上传到yolov5-rk文件中,可以详细的研究

相关文章:

RKNN_C++版本-YOLOV5

1.背景 为了实现低延时&#xff0c;所以开始看看C版本的rknn的使用&#xff0c;确实有不足的地方&#xff0c;请指正&#xff08;代码借鉴了rk官方的仓库文件&#xff09;。 2.基本的操作流程 1.读取模型初始化 // 设置基本信息 // 在postprocess.h文件中定义&#xff0c;详见…...

k8s优雅重启

理论上处于terminating状态的pod&#xff0c;k8s 就会把它从service中移除了&#xff0c;只用配置一个优雅停机时长就行了。kubectl get endpoints 验证 因此&#xff0c;优雅重新的核心问题&#xff0c;是怎么让空闲长连接关闭&#xff0c;再等待处理中的请求执行完。 一些底…...

三高“高性能、高并发、高可靠”系统架构设计系列文章

目录 高并发系统的艺术&#xff1a;如何在流量洪峰中游刃有余 《数据密集型应用系统设计》读后感与高并发高性能实践案例 系统稳定性与高可用保障的几种思路 软件系统限流的底层原理解析 技术解决方案调研 延迟队列调研 重试调研 异步回调调研 分库分表调研 分布式事…...

opengrok_使用技巧

Searchhttps://xrefandroid.com/android-15.0.0_r1/https://xrefandroid.com/android-15.0.0_r1/ 选择搜索的目录&#xff08;工程&#xff09; 手动在下拉框中选择&#xff0c;或者 使用下面三个快捷按钮进行选择或者取消选择。 输入搜索的条件 搜索域说明 域 fullSearc…...

C++资料

InterviewGuide 首页 - 八股精 Releases halfrost/LeetCode-Go GitHub GitHub - GrindGold/CppGuide: 「C/C学习面试指南」一份涵盖大部分 C 程序员所需要掌握的知识。入门、进阶、深入、校招、社招&#xff0c;准备 C 学习& 面试&#xff0c;首选 CppGuide&#xff0…...

基于模糊PID的孵化箱温度控制系统(论文+源码)

1系统方案设计 本课题为基于模糊PID的孵化箱温度控制系统&#xff0c;其以STM32最小系统与模糊PID控制器为控制核心。系统主要包括数据采集模块、处理器模块、电机控制模块。 数据采集模块由温度传感器构成&#xff0c;通过温度传感器感应温度变化&#xff0c;获得待处理的数据…...

景联文科技加入AIIA联盟数据标注分委会

2025年1月16日&#xff0c;中国人工智能产业发展联盟&#xff08;简称AIIA&#xff09;数据委员会数据标注分委会&#xff08;以下简称“分委会”&#xff09;正式成立。景联文科技成为第一批AIIA联盟数据标注分委会委员单位。 数据标注分委会的成立旨在搭建数据标注领域产学研…...

1-1 飞机大战项目框架搭建

前言&#xff1a; 基于本人巩固C语言编写&#xff0c;仅供学习参考 1.0 框架搭建 搭建完成后状态 C语言飞机大战框架 使用loadimage时出现波浪线的错误如何解决&#xff0c;这个问题主要是编码格式不对造成的&#xff0c;我们需要修改系统的编码格式&#xff0c;将unicode编码格…...

【C++高并发服务器WebServer】-7:共享内存

本文目录 一、共享内存1.1 shmget函数1.2 shmat1.3 shmdt1.4 shmctl1.5 ftok1.6 共享内存和内存映射的关联1.7 小demo 二、共享内存操作命令 一、共享内存 共享内存允许两个或者多个进程共享物理内存的同一块区域&#xff08;通常被称为段&#xff09;。由于一个共享内存段会称…...

RabbitMQ 多种安装模式

文章目录 前言一、Windows 安装 RabbitMq1、版本关系2、Erlang2.1、下载安装 Erlang 23.12.2、配置 Erlang 环境变量 3、RabbitMQ3.1、下载安装 RabbitMQ 3.8.93.2、环境变量3.3、启动RabbitMQ 管理插件3.3、RabbitMQ3.4、注意事项 二、安装docker1、更新系统包&#xff1a;2、…...

C++ 包装器与绑定器的应用之回调函数的实现

回调函数的实现 在消息队列和网络库的框架中&#xff0c;当接收到消息&#xff08;报文&#xff09;时&#xff0c;回调用户自定义的函数对象&#xff0c;把消息&#xff08;报文&#xff09;参数传给它&#xff0c;由它决定如何处理。 queue参考文章:C queue(STL queue&…...

Baichuan大模型Base、Chat、Instruct等版本的区别

Baichuan大模型Base与Instruct等版本的区别解析 Baichuan大模型作为国内领先的开源语言模型&#xff0c;其不同版本&#xff08;如Base、Chat、Instruct等&#xff09;在训练目标、应用场景和性能特点上存在显著差异。以下是基于公开技术文档和行业分析的详细对比&#xff1a;…...

3.DrawCall的概念

DrawCall是渲染管线中的一个重要概念&#xff0c;指的是CPU向GPU发送的一个绘制命令&#xff0c;告诉GPU&#xff1a;“请根据我提供的数据&#xff0c;画一个物体&#xff08;或一部分物体&#xff09;。” 通俗易懂讲解&#xff1a;DrawCall就像给画师下订单 想象你是一个老…...

ubuntu电脑调用摄像头拍摄照片

一、 1、先装环境 conda create -n text python3.8 -y conda activate text 2、 pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 1、连接摄像头拍摄收集数据集 capture_image5.py import cv2 as cv import os import datetime import n…...

PyQt4 的图片切割编辑器

一、 编辑器功能明确 允许用户加载图片、选择切割模式、对切割后的图片片段进行操作&#xff08;如移动、复制、粘贴、删除等&#xff09;&#xff0c;并支持撤销和重做操作。 环境&#xff1a;Py2.7 PyQt 4.11 二、导入模块介绍 sys: 用于访问与 Python 解释器强相关的变…...

mac 电脑上安装adb命令

在Mac下配置android adb命令环境&#xff0c;配置方式如下&#xff1a; 1、下载并安装IDE &#xff08;android studio&#xff09; Android Studio官网下载链接 详细的安装连接请参考 Mac 安装Android studio 2、配置环境 在安装完成之后&#xff0c;将android的adb工具所在…...

Webrtc (1) - Windows 编译

最近项目上遇到webrtc wgc 的几个test case无法通过&#xff0c;与webrtc人员沟通后决定要自行修复一下(因为他们不想管…) 参考文档 https://webrtc.org/support/contributinghttps://chromium.googlesource.com/chromium/src//main/docs/#checking-out-and-building 以上两…...

学习数据结构(1)算法复杂度

1.数据结构和算法 &#xff08;1&#xff09;数据结构是计算机存储、组织数据的方式&#xff0c;指相互之间存在⼀种或多种特定关系的数据元素的集合 &#xff08;2&#xff09;算法就是定义良好的计算过程&#xff0c;取一个或一组的值为输入&#xff0c;并产生出一个或一组…...

GCC之编译(8)AR打包命令

GCC之(8)AR二进制打包命令 Author: Once Day Date: 2025年1月23日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章请查看专栏: Linux实践记录_Once-Day的博客-C…...

RocketMQ原理—4.消息读写的性能优化

大纲 1.Producer基于队列的消息分发机制 2.Producer基于Hash的有序消息分发 3.Broker如何实现高并发消息数据写入 4.RocketMQ读写队列的运作原理分析 5.Consumer拉取消息的流程原理分析 6.ConsumeQueue的随机位置读取需求分析 7.ConsumeQueue的物理存储结构设计 8.Cons…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...