rk1126, 实现 yolov8 目标检测

在这里插入图片描述

基于 RKNN 1126 实现 yolov8 目标检测


Ⓜ️ RKNN 模型转换

  1. ONNX

    yolo export model=./weights/yolov8s.pt format=onnx
    
  2. 导出 RKNN

    这里选择输出 concat 输入两个节点 onnx::Concat_425onnx::Concat_426

在这里插入图片描述

from rknn.api import RKNNONNX_MODEL = './weights/yolov8s.onnx'RKNN_MODEL = './weights/yolov8s.rknn'QUA_DATASETS = './data/coco/datasets.txt'QUA_DATASETS_analysis = './data/coco/images/datasets_ans.txt'QUANTIZE_ON = Trueif __name__ == '__main__':# Create RKNN objectrknn = RKNN(verbose=True)# pre-process config  # asymmetric_affine-u8, dynamic_fixed_point-i8, dynamic_fixed_point-i16print('--> config model')rknn.config(reorder_channel='0 1 2',mean_values=[[0, 0, 0]],std_values=[[255, 255, 255]],quantized_algorithm="normal",optimization_level=3,target_platform = 'rk1126',quantize_input_node= QUANTIZE_ON,quantized_dtype='asymmetric_quantized-u8',batch_size = 64,force_builtin_perm = False)print('done')print('--> Loading model')ret = rknn.load_onnx(model=ONNX_MODEL, outputs=['onnx::Concat_425', 'onnx::Concat_426'])if ret != 0:print('Load model  failed!')exit(ret)print('done')# Build modelprint('--> Building model')ret = rknn.build(do_quantization=QUANTIZE_ON, dataset=QUA_DATASETS,pre_compile=True)  # ,pre_compile=Trueif ret != 0:print('Build occ_model failed!')exit(ret)print('done')# Export rknn modelprint('--> Export RKNN model')ret = rknn.export_rknn(RKNN_MODEL)if ret != 0:print('Export occ_model failed!')exit(ret)print('done')

🚀​ RKNN板子上推理

  1. 前处理,为了简单方便直接 resize

    cv::Mat resize_img(INPUT_H, INPUT_W, CV_8UC3);
    cv::resize(src, resize_img, resize_img.size(), 0, 0, cv::INTER_LINEAR);
    cv::Mat pr_img;
    cvtColor(resize_img, pr_img, COLOR_BGR2RGB);
    
  2. 模型推理

    /* Init input tensor */
    rknn_input inputs[1];
    memset(inputs, 0, sizeof(inputs));
    inputs[0].index = 0;
    inputs[0].buf = pr_img.data;
    // inputs[0].buf = input_data;
    inputs[0].type = RKNN_TENSOR_UINT8;
    inputs[0].size = input_width * input_height * input_channel;
    inputs[0].fmt = RKNN_TENSOR_NHWC;
    inputs[0].pass_through = 0;// printf("img.cols: %d, img.rows: %d\n", pr_img.cols, pr_img.rows);
    printf("input io_num: %d, output io_num: %d\n", io_num.n_input, io_num.n_output);
    auto t1 = std::chrono::steady_clock::now();
    rknn_inputs_set(ctx, io_num.n_input, inputs);
    std::cout << "rknn_inputs_set time: " << std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - t1).count() * 1000 << " ms." << std::endl;
    ret = rknn_run(ctx, NULL);
    std::cout << "rknn_run time: " << std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - t1).count() * 1000 << " ms." << std::endl;
    if (ret < 0)
    {printf("ctx error ret=%d\n", ret);return -1;
    }/* Init output tensor */
    rknn_output outputs[io_num.n_output];
    memset(outputs, 0, sizeof(outputs));
    for (int i = 0; i < io_num.n_output; i++)
    {outputs[i].want_float = 1;
    }
    ret = rknn_outputs_get(ctx, io_num.n_output, outputs, NULL);
    if (ret < 0)
    {printf("outputs error ret=%d\n", ret);return -1;
    }
    
  3. 后处理

    1. 导出模型没有进行 concat 操作,所以自行处理.
    cv::Mat out_buffer0_mat;
    std::vector<Mat> vImgs;
    cv::Mat out0_mat = cv::Mat(4, Num_box, CV_32F, (float*)outputs[0].buf);
    cv::Mat out1_mat = cv::Mat(CLASSES, Num_box, CV_32F, (float*)outputs[1].buf);
    vImgs.push_back(out0_mat);       // 4 * 8400
    vImgs.push_back(out1_mat);       // CLASSES * 8400
    vconcat(vImgs, out_buffer0_mat); // 垂直方向拼接  (CLASSES + 4) * 8400
    
    1. 后处理
    std::vector<Detection> detections; // 结果id数组std::vector<int> classIds;      // 结果id数组
    std::vector<float> confidences; // 结果每个id对应置信度数组
    std::vector<cv::Rect> boxes;    // 每个id矩形框
    auto start = std::chrono::system_clock::now();
    for (int i = 0; i < Num_box; i++)
    {// 输出是1*net_length*Num_box;所以每个box的属性是每隔Num_box取一个值,共net_length个值cv::Mat scores = out_buffer0_mat(Rect(i, 4, 1, CLASSES)).clone();Point classIdPoint;Point minclassIdPoint;double max_class_socre;double min_class_socre;minMaxLoc(scores, &min_class_socre, &max_class_socre, &minclassIdPoint, &classIdPoint);// if (max_class_socre > CONF_THRESHOLD)//     std::cout << "max_class_socre:" << max_class_socre << std::endl;max_class_socre = (float)max_class_socre;if (max_class_socre >= CONF_THRESHOLD){float x = (out_buffer0_mat.at<float>(0, i)) * ratio_w; // cxfloat y = (out_buffer0_mat.at<float>(1, i)) * ratio_h; // cyfloat w = out_buffer0_mat.at<float>(2, i) * ratio_w;   // wfloat h = out_buffer0_mat.at<float>(3, i) * ratio_h;   // hint left = MAX((x - 0.5 * w), 0);int top = MAX((y - 0.5 * h), 0);int width = (int)w;int height = (int)h;if (width <= 0 || height <= 0)continue;printf("====> id: %d \n", classIdPoint.y);classIds.push_back(classIdPoint.y);confidences.push_back(max_class_socre);boxes.push_back(Rect(left, top, width, height));}
    }// 执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a9897fddb01642358b2a9047ccd98067.jpeg#pic_center)std::vector<int> nms_result;
    cv::dnn::NMSBoxes(boxes, confidences, CONF_THRESHOLD, NMS_THRESHOLD, nms_result);std::cout << ">>>>> nms_result: " << boxes.size() << " " << nms_result.size() << std::endl;for (int i = 0; i < nms_result.size(); ++i)
    {Detection detection;int idx = nms_result[i];detection.class_id = classIds[idx];detection.conf = confidences[idx];detection.box = boxes[idx];detections.push_back(detection);
    }
    

在这里插入图片描述

在这里插入图片描述


🇶🇦 关于遇到的问题 ?

  • 当我指定 onnx 最后一层时 (output0),导出的 rknn模型推理没有结果。个人感觉是 rknn 量化时, concat操作有问题. 所以我改成输出上两个节点,自行拼接. 如果有明白的大佬,望指定一二, 抱拳了 .

在这里插入图片描述

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

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

相关文章

MySQL 索引(下)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL-进阶篇 &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现…

推荐新版AI智能聊天系统网站源码ChatGPT NineAi

Nine AI.ChatGPT是基于ChatGPT开发的一个人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过学习和理解人类的语言来进行对话&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写邮件、视频脚本、文案、翻译、代…

GoZero微服务个人探究之路(七)添加中间件、自定义中间件

说在前面 官方已经自己实现了很多中间件&#xff0c;我们可以方便的直接使用&#xff0c;不用重复造轮子了 开启方式可以看官方文档 中间件 | go-zero Documentation 实现自定义的中间件 在业务逻辑中&#xff0c;我们需要实现自定义功能的中间件 ------这里我们以实现跨源…

Spring+SprinMVC+MyBatis配置方式简易模板

SpringSprinMVCMyBatis配置方式简易模板代码Demo GitHub访问 ssm-tpl-cfg 一、SQL数据准备 创建数据库test&#xff0c;执行下方SQL创建表ssm-tpl-cfg /*Navicat Premium Data TransferSource Server : 127.0.0.1Source Server Type : MySQLSource Server Versio…

Linux ---- 小玩具

目录 一、安装&#xff1a; 1、佛祖保佑&#xff0c;永不宕机&#xff0c;永无bug 2、小火车 3、艺术字和其它 天气预报 艺术字 4、会说话的小牦牛 5、其他趣味图片 我爱你 腻害 英雄联盟 帅 忍 龙 你是猪 福 好运连连 欢迎 加油 想你 忘不了你 我错了 你…

细说JavaScript事件处理(JavaScript事件处理详解)

js语言的一个特色和就是它的动态性&#xff0c;即一时间驱动的方式对用户输入作出反应而不需要依赖服务器端程序。事件是指人机交互的结果&#xff0c;如鼠标移动、点击按钮、在表单中输入数据或载入新的Web洁面等。 一、什么是事件 1、事件类型 1.1、事件源 1.2、事件处理…

Node.js Stream.pipeline() Method

Why Stream.pipeline 通过流我们可以将一大块数据拆分为一小部分一点一点的流动起来&#xff0c;而无需一次性全部读入&#xff0c;在 Linux 下我们可以通过 | 符号实现&#xff0c;类似的在 Nodejs 的 Stream 模块中同样也为我们提供了 pipe() 方法来实现。 未使用 Stream p…

Pyro —— Understanding how pyro works

目录 Simulation fields Inside the Pyro Solver Colliders Pressure projection Simulation fields Pyro是纯体积流体解算器&#xff0c;表示流体状态的数据存于各种标量场和矢量场&#xff1b;Smoke Object会创建这些场&#xff0c;且能可视化这些场&#xff1b; vel场&…

【JavaEE】网络原理:网络中的一些基本概念

目录 1. 网络通信基础 1.1 IP地址 1.2 端口号 1.3 认识协议 1.4 五元组 1.5 协议分层 什么是协议分层 分层的作用 OSI七层模型 TCP/IP五层&#xff08;或四层&#xff09;模型 网络设备所在分层 网络分层对应 封装和分用 1. 网络通信基础 1.1 IP地址 概念:IP地址…

C语言/c++指针详细讲解【超详细】【由浅入深】

指针用法简单介绍 指针&#xff0c;是内存单元的编号。 内存条分好多好多小单元&#xff0c;一个小单元有 8 位&#xff0c;可以存放 8 个 0 或 1&#xff1b;也就是说&#xff0c;内存的编号不是以位算的&#xff0c;而是以字节算的&#xff0c;不是一个 0 或 1 是一个编号&…

立体视觉几何(一)

1.什么是立体视觉几何 立体视觉对应重建&#xff1a; • 对应&#xff1a;给定一幅图像中的点pl&#xff0c;找到另一幅图像中的对应点pr。 • 重建&#xff1a;给定对应关系(pl, pr)&#xff0c;计算空间中相应点的3D 坐标P。 立体视觉&#xff1a;从图像中的投影恢复场景中点…

list下

文章目录 注意&#xff1a;const迭代器怎么写&#xff1f;运用场合&#xff1f; inserterase析构函数赋值和拷贝构造区别&#xff1f;拷贝构造不能写那个swap,为什么&#xff1f;拷贝构造代码 面试问题什么是迭代器失效&#xff1f;vector、list的区别&#xff1f; 完整代码 注…

qt学习:QT对话框+颜色+文件+字体+输入

目录 概述 继承图 QColorDialog 颜色对话框 QFileDialog 文件对话框 保存文件对话框 QFontDialog 字体对话框 QInputDialog 输入对话框 概述 对于对话框的功能&#xff0c;在GUI图形界面开发过程&#xff0c;使用是非常多&#xff0c;那么Qt也提供了丰富的对话框类QDia…

网络:FTP

1. FTP 文件传输协议&#xff0c;FTP是用来传输文件的协议。使用FTP实现远程文件传输的同时&#xff0c;还可以保证数据传输的可靠性和高效性。 2. 特点 明文传输。 作用&#xff1a;可以从服务器上下载文件&#xff0c;或将本地文件上传到服务器。 3. FTP原理 FTP有控制层面…

坦克大战游戏代码

坦克大战游戏 主函数战场面板开始界面坦克父类敌方坦克我方坦克子弹爆炸效果数据存盘及恢复图片 主函数 package cn.wenxiao.release9;import java.awt.event.ActionEvent; import java.awt.event.ActionListener;import javax.swing.JFrame; import javax.swing.JMenu; impor…

RS-485通讯

RS-485通讯协议简介 与CAN类似&#xff0c;RS-485是一种工业控制环境中常用的通讯协议&#xff0c;它具有抗干扰能力强、传输距离远的特点。RS-485通讯协议由RS-232协议改进而来&#xff0c;协议层不变&#xff0c;只是改进了物理层&#xff0c;因而保留了串口通讯协议应用简单…

【HarmonyOS】掌握布局组件,提升应用体验

从今天开始&#xff0c;博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”&#xff0c;对于刚接触这项技术的小伙伴在学习鸿蒙开发之前&#xff0c;有必要先了解一下鸿蒙&#xff0c;从你的角度来讲&#xff0c;你认为什么是鸿蒙呢&#xff1f;它出现的意义又是…

【RT-DETR有效改进】华为 | GhostnetV2移动端的特征提取网络效果完爆MobileNet系列

前言 大家好&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持ResNet32、ResNet101和PP…

自动控制原理——数学模型建立

目标 1.数学模型概念 描述系统输入、输出变量以及内部个变量之间的关系的数学表达式 2.建模方法 解析法&#xff08;机理解析法&#xff09;: 根据系统工作所依据的物理定律写运动方程 实验法&#xff08;系统辨识法&#xff09;&#xff1a; 给系统施加某种测试信号&am…

万户 ezOFFICE wf_process_attrelate_aiframe.jsp SQL注入漏洞复现

0x01 产品简介 万户OA ezoffice是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品,统一的基础管理平台,实现用户数据统一管理、权限统一分配、身份统一认证。统一规划门户网站群和协同办公平台,将外网信息维护、客户服务、互动交流和日…