yolov8 瑞芯微 RKNN 的 C++部署

这篇具有很好参考价值的文章主要介绍了yolov8 瑞芯微 RKNN 的 C++部署。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

   上一篇博客 yolov8 瑞芯微RKNN和地平线Horizon芯片仿真测试部署 写了在rknn模型的转换与PC端仿真测试,有网友希望写一篇在板子上部署的博文和开源提供C++代码。这一篇基于rknn板子进行C++部署,并开源提供完整的源代码和模型,供网友自行进行测试验证。

特别说明:如有侵权告知删除,谢谢。

【完整代码】代码和模型

1、rknn模型准备

   onnx转rknn模型这一步就不再赘述,请参考上一篇 ”yolov8 瑞芯微RKNN和地平线Horizon芯片仿真测试部署“ 。上一篇提供了完整的模型和代码,如果仅仅是想验证模型,可以直接拿提供的rknn模型进行后续的步骤,本篇也是基于上一篇转好的rknn模型进行的,在rk3588芯片部署测试。

2、C++代码准备

   本篇中的 C++ 代码基于瑞芯微官方提供的 rknpu2_1.3.0 进行的。官方提供的开源示例参考 ,提取码:rknn .

3、C++ 代码说明

   模型和图片读取部分参考官方提供的示例,主要说明后处理部分。定义了一个yolov8后处理类,将模型输出进行解码处理,解码结果装在一个vector中,装的格式按照 classId,score,xmin,ymin,xmax,ymax, classId,score,xmin,ymin,xmax,ymax … 进行,每六个数据为一个检测框,对 vector 进行遍历得到检测结。

   // 后处理部分
   std::vector<float> out_scales;
   std::vector<int32_t> out_zps;
   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);
   }

   int8_t *pblob[6];
   for (int i = 0; i < io_num.n_output; ++i)
   {
       pblob[i] = (int8_t *)outputs[i].buf;
   }

   // 将检测结果按照classId、score、xmin1、ymin1、xmax1、ymax1 的格式存放在vector<float>中
   GetResultRectYolov8 PostProcess;
   std::vector<float> DetectiontRects;
   PostProcess.GetConvDetectionResult(pblob, out_zps, out_scales, DetectiontRects);

   for (int i = 0; i < DetectiontRects.size(); i += 6)
   {
       int classId = int(DetectiontRects[i + 0]);
       float conf = DetectiontRects[i + 1];
       int xmin = int(DetectiontRects[i + 2] * float(img_width) + 0.5);
       int ymin = int(DetectiontRects[i + 3] * float(img_height) + 0.5);
       int xmax = int(DetectiontRects[i + 4] * float(img_width) + 0.5);
       int ymax = int(DetectiontRects[i + 5] * float(img_height) + 0.5);

       char text1[256];
       sprintf(text1, "%d:%.2f", classId, conf);
       rectangle(src_image, cv::Point(xmin, ymin), cv::Point(xmax, ymax), cv::Scalar(255, 0, 0), 2);
       putText(src_image, text1, cv::Point(xmin, ymin + 15), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 0, 255), 2);
   }

   imwrite(save_image_path, src_image);

后处理核心部分代码如下,其中后处理代码不一定是最优的,如果有更优的写法欢迎交流。完整代码请参本实例对应的github仓库,代码和模型 。

int GetResultRectYolov8::GetConvDetectionResult(int8_t **pBlob, std::vector<int> &qnt_zp, std::vector<float> &qnt_scale, std::vector<float> &DetectiontRects)
{
    int ret = 0;
    if (meshgrid.empty())
    {
        ret = GenerateMeshgrid();
    }

    int gridIndex = -2;
    float xmin = 0, ymin = 0, xmax = 0, ymax = 0;
    float cls_val = 0;
    float cls_max = 0;
    int cls_index = 0;

    int quant_zp_cls = 0, quant_zp_reg = 0;
    float quant_scale_cls = 0, quant_scale_reg = 0;

    DetectRect temp;
    std::vector<DetectRect> detectRects;

    for (int index = 0; index < headNum; index++)
    {
        int8_t *reg = (int8_t *)pBlob[index * 2 + 0];
        int8_t *cls = (int8_t *)pBlob[index * 2 + 1];

        quant_zp_reg = qnt_zp[index * 2 + 0];
        quant_zp_cls = qnt_zp[index * 2 + 1];

        quant_scale_reg = qnt_scale[index * 2 + 0];
        quant_scale_cls = qnt_scale[index * 2 + 1];

        for (int h = 0; h < mapSize[index][0]; h++)
        {
            for (int w = 0; w < mapSize[index][1]; w++)
            {
                gridIndex += 2;

                if (1 == class_num)
                {
                    cls_max = sigmoid(DeQnt2F32(cls[0 * mapSize[index][0] * mapSize[index][1] + h * mapSize[index][1] + w], quant_zp_cls, quant_scale_cls));
                    cls_index = 0;
                }
                else
				{
                    for (int cl = 0; cl < class_num; cl++)
                    {
						cls_val = cls[cl * mapSize[index][0] * mapSize[index][1] + h * mapSize[index][1] + w];

						if (0 == cl)
						{
                            cls_max = cls_val;
                            cls_index = cl;
						}
						else
						{
                            if (cls_val > cls_max)
                            {
                            	cls_max = cls_val;
                            	cls_index = cl;
                            }
						}
                    }
                    cls_max = sigmoid(DeQnt2F32(cls_max, quant_zp_cls, quant_scale_cls));
					}


                if (cls_max > objectThresh)
                {
                    xmin = (meshgrid[gridIndex + 0] - DeQnt2F32(reg[0 * mapSize[index][0] * mapSize[index][1] + h * mapSize[index][1] + w], quant_zp_reg, quant_scale_reg)) * strides[index];
                    ymin = (meshgrid[gridIndex + 1] - DeQnt2F32(reg[1 * mapSize[index][0] * mapSize[index][1] + h * mapSize[index][1] + w], quant_zp_reg, quant_scale_reg)) * strides[index];
                    xmax = (meshgrid[gridIndex + 0] + DeQnt2F32(reg[2 * mapSize[index][0] * mapSize[index][1] + h * mapSize[index][1] + w], quant_zp_reg, quant_scale_reg)) * strides[index];
                    ymax = (meshgrid[gridIndex + 1] + DeQnt2F32(reg[3 * mapSize[index][0] * mapSize[index][1] + h * mapSize[index][1] + w], quant_zp_reg, quant_scale_reg)) * strides[index];

                    xmin = xmin > 0 ? xmin : 0;
                    ymin = ymin > 0 ? ymin : 0;
                    xmax = xmax < input_w ? xmax : input_w;
                    ymax = ymax < input_h ? ymax : input_h;

                    if (xmin >= 0 && ymin >= 0 && xmax <= input_w && ymax <= input_h)
                    {
                        temp.xmin = xmin / input_w;
                        temp.ymin = ymin / input_h;
                        temp.xmax = xmax / input_w;
                        temp.ymax = ymax / input_h;
                        temp.classId = cls_index;
                        temp.score = cls_max;
                        detectRects.push_back(temp);
                    }
                }
            }
        }
    }

    std::sort(detectRects.begin(), detectRects.end(), [](DetectRect &Rect1, DetectRect &Rect2) -> bool
              { return (Rect1.score > Rect2.score); });

    std::cout << "NMS Before num :" << detectRects.size() << std::endl;
    for (int i = 0; i < detectRects.size(); ++i)
    {
        float xmin1 = detectRects[i].xmin;
        float ymin1 = detectRects[i].ymin;
        float xmax1 = detectRects[i].xmax;
        float ymax1 = detectRects[i].ymax;
        int classId = detectRects[i].classId;
        float score = detectRects[i].score;

        if (classId != -1)
        {
            // 将检测结果按照classId、score、xmin1、ymin1、xmax1、ymax1 的格式存放在vector<float>中
            DetectiontRects.push_back(float(classId));
            DetectiontRects.push_back(float(score));
            DetectiontRects.push_back(float(xmin1));
            DetectiontRects.push_back(float(ymin1));
            DetectiontRects.push_back(float(xmax1));
            DetectiontRects.push_back(float(ymax1));

            for (int j = i + 1; j < detectRects.size(); ++j)
            {
                float xmin2 = detectRects[j].xmin;
                float ymin2 = detectRects[j].ymin;
                float xmax2 = detectRects[j].xmax;
                float ymax2 = detectRects[j].ymax;
                float iou = IOU(xmin1, ymin1, xmax1, ymax1, xmin2, ymin2, xmax2, ymax2);
                if (iou > nmsThresh)
                {
                    detectRects[j].classId = -1;
                }
            }
        }
    }

    return ret;
}


4、编译运行

1)编译

cd examples/rknn_yolov8_demo_open

bash build-linux_RK3588.sh

2)运行

cd install/rknn_yolov8_demo_Linux

./rknn_yolov8_demo

注意:修改模型、测试图像、保存图像的路径,所在文件为 src 下main.cc文件。

5、板端效果

冒号“:”前的数子是coco的80类对应的类别,后面的浮点数是目标得分。(类别:得分)
rknn部署,YOLO,c++,开发语言
(注:图片来源coco128)

说明:推理测试预处理没有考虑等比率缩放,激活函数 SiLU 用 Relu 进行了替换。由于使用的是coco128的128张图片数据进行训练的,且迭代的次数不多,效果并不是很好,仅供测试流程用。换其他图片测试检测不到属于正常现象,最好选择coco128中的图像进行测试。

6、模型和后处理时耗

把模型和后处理时耗贴出来,供大家参考,使用芯片rk3588。
rknn部署,YOLO,c++,开发语言

2024年1月12日:后处理代码有所优化,后处理时耗由21ms降低至8ms。(检测类别越多效果越明显,检测1个类别就没有优化效果,代码已同步到对应的代码仓中)
rknn部署,YOLO,c++,开发语言文章来源地址https://www.toymoban.com/news/detail-601414.html

到了这里,关于yolov8 瑞芯微 RKNN 的 C++部署的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 瑞芯微RK3588 C++部署Yolov8检测和分割模型

    最近这一个月在研究国产瑞芯微板子上部署yolov8的检测和分割模型,踩了很多坑,记录一下部署的过程和遇到的一些问题: 需要的环境和代码主要包括: (1)rknn-toolkit2-1.5.2:工具链,开发环境 (2)rockchip-yolov8:pt模型转onnx模型 (3)yolov8_onnx2rknn:在(2)的基础上转检测

    2024年04月09日
    浏览(42)
  • 36、RK3399Pro 环境搭建和Yolov5 c++调用opencv进行RKNN模型部署和使用

    基本思想:记录rk3399 pro配置环境和c++ npu开发记录,主要想搞一份c++代码和其它图像算法结合一下,好进行部署,淘宝链接见附录  需要的python3.7对应的aarch64的whl包:包含opencv-whl 、h5py-whl包: 链接: https://pan.baidu.com/s/1cvCAmHBa_4KgEjrcFIYnig 提取码: 5ui4 链接: https://pan.baidu.com/s/1hrc

    2024年02月07日
    浏览(30)
  • yolov5训练pt模型并转换为rknn模型,部署在RK3588开发板上——从训练到部署全过程

    目录 一、任务介绍 二、实验过程 2.1 使用正确版本的yolov5进行训练(平台:x86机器windows系统) 2.2 best.pt转换为best.onnx(平台:x86机器window系统) 2.3 best.onnx转换为best.rknn(平台:x86机器Linux系统) 2.3.1 环境准备和工具包安装 2.3.2 onnx转换为rknn 2.4 RK3588部署rknn实现NPU加速(平台:

    2024年02月03日
    浏览(37)
  • 模型部署——rknn-toolkit-lite2部署RKNN模型到开发板上(python版)

    欢迎学习RKNN系列相关文章,从模型转换、精度分析,评估到部署,推荐好资源: 一、Ubuntu系统上安装rknn-toolkit 二、使用rknn-toolkit将Pytorch模型转为RKNN模型 三、RKNN模型的评估和推理测试 四、RKNN模型量化精度分析及混合量化提高精度 五、RKNN模型性能评估和内存评估 六、rkn

    2024年04月11日
    浏览(28)
  • 使用rknn-toolkit2把YOLOV5部署到OK3588上

    首先在PC的ubuntu系统安装虚拟环境: 我的服务器是ubuntu18.04版本,所以安装python3.6 conda create -n ok3588 python=3.6 需要键盘输入y,然后完成虚拟环境安装。 其他系统的对应关系: Ubuntu 18.04 python 3.6 / Ubuntu 20.04 python 3.8 / Ubuntu 22.04 python 3.10 进入虚拟环境 conda activate ok3588 首先安装正

    2024年02月16日
    浏览(29)
  • 瑞芯微RK3568/RK3588平台YOLOV5实时视频算法的部署小白教程

    本文实现整体的部署流程比较小白,首先在PC上分别实现工程中的模型仿真推理、yolov5-pytorch仿真推理、自己训练yolov5模型仿真推理,完成仿真之后再在板端分别实现rk提供模型的板端推理、yolov5-pytorch板端推理、自己训练的yolov5模型板端推理,最后实现自己训练的yolov5模型实

    2024年02月06日
    浏览(38)
  • yolo v8 转rknn

    上一篇:yolo v7 转rknn 本文: 1.是对detect模型的转换,对于classify、pose、segment后续再写,估计是差不多的; 2. ☆ 支持量化。对于置信度量化后会全为0已经解决; 3.解决转换过程中出现的一些错误提示。主要是数组轴的大小超出限制的问题。 ultralytics-8.0.213 v8的训练可以参考:

    2024年02月01日
    浏览(29)
  • yolo v7 转rknn

    上一篇:yolo v5-release6.0转rknn 下一篇:yolo v8 转rknn v7的训练可以参考v5训练:yolov5 初识(ubuntu版)、yolov5 初识(win版) 注意一下,opset_version=12 (样式照搬官方已有实例:test.jpg为任意一张测试集里的数据,dataset.txt为量化数据集的路径(200~500张?我也不太确定,这里只用了1张),

    2023年04月08日
    浏览(22)
  • 香橙派5 RK3588 yolov5模型转换rknn及部署踩坑全记录 orangepi 5

    由于距离写这篇文章过去很久,有的部分,官方已更新,请多结合其他人的看,并多琢磨、讨论~ 另外打个小广告: 博客 https://blog.vrxiaojie.top/ 欢迎大家前来做客玩耍,提出问题~~ 以后的文章都会在博客发布了,CSDN这边可能这是最后一篇文章。 (1) 使用官方提供的Ubuntu镜像:

    2024年02月05日
    浏览(40)
  • yolov5训练自己的pt文件,转onnx,再转成rknn,到RK3588开发板运行测试

    yolov5训练好自己的模型,例如训练完后,名称为best.pt,路径为runs/exp/weights/best.pt。 采用detect.py文件验证best.pt可以正常检测目标,再进行下一步工作。 修改utils/yolo.py文件的后处理部分,将class Detect(nn.Module) 类的子函数forward由 修改为: 注意:训练和检测的时候,yolo.py文件应

    2024年02月01日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包