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

news2025/1/15 20:58:19

Fast SAM C++推理部署—TensorRT
核心源代码在结尾处有获取方式
晓理紫

0 XX开局一张图,剩下…

在这里插入图片描述

1 为什么需要trt部署

主要是在GPU上推理可以获得更高的推理速度。可与onnxruntim推理向比较一下

对比视频

2 TensorRt部署

2.1 环境与条件

  • 需要配置TensorRt相关环境

这个就需要有显卡,安装驱动,CUDA以及TensorRT

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

2.2 trt模型转换

trt模型转换有多种方式,本文采用的是先把pt模型转成onnx模型(),再把onnx通过trtexec工具进行转换。这里假设已经有onxx模型,转换命令如下:

trtexec --onnx=fastsam.onnx --saveEngine=fasrsam.engine 

注意: trtexec -h查看帮助,转fp16或者int8等参数

2.3 部署核心代码

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

  • 加载模型并初始化核心代码
  std::ifstream file(engine_file_path, std::ios::binary);
  assert(file.good());
  file.seekg(0, std::ios::end);
  auto size = file.tellg();
  std::ostringstream fmt;

  file.seekg(0, std::ios::beg);
  char *trtModelStream = new char[size];
  assert(trtModelStream);
  file.read(trtModelStream, size);
  file.close();
  initLibNvInferPlugins(&this->gLogger, "");
  this->runtime = nvinfer1::createInferRuntime(this->gLogger);
  assert(this->runtime != nullptr);

  this->engine = this->runtime->deserializeCudaEngine(trtModelStream, size);
  assert(this->engine != nullptr);

  this->context = this->engine->createExecutionContext();

  assert(this->context != nullptr);
  cudaStreamCreate(&this->stream);
  const nvinfer1::Dims input_dims =
      this->engine->getBindingDimensions(this->engine->getBindingIndex(INPUT));
  this->in_size = get_size_by_dims(input_dims);
  CHECK(cudaMalloc(&this->buffs[0], this->in_size * sizeof(float)));

  this->context->setBindingDimensions(0, input_dims);
  const int32_t output0_idx = this->engine->getBindingIndex(OUTPUT0);
  const nvinfer1::Dims output0_dims =
      this->context->getBindingDimensions(output0_idx);
  this->out_sizes[output0_idx - NUM_INPUT].first =
      get_size_by_dims(output0_dims);
  this->out_sizes[output0_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(output0_idx));

  const int32_t output1_idx = this->engine->getBindingIndex(OUTPUT1);
  const nvinfer1::Dims output1_dims =
      this->context->getBindingDimensions(output1_idx);

  this->out_sizes[output1_idx - NUM_INPUT].first =
      get_size_by_dims(output1_dims);
  this->out_sizes[output1_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(output1_idx));

  const int32_t Reshape_1252_idx = this->engine->getBindingIndex(Reshape_1252);
  const nvinfer1::Dims Reshape_1252_dims =
      this->context->getBindingDimensions(Reshape_1252_idx);
  this->out_sizes[Reshape_1252_idx - NUM_INPUT].first =
      get_size_by_dims(Reshape_1252_dims);
  this->out_sizes[Reshape_1252_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(Reshape_1252_idx));

  const int32_t Reshape_1271_idx = this->engine->getBindingIndex(Reshape_1271);
  const nvinfer1::Dims Reshape_1271_dims =
      this->context->getBindingDimensions(Reshape_1271_idx);
  this->out_sizes[Reshape_1271_idx - NUM_INPUT].first =
      get_size_by_dims(Reshape_1271_dims);
  this->out_sizes[Reshape_1271_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(Reshape_1271_idx));

  const int32_t Concat_1213_idx = this->engine->getBindingIndex(Concat_1213);
  const nvinfer1::Dims Concat_1213_dims =
      this->context->getBindingDimensions(Concat_1213_idx);
  this->out_sizes[Concat_1213_idx - NUM_INPUT].first =
      get_size_by_dims(Concat_1213_dims);
  this->out_sizes[Concat_1213_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(Concat_1213_idx));

  const int32_t OUTPUT1167_idx = this->engine->getBindingIndex(OUTPUT1167);
  const nvinfer1::Dims OUTPUT1167_dims =
      this->context->getBindingDimensions(OUTPUT1167_idx);
  this->out_sizes[OUTPUT1167_idx - NUM_INPUT].first =
      get_size_by_dims(OUTPUT1167_dims);
  this->out_sizes[OUTPUT1167_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(OUTPUT1167_idx));

  for (int i = 0; i < NUM_OUTPUT; i++) {
    const int osize = this->out_sizes[i].first * out_sizes[i].second;
    CHECK(cudaHostAlloc(&this->outputs[i], osize, 0));
    CHECK(cudaMalloc(&this->buffs[NUM_INPUT + i], osize));
  }
  if (warmup) {
    for (int i = 0; i < 10; i++) {
      size_t isize = this->in_size * sizeof(float);
      auto *tmp = new float[isize];

      CHECK(cudaMemcpyAsync(this->buffs[0], tmp, isize, cudaMemcpyHostToDevice,
                            this->stream));
      this->xiaoliziinfer();
    }
  }

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

  • 送入数据并推理
  float height = (float)image.rows;
  float width = (float)image.cols;

  float r = std::min(INPUT_H / height, INPUT_W / width);

  int padw = (int)std::round(width * r);
  int padh = (int)std::round(height * r);

  if ((int)width != padw || (int)height != padh) {
    cv::resize(image, tmp, cv::Size(padw, padh));
  } else {
    tmp = image.clone();
  }

  float _dw = INPUT_W - padw;
  float _dh = INPUT_H - padh;

  _dw /= 2.0f;
  _dh /= 2.0f;
  int top = int(std::round(_dh - 0.1f));
  int bottom = int(std::round(_dh + 0.1f));
  int left = int(std::round(_dw - 0.1f));
  int right = int(std::round(_dw + 0.1f));
  cv::copyMakeBorder(tmp, tmp, top, bottom, left, right, cv::BORDER_CONSTANT,
                     PAD_COLOR);
  cv::dnn::blobFromImage(tmp, tmp, 1 / 255.f, cv::Size(), cv::Scalar(0, 0, 0),
                         true, false, CV_32F);
  CHECK(cudaMemcpyAsync(this->buffs[0], tmp.ptr<float>(),
                        this->in_size * sizeof(float), cudaMemcpyHostToDevice,
                        this->stream));
  this->context->enqueueV2(buffs.data(), this->stream, nullptr);
  for (int i = 0; i < NUM_OUTPUT; i++) {
    const int osize = this->out_sizes[i].first * out_sizes[i].second;
    CHECK(cudaMemcpyAsync(this->outputs[i], this->buffs[NUM_INPUT + i], osize,
                          cudaMemcpyDeviceToHost, this->stream));
  }
  cudaStreamSynchronize(this->stream);
                        

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

  • 数据获取
cv::Mat matData(37, OUTPUT0w, CV_32F, pdata);
  matVec.push_back(matData);

  float *pdata1 = nullptr;
  pdata1 = static_cast<float *>(this->outputs[2]);
  if (pdata1 == nullptr) {
    return;
  }
  cv::Mat matData1(105, OUTPUT1w * OUTPUT1w, CV_32F, pdata1);
  matVec.push_back(matData1);

  float *pdata2 = nullptr;
  pdata2 = static_cast<float *>(this->outputs[3]);
  if (pdata2 == nullptr) {
    return;
  }
  cv::Mat matData2(105, Reshape_1252w * Reshape_1252w, CV_32F, pdata2);
  matVec.push_back(matData2);

  float *pdata3 = nullptr;
  pdata3 = static_cast<float *>(this->outputs[4]);
  if (pdata3 == nullptr) {
    return;
  }
  cv::Mat matData3(105, Reshape_1271w * Reshape_1271w, CV_32F, pdata3);
  matVec.push_back(matData3);

  float *pdata4 = nullptr;
  pdata4 = static_cast<float *>(this->outputs[1]);
  if (pdata4 == nullptr) {
    return;
  }
  cv::Mat matData4(Concat_1213w, 32, CV_32F, pdata4);
  matVec.push_back(matData4);

  float *pdata5 = nullptr;
  pdata5 = static_cast<float *>(this->outputs[0]);
  if (pdata5 == nullptr) {
    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 核心代码

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

在这里插入图片描述

晓理紫爱学习爱记录爱分享!

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

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

相关文章

【uniapp】uniapp使用微信开发者工具制作骨架屏:

文章目录 一、效果&#xff1a;二、过程&#xff1a; 一、效果&#xff1a; 二、过程&#xff1a; 【1】微信开发者工具打开项目&#xff0c;生成骨架屏&#xff0c;将wxml改造为vue页面组件&#xff0c;并放入样式 【2】页面使用骨架屏组件 【3】改造骨架屏&#xff08;去除…

Mr. Cappuccino的第61杯咖啡——Spring之BeanPostProcessor

Spring之BeanPostProcessor 概述基本使用项目结构项目代码运行结果源代码 常用处理器项目结构项目代码执行结果 概述 BeanPostProcessor&#xff1a;Bean对象的后置处理器&#xff0c;负责对已创建好的bean对象进行加工处理&#xff1b; BeanPostProcessor中的两个核心方法&am…

scope,deep穿透的实际应用

一.父组件代码 <template><div id"app"><h1 class"box"><pageName> </pageName></h1></div> </template><script> import pageName from "../src/components/pageName.vue"; export de…

感谢@艾玛·沃特森提供的华为OD机试【按单词下标区间翻转文章内容】【2023 B卷 100分】

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明4、再输入5、处理非法输入&#xff0c;确保通过率100%&#xff0c;千万不要大意失荆州 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 感谢艾玛沃特森提供…

【CheatSheet】Python、R、Julia数据科学编程极简入门

《Python、R、Julia数据科学编程极简入门》PDF版&#xff0c;是我和小伙伴一起整理的备忘清单&#xff0c;帮助大家10分钟快速入门数据科学编程。 另外&#xff0c;最近 TIOBE 公布了 2023 年 8 月的编程语言排行榜。 Julia 在本月榜单中实现历史性突破&#xff0c;成功跻身 …

C语言学习之一级指针二级指针

一级指针&#xff1a;内存中每个字节都有一个编号&#xff0c;这个编号就是指针&#xff0c;也称作地址&#xff1b;专门用来存储地址的变量&#xff0c;就是指针变量&#xff1b;定义一级指针变量并初始化&#xff1a; 数据类型 *指针变量名 &普通变量名; 数据类型 *指针…

原子css 和 组件化css如何搭配使用

如果让你来实现下面这种页面&#xff0c;该怎么实现呢 原子化和css组件化方式写法&#xff0c;可以搭配起来使用&#xff0c;常用的css 原子css 比如 下面这些类似flex 布局&#xff0c;lstn curser-pointer 等常用的或者 具备一定规律性的padding margin 样式可以抽取为单独…

排序算法————基数排序(RadixSort)

基数排序的概念&#xff1a; 什么是基数排序&#xff1f;&#xff1f;&#xff1f;基数排序是一种和快排、归并、希尔等等不一样的排序...它不需要比较和移动就可以完成整型的排序。它是时间复杂度是O&#xff08;K*N&#xff09;&#xff0c;空间复杂度是O&#xff08;KM&…

【软件测试】UI自动化框架,数据驱动 vs 关键字驱动怎么选

一、UI自动化测试用例剖析 让我们先从分析一端自动化测试案例的代码开始我们的旅程。以下是我之前写的一个自动化测试的小Demo。这个Demo基于Selenium与Java。 自动化测试小Demo 它要测试的东西其实是要看一下百度搜索能不能返回兴业银行的官网。我们分析一下这段代码都包含些…

C++笔记之字节数组的处理

C笔记之字节数组的处理 code review! 文章目录 C笔记之字节数组的处理1.字节数组打印2.将字节数组转换为十六进制字符串并打印3.将字符串转为字节数组4.将字节数组转为字符串5.字节数组和字符数组的区别6.字节数组用于二进制数据存储7.字节数组用于网络通信数据传输8.使用 un…

【字节跳动青训营】后端笔记整理-2 | Go实践记录:猜谜游戏,在线词典,Socks5代理服务器

**本人是第六届字节跳动青训营&#xff08;后端组&#xff09;的成员。本文由博主本人整理自该营的日常学习实践&#xff0c;首发于稀土掘金&#xff1a;&#x1f517;Go实践记录&#xff1a;猜谜游戏&#xff0c;在线词典&#xff0c;Socks5代理服务器 | 青训营 我的go开发环境…

群晖7.X版安装cpolar内网穿透

群晖7.X版安装cpolar内网穿透套件 文章目录 群晖7.X版安装cpolar内网穿透套件前言1. 下载cpolar的群晖系统套件1.1 在“套件中心” 选择“手动安装”1.2 完成套件安装 2. 进入cpolar软件信息页3. 点击“免费注册”轻松获得cpolar账号 前言 随着群晖系统的更新换代&#xff0c;…

第一百二十七天学习记录:我的创作纪念日

机缘 今天收到CSDN官方的来信&#xff0c;想想也可以对我前面的学习记录进行一个总结。 关于来到CSDN的初心&#xff0c;也就是为了让自己养成一个良好的学习总结的习惯。这里要感谢我C语言视频教程的老师&#xff0c;是他建议学生们在技术博客中进行记录。对于技术博客&…

【Plex】FRP内网穿透后 App无法使用问题

能搜索到这个文章的&#xff0c;应该都看过这位同学的分析【Plex】FRP内网穿透后 App无法使用问题_plex frp无效_Fu1co的博客-CSDN博客 这个是必要的过程&#xff0c;但是设置之后仍然app端无法访问&#xff0c;原因是因为网络端口的问题 这个里面的这个公开端口&#xff0c;可…

EVE-NG MPLS L2VPN BGP lsp

导入了新的H3C 镜像&#xff0c;bgp 正常了。 目录 1 拓扑 2 配置步骤 2.1 配置接口IP 和路由协议 2.2 配置MPLS LDP 2.3 配置L2VPN BGP 2.4 配置 xconnect-group 2.5 验证L2VPN 1 拓扑 2 配置步骤 2.1 配置接口IP 和路由协议 PE1 interface LoopBack 0ip address 1…

LNMP环境搭建wordpress以及跳转后台报404解决

基于上文配置好的LNMP环境继续搭建wordpress 目录 一.到官网下载tar.gz包&#xff0c;并上传到Linux上&#xff0c;也可以通过复制链接地址进行下载 二. 将wordpress中的所有文件移动到你nginx.conf中指定目录中 三.为wordpress配置数据库 四.到浏览器进行注册 1.刚开始…

使用QT纯代码创建(查找)对话框详细步骤与代码

一、创建项目文件 打开Qt Creator->文件->新建文件或项目->选择Qt Widgets Application 为项目起名字 输入类的名字 二、 了解每个文件的作用 项目创建完毕之后就会出现以下几个文件&#xff0c;先来分别介绍以下这些文件的作用。 Headers->finddialog.h——很显…

Java:函数式(Functional)接口

文章目录 1 什么是函数式接口2 如何理解函数式接口3 举例Java 内置函数式接口1 之前的函数式接口2 四大核心函数式接口3.4.3 其它接口 内置接口代码演示 5 练习 1 什么是函数式接口 只包含一个抽象方法&#xff08;Single Abstract Method&#xff0c;简称SAM&#xff09;的接…

虚拟机/双系统Ubuntu扩容

虚拟机Ubuntu扩容 1.需要删除所有的快照 2.扩展虚拟机磁盘大小 虚拟机(M)→设置(s)→硬盘(SCSI)→扩展磁盘容量 3.Ubuntu内调整分区大小 安装gparted分区工具&#xff1a;sudo apt-get install gparted 启动gparted并resize分区 4.最后最好建一个快照&#xff0c;不然gg了…