分割一切模型 Fast SAM C++推理部署---onnxruntime(有核心代码)

news2024/11/27 10:39:15

Fast SAM C++推理部署—onnxruntime
核心源代码在结尾处
晓理紫

0 XX开局一张图,剩下…

在这里插入图片描述
本文记录只为日后更好学习

1 Fast SAM 简介

Fast SAM是仅使用SAM作者发布的SA-1B数据集的2%进行训练的CNN任意分割模型。FastSAM的性能与SAM方法相当,运行速度提高了50倍。
在这里插入图片描述

在这里插入图片描述

2 onnxruntime部署

2.1 环境与条件

  • 需要配置onnxruntime相关环境

这个就网上自行解决

  • 需要把原始权重模型转为onnx模型

2.2 onnx模型转换

本文参考进行转换,在转换过程中需要把dynamic_axes设置为None,采用静态维度进行,在核心源码中我们提供了640以及1024大小的onnx模型。相关核心代码如下:

torch.onnx.export(model, 
      img,  
      output_model_path,
      export_params=True,       
      opset_version=11,        
      do_constant_folding=True,  
      input_names = ['images'],  
      output_names = output_names,
      dynamic_axes=None)

注意:dynamic_axes=None这个最为关键,当然你也可以试试设置为dynamic

2.3 部署核心代码

模型转换完成以后,剩下的就是部署推理。部署推理里面最为重要也是最难搞的是数据解析部分。其中模型加载是很标准的流程,当然我这里不一定是标准的。

  • 加载模型核心代码
  sessionOptions.SetExecutionMode(ORT_SEQUENTIAL);
  sessionOptions.EnableCpuMemArena();
  sessionOptions.SetIntraOpNumThreads(1);
  sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);
  ort_session = new Session(env, model_path.data(), sessionOptions);
  size_t numInputNodes = ort_session->GetInputCount();
  size_t numOutputNodes = ort_session->GetOutputCount();
  Ort::AllocatorWithDefaultOptions allocator;
  for (int i = 0; i < numInputNodes; i++) {
    this->input_names.emplace(ort_session->GetInputNameAllocated(i, allocator));
    Ort::TypeInfo input_type_info = ort_session->GetInputTypeInfo(i);
    auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();
    auto input_dims = input_tensor_info.GetShape();
    input_node_dims.push_back(input_dims);
  }
  for (int i = 0; i < numOutputNodes; i++) {
    this->output_names.emplace(
        ort_session->GetOutputNameAllocated(i, allocator));
    Ort::TypeInfo output_type_info = ort_session->GetOutputTypeInfo(i);
    auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
    auto output_dims = output_tensor_info.GetShape();
    output_node_dims.push_back(output_dims);
  }

  this->inpHeight = input_node_dims[0][2];
  this->inpWidth = input_node_dims[0][3];
  input_names__[0] = input_names->get();

模型加载以后,就可以送入数据进行推理

  • 推理
  xiaoliziprocessImage(frame, tmp);
  this->xiaoliziNormalize_(tmp);
  array<int64_t, 4> input_shape_{1, 3, this->inpHeight, this->inpWidth};
  auto allocator_info =
      MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
  Value input_tensor_ = Value::CreateTensor<float>(
      allocator_info, input_image_.data(), input_image_.size(),
      input_shape_.data(), input_shape_.size());

  vector<Value> ort_outputs = ort_session->Run(
      RunOptions{nullptr}, input_names__, &input_tensor_, 1, output_names__,
      sizeof(output_names__) / sizeof(char *)); // 开始推理

推理以后就可以获取数据并进行解析

  • 数据获取
  std::vector<cv::Mat> matVec;
  float *pdata = nullptr;
  pdata = ort_outputs[0].GetTensorMutableData<float>();
  if (pdata == nullptr) {
    std::cout << "pdata is nullptr" << std::endl;
    return;
  }
  cv::Mat matData(37, OUTPUT0w, CV_32F, pdata);
  matVec.push_back(matData);
  float *pdata5 = nullptr;
  pdata5 = ort_outputs[5].GetTensorMutableData<float>();
  if (pdata5 == nullptr) {
    std::cout << "pdata or pdata5 is nullptr" << std::endl;
    return;
  }
  cv::Mat matData5(32, OUTPUT1167w * OUTPUT1167w, CV_32F, pdata5);
  matVec.push_back(matData5);
  • 数据解析

首先是对数据进行分割处理并进行NMS获取box、lab以及mask相关信息

cv::Mat box;
cv::Mat cls;
cv::Mat mask;
box = temData.colRange(0, 4).clone();
cls = temData.colRange(4, 5).clone();
mask = temData.colRange(5, temData.cols).clone();
cv::Mat j = cv::Mat::zeros(cls.size(), CV_32F);
cv::Mat dst;
cv::hconcat(box, cls, dst); // dst=[A  B]
cv::hconcat(dst, j, dst);
cv::hconcat(dst, mask, dst);
std::vector<float> scores;
std::vector<cv::Rect> boxes;
pxvec = dst.ptr<float>(0);
for (int i = 0; i < dst.rows; i++) {
  pxvec = dst.ptr<float>(i);
  boxes.push_back(cv::Rect(pxvec[0], pxvec[1], pxvec[2], pxvec[3]));
  scores.push_back(pxvec[4]);
}
std::vector<int> indices;
xiaoliziNMSBoxes(boxes, scores, conf_thres, iou_thres, indices);
cv::Mat reMat;
for (int i = 0; i < indices.size() && i < max_det; i++) {
  int index = indices[i];
  reMat.push_back(dst.rowRange(index, index + 1).clone());
}
box = reMat.colRange(0, 6).clone();
xiaolizixywh2xyxy(box);
mask = reMat.colRange(6, reMat.cols).clone();

其次是获取mask相关数据

  for (int i = 0; i < bboxes.rows; i++) {
    pxvec = bboxes.ptr<float>(i);
    cv::Mat dest, mask;
    cv::exp(-maskChannels[i], dest);
    dest = 1.0 / (1.0 + dest);
    dest = dest(roi);
    cv::resize(dest, mask, frmae.size(), cv::INTER_LINEAR);
    cv::Rect roi(pxvec[0], pxvec[1], pxvec[2] - pxvec[0], pxvec[3] - pxvec[1]);
    cv::Mat temmask = mask(roi);
    cv::Mat boxMask = cv::Mat(frmae.size(), mask.type(), cv::Scalar(0.0));
    float rx = std::max(pxvec[0], 0.0f);
    float ry = std::max(pxvec[1], 0.0f);
    for (int y = ry, my = 0; my < temmask.rows; y++, my++) {
      float *ptemmask = temmask.ptr<float>(my);
      float *pboxmask = boxMask.ptr<float>(y);
      for (int x = rx, mx = 0; mx < temmask.cols; x++, mx++) {
        pboxmask[x] = ptemmask[mx] > 0.5 ? 1.0 : 0.0;
      }
    }
    vremat.push_back(boxMask);
  }

最后是画出相关信息

cv::Mat bbox = vremat[0];
  float *pxvec = bbox.ptr<float>(0);
  for (int i = 0; i < bbox.rows; i++) {
    pxvec = bbox.ptr<float>(i);
    cv::rectangle(image, cv::Point(pxvec[0], pxvec[1]),
                  cv::Point(int(pxvec[2]), int(pxvec[3])),
                  cv::Scalar(0, 0, 255), 2);
  }

  for (int i = 1; i < vremat.size(); i++) {
    cv::Mat mask = vremat[i];
    int indx = (rand() % (80 - 0)) + 0;
    for (int y = 0; y < mask.rows; y++) {
      const float *mp = mask.ptr<float>(y);
      uchar *p = image.ptr<uchar>(y);
      for (int x = 0; x < mask.cols; x++) {
        if (mp[x] == 1.0) {
          p[0] = cv::saturate_cast<uchar>(p[0] * 0.5 + COLORS[indx][0] * 0.5);
          p[1] = cv::saturate_cast<uchar>(p[1] * 0.5 + COLORS[indx][1] * 0.5);
          p[2] = cv::saturate_cast<uchar>(p[2] * 0.5 + COLORS[indx][2] * 0.5);
        }
        p += 3;
      }
    }
  }

3 核心代码

扫一扫,关注并回复fastsamonnx获取核心代码

在这里插入图片描述

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

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

相关文章

概率论与数理统计:第二、三章:一维~n维随机变量及其分布

文章目录 Ch2. 一维随机变量及其分布1.一维随机变量1.随机变量2.分布函数 F ( x ) F(x) F(x)(1)定义(2)分布函数的性质 (充要条件)(3)分布函数的应用——求概率3.最大最小值函数 2.一维离散型随机变量及其概率分布(分布律)3.一维连续型随机变量及其概率分布(概率密度)4.一般类型…

Linux基础篇(五)文件权限

目录 一、文件权限的概念 二、Linux命令ll的结果解析 三、Linux修改权限的两种方法 四、更改文件的拥有者和所属组 五、身份的判定 六、系统掩码 七、删除文件需要的权限 八、粘滞位 一、文件权限的概念 1.是什么&#xff1f; 简单地说就是什么身份的用户能对文件做什么事。 …

如何在CSS中水平居中一个元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 margin: 0 auto⭐ 使用 Flexbox 布局⭐ 使用绝对定位和负边距⭐ 使用表格布局⭐ 使用网格布局⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅…

【密码学】密码棒密码

密码棒密码 大约在公元前700年,古希腊军队使用一种叫做scytale的圆木棍来进行保密通信。其使用方法是这样的:把长带子状羊皮纸缠绕在圆木棍上,然后在上面写字;解下羊皮纸后,上面只有杂乱无章的字符,只有再次以同样的方式缠绕到同样粗细的棍子上,才能看出所写的内容。快速且不容…

STM32定时器TIM控制

一、CubeMX的设置 1、新建工程&#xff0c;进行基本配置 2、配置定时器TIM2 1&#xff09;定时器计算公式&#xff1a;&#xff08;以下两条公式相同&#xff09; Tout ((ARR1) * PSC1)) / Tclk TimeOut ((Prescaler 1) * (Period 1)) / TimeClockFren Tout TimeOut&…

选读SQL经典实例笔记23_读后总结与感想兼导读

1. 基本信息 SQL经典实例 SQL Cookbook [美]安东尼莫利纳罗&#xff08;Anthony Molinaro&#xff09; / 人民邮电出版社 / 2018-07 / 其他 人民邮电出版社,2018年7月出版第1版&#xff0c;2021年12月出版第2版 1.1. 读薄率 1版书籍总字数827千字&#xff0c;笔记总字数30…

sharedPreferences的使用之按钮状态切换的保存

什么是sharedPreferences&#xff1f;有什么用 SharedPreference是Android开发中一个轻量级的数据存储的方式&#xff0c;除了它还有SQLite数据库。它可以将数据以键值对的形式存放到文件中&#xff0c;在需要的时候再取出来使用。相比于去操作数据库&#xff0c;对于一些简单…

缓存穿透,击穿,雪崩之间的区别与联系

1、缓存数据基本流程 通常来说,我们是从数据库将数据查询出来之后,如果数据不为空,则将数据存储在缓存中,下次查询时就直接从缓存查询了,只有查询不到才会从数据库查询。 2、缓存穿透 核心在穿透两个字,穿透了,就说明在查询数据时没有遇到阻碍,直接就查询到了数据库。…

Spring-Cloud-Loadblancer详细分析_2

LoadBalancerClients 终于分析到了此注解的作用&#xff0c;它是实现不同服务之间的配置隔离的关键 Configuration(proxyBeanMethods false) Retention(RetentionPolicy.RUNTIME) Target({ ElementType.TYPE }) Documented Import(LoadBalancerClientConfigurationRegistrar…

记录--浏览器渲染15M文本导致崩溃怎么办

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 最近&#xff0c;我刚刚完成了一个阅读器的txt文件阅读功能&#xff0c;但在处理大文件时&#xff0c;遇到了文本内容过多导致浏览器崩溃的问题。 一般情况下&#xff0c;没有任何样式渲染时不会出现什…

《全生命周期眼健康管理》助力健康科学用眼

8月8日下午&#xff0c;烟台正大光明眼科医院眼健康管理中心张提主任受邀来到烟台市残疾人事务综合服务中心&#xff0c;为残联康复训练教师及相关工作人员进行了《全生命周期眼健康管理》讲座。 烟台正大光明眼科医院眼健康管理中心张提主任 “全生命周期眼健康”这一理念其宗…

u盘为什么提示格式化?u盘提示格式化怎么办

U盘是一种便携式存储设备&#xff0c;在使用U盘的过程中&#xff0c;有时候会出现提示需要格式化的情况。这种情况通常会让人担心自己重要的数据是否会丢失。那么&#xff0c;U盘为什么提示格式化&#xff1f;U盘提示格式化怎么办&#xff1f;在本文中&#xff0c;我们将探讨U盘…

80. 删除有序数组中的重复项 II

题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 解题思路&#xff1a;因为数组有序&#xff0c;相等的元素一定相邻&#xff0c;所以可以使用一个变量num统计相等元素的个数&#xff0c;如果当前元素和前一个元素相等&#xff0c…

【雕爷学编程】Arduino动手做(09)---火焰传感器模块3

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

【java面试题】不定义新变量的情况下交换两个Integer变量

题目&#xff1a; 不定义新变量的情况下交换两个Integer变量&#xff0c;完善swap&#xff08;&#xff09;方法&#xff1a; public class Main {public static void main(String[] args) {Integer a 10;Integer b 20;swap(a, b);System.out.printf("a is %d,b is %d&q…

TansUNet代码理解

首先通过论文中所给的图片了解网络的整体架构&#xff1a; vit_seg_modeling部分 模块引入和定义相关量&#xff1a; # codingutf-8 # __future__ 在老版本的Python代码中兼顾新特性的一种方法 from __future__ import absolute_import from __future__ import division fr…

制造业为什么要建设数字化供应链

数字化让越来越多的人走向了线上的世界&#xff0c;让那些拥有线上产品或提供线上服务的企业提供了更多流量。 但与此同时&#xff0c;传统制造业遭受了沉重的打击&#xff0c;考虑到防疫要求&#xff0c;很多工厂长期处于人手不足的状态&#xff0c;生产制造效率大幅降低&…

激活函数总结(六):ReLU系列激活函数补充(RReLU、CELU、ReLU6)

激活函数总结&#xff08;六&#xff09;&#xff1a;ReLU系列激活函数补充 1 引言2 激活函数2.1 RReLU激活函数2.2 CELU激活函数2.3 ReLU6 激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、Leaky ReLU、PReLU、Swish、ELU、SEL…

用python写一个简单的贪吃蛇游戏

入门教程、案例源码、学习资料、读者群 请访问&#xff1a; python666.cn 大家好&#xff0c;欢迎来到 Crossin的编程教室 &#xff01; 不知道有多少同学跟我一样&#xff0c;最初接触编程的动机就是为了自己做个游戏玩&#xff1f; Python 虽然并不是一个“为游戏而生”的语言…

给QT添加图片

给QT添加图片 第一步: 添加图片资源文件。