C版本的-Unet-rknn推理
1. 前言
之前就想着使用rknn的c版本的api做推理看看,找了一个简单的,那就unet吧,本来想着用rk的demo文件,但是里面是mobilenet,相关的函数没有,卡这也卡了好久,突然发现tengine相关的后处理,拿来用用,终于调试好了!!!(环境自己配置)
2. c代码修改
2.1前处理
const char* img_path = "/home/ubuntu/npu_test/unet/img/01_test.tif";const char* roi_mask_path = "/home/ubuntu/npu_test/unet/img/01_test_mask.png";const char *model_path = "/home/ubuntu/npu_test/unet/model/eyes_unet-sim-3588.rknn";// Load ROI maskMat roi_img = imread(roi_mask_path, IMREAD_GRAYSCALE);if (roi_img.empty()) {cout << "Image not found: " << roi_mask_path << endl;return -1;}// Load imageMat original_img = imread(img_path);if (original_img.empty()) {cout << "Image not found: " << img_path << endl;return -1;}// Convert image to RGBcvtColor(original_img, original_img, COLOR_BGR2RGB);// Expand batch dimension// Mat img = original_img.reshape(1, 1);Mat img = original_img;
2.2 rknn的模型加载
const int MODEL_IN_WIDTH = 565;const int MODEL_IN_HEIGHT = 584;const int MODEL_IN_CHANNELS = 3;rknn_context ctx = 0;int ret;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;}// ======================= 获取模型输入输出信息 ===================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;}// ======================= 设置模型输入 ===================// 使用rknn_input结构体存储模型输入信息, 表示模型的一个数据输入,用来作为参数传入给 rknn_inputs_set 函数rknn_input inputs[1];memset(inputs, 0, sizeof(inputs));inputs[0].index = 0; // 设置模型输入索引inputs[0].type = RKNN_TENSOR_UINT8; // 设置模型输入类型inputs[0].size = img.cols * img.rows * img.channels() * sizeof(uint8_t); // 设置模型输入大小inputs[0].fmt = RKNN_TENSOR_NHWC; // 设置模型输入格式:NHWCinputs[0].buf = img.data; // 设置模型输入数据// 使用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;}// ======================= 推理 ===================printf("rknn_run\n");ret = rknn_run(ctx, nullptr);if (ret < 0){printf("rknn_run fail! ret=%d\n", ret);return -1;}// ======================= 获取模型输出 ===================// 使用rknn_output结构体存储模型输出信息rknn_output outputs[1];memset(outputs, 0, sizeof(outputs));outputs[0].want_float = 1;// 使用rknn_outputs_get函数获取模型输出ret = rknn_outputs_get(ctx, 1, outputs, NULL);if (ret < 0){printf("rknn_outputs_get fail! ret=%d\n", ret);return -1;}
2.3 后处理
float *output_data = (float *)outputs[0].buf;int output_size = outputs[0].size / sizeof(uint32_t);// cout << "channel: " << channel << endl;// cout << "res: " << res << endl;// cout << "size: " << output_size << endl;int img_h = 584;int img_w = 565;int channel = output_size / img_h / img_w;int res = output_size % (img_h * img_w);cout << "channel: " << channel << endl;cout << "res: " << res << endl;int* label_data = new int[img_h * img_w];if (res != 0){fprintf(stderr, "output shape is not supported.\n");}else{/* multi-class segmentation */for (int i = 0; i < img_h; ++i){for (int j = 0; j < img_w; ++j){int argmax_id = -1;float max_conf = std::numeric_limits<float>::min();for (int k = 0; k < channel; ++k){float out_value = output_data[k * img_w * img_h + i * img_w + j];if (out_value > max_conf){argmax_id = k;max_conf = out_value;}}label_data[i * img_w + j] = argmax_id;if (label_data[i * img_w + j] == 1) {label_data[i * img_w + j] = 255;}}}}// 将图像数据存储到一维数组中int* roi_array = new int[img_h * img_w];for (int i = 0; i < img_h; ++i) {for (int j = 0; j < img_w; ++j) {roi_array[i * img_w + j] = static_cast<int>(roi_img.at<uchar>(i, j));}}for (int i = 0; i < img_h; ++i) {for (int j = 0; j < img_w; ++j) {if (roi_array[i * img_w + j] == 0) {label_data[i * img_w + j] = roi_array[i * img_w + j];}}}Mat result_img(img_h, img_w, CV_8UC1);for (int i = 0; i < img_h; ++i) {for (int j = 0; j < img_w; ++j) {result_img.at<uchar>(i, j) = static_cast<uchar>(label_data[i * img_w + j]);}}imwrite("result.png", result_img);
2.4 rknn资源释放
// Release resourcesrknn_outputs_release(ctx, 1, outputs);if (ret < 0){printf("rknn_outputs_release fail! ret=%d\n", ret);return -1;}else if (ctx > 0){// ======================= 释放RKNN模型 ===================rknn_destroy(ctx);}// ======================= 释放模型数据 ===================if (model){free(model);}
2.5 完整代码
#include <iostream>
#include <opencv2/core/hal/interface.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include "rknn_api.h"
#include <chrono>using namespace std;
using namespace cv;static unsigned char *load_model(const char *filename, int *model_size)
{FILE *fp = fopen(filename, "rb");if (fp == nullptr){printf("fopen %s fail!\n", filename);return NULL;}fseek(fp, 0, SEEK_END);int model_len = ftell(fp);unsigned char *model = (unsigned char *)malloc(model_len); // 申请模型大小的内存,返回指针fseek(fp, 0, SEEK_SET);if (model_len != fread(model, 1, model_len, fp)){printf("fread %s fail!\n", filename);free(model);return NULL;}*model_size = model_len;if (fp){fclose(fp);}return model;
}int main() {auto start = std::chrono::high_resolution_clock::now();const char* img_path = "/home/ubuntu/npu_test/unet/img/01_test.tif";const char* roi_mask_path = "/home/ubuntu/npu_test/unet/img/01_test_mask.png";const char *model_path = "/home/ubuntu/npu_test/unet/model/eyes_unet-sim-3588.rknn";// Load ROI maskMat roi_img = imread(roi_mask_path, IMREAD_GRAYSCALE);if (roi_img.empty()) {cout << "Image not found: " << roi_mask_path << endl;return -1;}// Load imageMat original_img = imread(img_path);if (original_img.empty()) {cout << "Image not found: " << img_path << endl;return -1;}// Convert image to RGBcvtColor(original_img, original_img, COLOR_BGR2RGB);// Expand batch dimension// Mat img = original_img.reshape(1, 1);Mat img = original_img;const int MODEL_IN_WIDTH = 565;const int MODEL_IN_HEIGHT = 584;const int MODEL_IN_CHANNELS = 3;rknn_context ctx = 0;int ret;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;}// ======================= 获取模型输入输出信息 ===================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;}// ======================= 设置模型输入 ===================// 使用rknn_input结构体存储模型输入信息, 表示模型的一个数据输入,用来作为参数传入给 rknn_inputs_set 函数rknn_input inputs[1];memset(inputs, 0, sizeof(inputs));inputs[0].index = 0; // 设置模型输入索引inputs[0].type = RKNN_TENSOR_UINT8; // 设置模型输入类型inputs[0].size = img.cols * img.rows * img.channels() * sizeof(uint8_t); // 设置模型输入大小inputs[0].fmt = RKNN_TENSOR_NHWC; // 设置模型输入格式:NHWCinputs[0].buf = img.data; // 设置模型输入数据// 使用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;}// ======================= 推理 ===================printf("rknn_run\n");ret = rknn_run(ctx, nullptr);if (ret < 0){printf("rknn_run fail! ret=%d\n", ret);return -1;}// ======================= 获取模型输出 ===================// 使用rknn_output结构体存储模型输出信息rknn_output outputs[1];memset(outputs, 0, sizeof(outputs));outputs[0].want_float = 1;// 使用rknn_outputs_get函数获取模型输出ret = rknn_outputs_get(ctx, 1, outputs, NULL);if (ret < 0){printf("rknn_outputs_get fail! ret=%d\n", ret);return -1;}float *output_data = (float *)outputs[0].buf;int output_size = outputs[0].size / sizeof(uint32_t);// cout << "channel: " << channel << endl;// cout << "res: " << res << endl;// cout << "size: " << output_size << endl;int img_h = 584;int img_w = 565;int channel = output_size / img_h / img_w;int res = output_size % (img_h * img_w);cout << "channel: " << channel << endl;cout << "res: " << res << endl;int* label_data = new int[img_h * img_w];if (res != 0){fprintf(stderr, "output shape is not supported.\n");}else{/* multi-class segmentation */for (int i = 0; i < img_h; ++i){for (int j = 0; j < img_w; ++j){int argmax_id = -1;float max_conf = std::numeric_limits<float>::min();for (int k = 0; k < channel; ++k){float out_value = output_data[k * img_w * img_h + i * img_w + j];if (out_value > max_conf){argmax_id = k;max_conf = out_value;}}label_data[i * img_w + j] = argmax_id;if (label_data[i * img_w + j] == 1) {label_data[i * img_w + j] = 255;}}}}// 将图像数据存储到一维数组中int* roi_array = new int[img_h * img_w];for (int i = 0; i < img_h; ++i) {for (int j = 0; j < img_w; ++j) {roi_array[i * img_w + j] = static_cast<int>(roi_img.at<uchar>(i, j));}}for (int i = 0; i < img_h; ++i) {for (int j = 0; j < img_w; ++j) {if (roi_array[i * img_w + j] == 0) {label_data[i * img_w + j] = roi_array[i * img_w + j];}}}Mat result_img(img_h, img_w, CV_8UC1);for (int i = 0; i < img_h; ++i) {for (int j = 0; j < img_w; ++j) {result_img.at<uchar>(i, j) = static_cast<uchar>(label_data[i * img_w + j]);}}imwrite("result.png", result_img);// Release resourcesrknn_outputs_release(ctx, 1, outputs);if (ret < 0){printf("rknn_outputs_release fail! ret=%d\n", ret);return -1;}else if (ctx > 0){// ======================= 释放RKNN模型 ===================rknn_destroy(ctx);}// ======================= 释放模型数据 ===================if (model){free(model);}auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);std::cout << "Execution time: " << duration.count() << " milliseconds" << std::endl;return 0;
}
感觉代码还是不优美,很多的for循环看着难受,但是已经实现了,后续再修改吧
3. 结果展示
![]() | ![]() |
| C++的测试结果 time: 497 ms | python的测试结果 time:660ms |
相关文章:
C版本的-Unet-rknn推理
1. 前言 之前就想着使用rknn的c版本的api做推理看看,找了一个简单的,那就unet吧,本来想着用rk的demo文件,但是里面是mobilenet,相关的函数没有,卡这也卡了好久,突然发现tengine相关的后处理&…...
Transformer的前世今生 day04(ELMO、Attention注意力机制)
ELMO 前情回顾 NNLM模型:主要任务是在预测下一个词,副产品是词向量Word2Vec模型:主要任务是生成词向量 CBOW:训练目标是根据上下文预测目标词Skip-gram:训练目标是根据目标词预测上下文词 ELMO模型的流程 针对Wor…...
稀碎从零算法笔记Day19-LeetCode:相交链表
题型:链表基本操作 链接:160. 相交链表 - 力扣(LeetCode) 来源:LeetCode 题目描述 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&…...
AI系统性学习03—ChatGPT开发教程
文章目录 1、OpenAI关键概念⭐️2、OpenAI SDK介绍3、OpenAI API KEY&API 认证3.1 REST API安全认证 4、OpenAI模型⭐️4.1 模型分类4.2 GPT44.3 GPT-3.54.4 Embeddings 5、OpenAI快速入门6、Function calling(函数调用)⭐️⭐️⭐️6.1 应用场景6.2 支持function calling的…...
每日一练 | 华为认证真题练习Day201
1、BGP Notification报文Error Code为2时表示open消息错误,其中包含如下哪些错误子码?(多选) A. 1-不支持的版本号 B. 2-错误的对等体AS号 C. 2-错误的对等体AS号 D. 4-错误的属性列表 2、A greate命令(aggregate ipy4-addre…...
nginx日志统计qps
1.QPS QPS全称为Queries Per Second,即每秒钟处理的请求数量。对于一个高并发应用来说,QPS是非常重要的性能指标,它反映了应用处理请求的能力。在实际应用中,QPS的大小取决于应用的负载和应用本身的性能。 QPS req/sec 请求数/…...
9.登入页面
登入页面 在pages中新建页面login 修改代码 <template><view></view> </template><script setup></script><style lang"scss"></style>添加头像组件 官网 https://vkuviewdoc.fsq.pub/components/avatar.html …...
js封装SDK 在VUE、小程序、公众号直接调用js调用后端接口(本文以vue项目为例)
1.封装一个js文件msgSdk.js 注意:需要修改这个请求地址 apiServiceAddress ;(function () {if (window.msgSdk) {return}var msgSdk (function () {var m_msgSdk thisvar apiServiceAddress"http://172.12.14.5:8000"this.I_SendHTTPRequest functi…...
ideaSSM社区二手交易平台C2C模式开发mysql数据库web结构java编程计算机网页源码maven项目
一、源码特点 idea ssm 社区二手交易平台系统是一套完善的完整信息管理系统,结合SSM框架完成本系统SpringMVC spring mybatis ,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码…...
利用子类化技术拦截win32窗口各种消息(包括但不限于鼠标键盘消息)
创建子类化函数: 首先,您需要编写一个子类化函数,该函数将用于处理编辑框的消息。这个函数通常会拦截并处理您感兴趣的消息,比如鼠标消息。 子类化编辑框: 在窗口程序中找到编辑框的句柄(HWND)…...
HCIP—OSPF课后练习一
本实验模拟了一个企业网络场景,R1、R2、R3为公司总部网络的路由器,R4、R5分别为企业分支机构1和分支机构2的路由器,并且都采用双上行方式与企业总部相连。整个网络都运行OSPF协议,R1、R2、R3之间的链路位于区域0,R4与R…...
Android 13.0 kenel和frameworks中修改ram运行内存的功能实现
1.前言 在13.0的系统rom产品开发定制中,在对一些产品开发中的配置需求方面,在产品后续订单中,产品提出要提高硬件配置,但是硬件方面已经定板,项目时间比较仓促,所以 来不及对硬件重新定制,就需要软件方面在ram运行内存的容量大小方面作假,修改ram真实的大小容量,所以…...
如何将应用程序发布到 App Store
憧憬blog主页 在强者的眼中,没有最好,只有更好。我们是移动开发领域的优质创作者,同时也是阿里云专家博主。 ✨ 关注我们的主页,探索iOS开发的无限可能! 🔥我们与您分享最新的技术洞察和实战经验࿰…...
Python进程与线程开发
目录 multiprocessing模块 线程的开发 threading模块 setDaemon 死锁 线程间的通信 multiprocessing模块 运行python的时候,我们都是在创建并运行一个进程,(linux中一个进程可以fork一个子进程,并让这个子进程exec另外一个程序)。在pyt…...
【3DsMax】UVW展开——以制作牙膏盒为例
效果 步骤 1. 从网上下载牙膏盒贴图,我下载的贴图地址为(牙膏盒贴图链接) 2. 打开3DsMax,创建一个长方体,设置长宽高分别为180、45、40毫米 打开材质编辑器,点击漫反射后的按钮 双击“位图” 将材质赋予长…...
Mysql数据库概念与安装
目录 一、数据库概述 1、数据库的基本概念 2、数据库管理系统(DBMS) 2.1 数据库管理系统概念 2.2 数据库管理系统工作模式 3、数据库系统(DBS) 3.1 数据库系统概念 3.2 数据库系统发展史 4、关系型数据库与非关系型数据库…...
【Java - 框架 - SpringMVC】(01) SpringMVC框架的简单创建与使用,快速上手
"SpringMVC"框架的简单创建与使用,快速上手; 环境 Java版本"1.8.0_202";Spring Boot版本"2.5.9";Windows 11 专业版_22621.2428;IntelliJ IDEA 2021.1.3(Ultimate Edition)࿱…...
框架篇常见面试题
1、Spring框架的单例bean是线程安全的吗? 2、什么是AOP? 3、Spring的事务是如何实现的? 4、Spring事务失效的场景 5、SpringBean的声明周期 6、Spring的循环依赖 7、SpringMVC的执行流程 8、SpringBoot自动配置原理 9、Spring常见注解 10、My…...
【刷题】滑动窗口入门
送给大家一句话: 那脑袋里的智慧,就像打火石里的火花一样,不去打它是不肯出来的。——莎士比亚 滑动窗口入门 认识滑动窗口Leetcode 209. 长度最小的子数组题目描述算法思路 Leetcode 3. 无重复字符的最长子串题目描述算法思路 Leetcode 1004…...
【Python 48小时速成 3】输入与输出
在 Python 中,输入和输出通常通过内置函数来实现。主要的输入函数是 input(),用于从用户获取输入,而输出函数则是 print(),用于将结果打印到控制台。以下是简单的代码示例演示了输入和输出: # 输入示例 name input(&…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

