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文件中,可以详细的研究

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/893828.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Learning Vue 读书笔记 Chapter 2

2. Vue 基本工作原理 2.1 Virtual DOM 概念&#xff1a; DOM: DOM以内存中树状数据结构的形式&#xff0c;代表了网页上的HTML&#xff08;或XML&#xff09;文档内容。它充当了一个编程接口&#xff0c;将网页与实际的编程代码&#xff08;如JavaScript&#xff09;连接起来…

Python标准库 - os (1) 环境变量、进程的用户和组

文章目录 1 访问和修改环境变量1.1 访问环境变量1.2 修改环境变量 2 进程的用户和组2.1 进程的ID2.2 进程的用户2.3 进程组 os模块提供了各种操作系统接口。包括环境变量、进程管理、进程调度、文件操作等方面。 这里整理了环境变量、进程的用户和用户组相关的控制方法。 参考…

Synology 群辉NAS安装(4)docker-compose

Synology 群辉NAS安装&#xff08;4&#xff09;docker-compose Synology 群辉NAS安装&#xff08;4&#xff09;docker-composeerror while loading shared libraries: libz.so.1 Synology 群辉NAS安装&#xff08;4&#xff09;docker-compose 1.下载最新版docker-compose |…

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

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

【C语言指针】数组指针和指针数组

一、数组指针 1.1 含义 数组指针本质是一个指针&#xff0c;它指向一个数组也就是说它指向数组在内存中的起始地址。数组指针可以用来处理多维数组&#xff0c;尤其是二维数组。 1.2 数组指针的一般形式 首先数组的一般形式是&#xff1a; int a[10] {1,2,3,4,5};这里a代…

关于av_get_channel_layout_nb_channels函数

问题&#xff1a;ffmpeg5.1 使用av_get_channel_layout_nb_channels函数时报错。 过程&#xff1a;经过检查&#xff0c;发现对应头文件内已经不包含该函数。遂查找资料&#xff0c;发现在ffmpeg5.1之后该函数被废弃&#xff0c;具体而言&#xff0c;新增了AVChannelLayout。 …

CrypTen——基于pytorch的隐私保护机器学习框架

目录 一、CrypTen概述 二、应用场景 三、CrypTen优势 四、CrypTen技术解析 1.基于pytorch的构建基础 2.核心密码学原语 3.加密模型训练流程 五、传统隐私保护技术与CrypTen的对比 1.传统隐私保护技术介绍 2.CrypTen与传统隐私保护技术的区别 六、CrypTen的环境配置…

ES6 简单练习笔记--变量申明

一、ES5 变量定义 1.在全局作用域中 this 其实就是window对象 <script>console.log(window this) </script>输出结果: true 2.在全局作用域中用var定义一个变量其实就相当于在window上定义了一个属性 例如: var name "孙悟空" 其实就相当于执行了 win…

Arduino大师练成手册 -- 控制 PN532 NFC 模块

要在 Arduino 上控制 PN532 NFC 模块&#xff0c;你可以按照以下步骤进行&#xff1a; 硬件连接 VCC&#xff1a;连接到 Arduino 的 3.3V 引脚。 GND&#xff1a;连接到 Arduino 的 GND 引脚。 SDA&#xff1a;连接到 Arduino 的 SDA 引脚&#xff08;通常是 A4&#xff09…

.NET Core跨域

CORS 跨域通讯的问题。解决方案&#xff1a;JSONP、前端代理后端请求、CORS等。CORS原理&#xff1a;在服务器的响应报文头中通过access-control-allow-origin告诉浏览器允许跨域访问的域名。在Program.cs的“var appbuilder.Build()”这句代码之前注册 string[] urls new[] …

python——Django 框架

Django 框架 1、简介 Django 是用python语言写的开源web开发框架&#xff0c;并遵循MVC设计。 Django的**主要目的是简便、快速的开发数据库驱动的网站。**它强调代码复用&#xff0c;多个组件可以很方便的以"插件"形式服务于整个框架&#xff0c;Django有许多功能…

大模型正确调用方式

1、ollama 安装 curl -fsSL https://ollama.com/install.sh | sh 如果是AutoDl服务器&#xff0c;可以开启学术加速。 source /etc/network_turbo 本次使用腾讯云Cloud Studio&#xff0c;所以已经安装好了 Ollama 2、启动 ollama run 模型的名字 ollama serve # 开启服务 olla…

CE-PBFT:大规模联盟区块链的高可用一致性算法

摘要 区块链已广泛应用于农产品溯源、供应链管理、物流运输等各个领域。作为联盟区块链不可缺少的组成部分&#xff0c;共识算法保证了网络中每个节点的一致性和可信度。然而&#xff0c;由于通信过程的复杂性&#xff0c;现有的大规模联盟区块链场景中的共识算法存在低系统吞…

2025年新开局!谁在引领汽车AI风潮?

汽车AI革命已来。 在2025年伊始开幕的CES展上&#xff0c;AI汽车、AI座舱无疑成为了今年汽车行业的最大热点。其中不少车企在2025年CES上展示了其新一代AI座舱&#xff0c;为下一代智能汽车的人机交互、场景创新率先打样。 其中&#xff0c;东软集团也携带AI驱动、大数据支撑…

通义灵码插件保姆级教学-IDEA(安装及使用)

一、JetBrains IDEA 中安装指南 官方下载指南&#xff1a;通义灵码安装教程-阿里云 步骤 1&#xff1a;准备工作 操作系统&#xff1a;Windows 7 及以上、macOS、Linux&#xff1b; 下载并安装兼容的 JetBrains IDEs 2020.3 及以上版本&#xff0c;通义灵码与以下 IDE 兼容&…

Kafka常见问题之 `javax.management.InstanceAlreadyExistsException`

文章目录 Kafka常见问题之 javax.management.InstanceAlreadyExistsException1. 概述2. 常见原因3. 具体异常示例4. 解决方案4.1 确保单一 Kafka Producer 实例4.2 配置 Kafka Broker 和 Producer 使用唯一的 JMX 名称&#xff08;对于Producer重点检查 client.id&#xff09;4…

跟我学C++中级篇——64位的处理

一、计算机的发展 计算机从二进制为基础开始描述整个世界&#xff0c;但正如现实世界一样&#xff0c;十进制为主的世界也会有万千百概念。所以在实际的应用中&#xff0c;会出现32位和64位的计算机系统。当然&#xff0c;前面还有过16位、8位和4位等&#xff0c;以后还可以会…

文献阅读 250125-Accurate predictions on small data with a tabular foundation model

Accurate predictions on small data with a tabular foundation model Accurate predictions on small data with a tabular foundation model | Nature 使用一种基于表格的模型来对小型数据实现准确预测 ## Abstract: 基于其他列来填充标签列中缺失值的基本预测任务对于各种应…

dup2 + fgets + printf 实现文件拷贝

思路 将源文件的内容读取到内存中&#xff0c;然后将这些内容写入到目标文件。 1: 打开源文件、目标文件 fopen() 以读模式打开源文件。 open ()以写模式打开目标文件。 2: 读取源文件、写入目标文件 fgets ()从源文件中读取内容。 printf ()将内容写入目标文件。 printf…

通过配置核查,CentOS操作系统当前无多余的、过期的账户;但CentOS操作系统存在共享账户r***t

通过配置核查,CentOS操作系统当前无多余的、过期的账户;但CentOS操作系统存在共享 核查CentOS操作系统中的用户账户&#xff0c;可以使用以下命令&#xff1a; 查看当前活跃用户&#xff1a; awk -F: /\$1\$/{print $1} /etc/shadow 查看多余账户&#xff08;非活跃账户&…