Fast SAM与YOLOV8检测模型一起使用实现实例分割

Fast SAM与YOLOV8检测模型一起使用
部分源代码在结尾处可获取
晓理紫

1 使用场景

实例分割数据集的获取要比检测数据的获取更加困难,在已有检测模型不想从新标注分割数据进行训练但是又想获取相关物体的mask信息以便从像素级别对物体进行操作,这时就可以把检测模型与FastSAM模型配合进行时候实现分割的效果。

2 检测加分割效果

2.1 检测+分割

请添加图片描述

2.2 分割指定物体(分割交通灯,汽车,公交车)

请添加图片描述

3 部署使用

3.1 检测模型

这里使用的检测模型使用YOLOV8,使用TensorRT对YOLOV8进行部署

  • 部署条件

安装YOLOv8环境,可按照git进行配置

需要配置TensorRt相关环境,需要有显卡,安装驱动,CUDA以及TensorRT

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

2.2 trt模型转换

trt模型转换有多种方式,本文采用的是先把pt模型转成onnx模型参考,再把onnx通过trtexec工具进行转换。转换命令如下:

yolo mode=export model=yolov8s.pt  format=onnx dynamic=False
trtexec --onnx=yolov8.onnx --saveEngine=yolov8.engine 

注意: trtexec -h查看帮助,转fp16或者int8等参数
部署核心代码

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

  • 加载模型并初始化核心代码
  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);
                        

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

  • 数据获取并进行解析
  int *num_dets = static_cast<int *>(this->outputs[0]);
  auto *boxes = static_cast<float *>(this->outputs[1]);
  auto *scores = static_cast<float *>(this->outputs[2]);
  int *labels = static_cast<int *>(this->outputs[3]);
  for (int i = 0; i < num_dets[0]; i++) {
    float *ptr = boxes + i * 4;
    Object obj;
    float x0 = *ptr++ - this->dw;
    float y0 = *ptr++ - this->dh;
    float x1 = *ptr++ - this->dw;
    float y1 = *ptr++ - this->dh;

    x0 = clamp(x0 * this->ratio, 0.f, this->w);
    y0 = clamp(y0 * this->ratio, 0.f, this->h);
    x1 = clamp(x1 * this->ratio, 0.f, this->w);
    y1 = clamp(y1 * this->ratio, 0.f, this->h);
    if (!filterClass.empty() &&
        std::find(filterClass.begin(), filterClass.end(), int(*(labels + i))) ==
            filterClass.end())
      continue;
    if (x0 < 0 || y0 < 0 || x1 > this->w || y1 > this->h || (x1 - x0) <= 0 ||
        (y1 - y0) <= 0)
      continue;
    obj.rect.x = x0;
    obj.rect.y = y0;
    obj.rect.width = x1 - x0;
    obj.rect.height = y1 - y0;
    obj.prob = *(scores + i);
    obj.label = *(labels + i);
    obj.pixelBox.push_back(std::vector<float>{x0, y0});
    obj.pixelBox.push_back(std::vector<float>{x1, y1});
    obj.pixelBoxCent = std::vector<float>{(x0 + x1) / 2, (y0 + y1) / 2};
    obj.className = CLASS_NAMES[int(obj.label)];
    const std::vector<float> box = {x0, y0, x1, y1};
    cv::Mat maskmat;
  • 获取对应物体mask(前提已经使用FastSAM进行推理)
  float boxarea = (box[2] - box[0]) * (box[3] - box[1]);
  std::tuple<float, float, float, float> mapkey;
  float maxIoU = FLT_MIN;
  for (auto mapdata : boxMaskMat) {
    cv::Mat maskmat = mapdata.second;
    if (maskmat.rows == 0 || maskmat.cols == 0)
      continue;
    float orig_masks_area = cv::sum(maskmat)[0];
    cv::Rect roi(box[0], box[1], box[2] - box[0], box[3] - box[1]);
    cv::Mat temmask = maskmat(roi);
    float masks_area = cv::sum(temmask)[0];
    float union_arrea = boxarea + orig_masks_area - masks_area;
    float IoUs = masks_area / union_arrea;
    if (IoUs > maxIoU) {
      maxIoU = IoUs;
      mapkey = mapdata.first;
    }
  }
  mask = boxMaskMat[mapkey].clone();

  • 对物体进行过滤

这里对物体进行过滤,主要采取的方式是在检测模块获取物体信息时对物体标签进行过滤。

3.2 FastSAM分割模型

FastSAM分割模型的部署可以参考这篇。

3 核心代码

扫一扫,关注并回复yolov8+fastsam获取核心代码
在这里插入图片描述

晓理紫记录学习!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

模拟实现消息队列项目(系列5) -- 服务器模块(虚拟主机)

目录 前言 1. 创建VirtualHost 1.1 定义虚拟主机的相关属性 1.2 VirtualHost 构造方法 1.3 交换机和队列的创建和删除 1.3.1 交换机操作 1.3.2 队列操作 1.4 绑定的创建和删除 1.5 发送消息到指定的队列/交换机 2. 实现路由规则Router 2.1 checkBindingKey() 2.2 checkRoutin…

【软件测试】接口测试工具APIpost

说实话&#xff0c;了解APIpost是因为&#xff0c;我的所有接口相关的文章下&#xff0c;都有该APIpost水军的评论&#xff0c;无非就是APIpost是中文版的postman&#xff0c;有多么多么好用&#xff0c;虽然咱也还不是什么啥网红&#xff0c;但是不知会一声就乱在评论区打广告…

springboot项目问题

目录标题 问题后端1.[mybatis报错Parameter start not found. Available parameters are [1, 0, param1, param2]](https://www.cnblogs.com/josephcnblog/articles/7077244.html) 知识后端1. [Select 数据表的字段与实体类的属性值](https://www.cnblogs.com/yanguobin/p/1191…

【SpringBoot学习笔记】04. Thymeleaf模板引擎

模板引擎 templates下的只能通过Controller来跳转&#xff0c;templates前后端分离&#xff0c;需要模板引擎thymeleaf支持 模板引擎的作用就是我们来写一个页面模板&#xff0c;比如有些值呢&#xff0c;是动态的&#xff0c;我们写一些表达式。而这些值&#xff0c;从哪来呢…

【JavaWeb】MySQL基础操作

1 通用语法规则 SQL语句可以单行或者多行书写&#xff0c;以分号结尾SQL语句不区分大小写&#xff0c;关键字建议使用大写单行注释 --注释内容&#xff08;通用&#xff09; # 注释内容&#xff08;MySQL独有&#xff09;多行注释 /* 注释内容 */ 2 语句 数据库 -- 查…

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

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

微信小程序开发价格

小程序开发费用 小程序的开发费用是很多企业和个人在规划项目时需要重点考虑的一个方面。本文将从微信认证费、域名、服务器、程序开发费用、微信支付费率以及维护费用等多个角度为大家分析小程序开发费用的组成。 1. 微信认证费&#xff1a;作为小程序的一种信任凭证&#xf…

【Spring】实现FactoryBean接口

FactoryBean FactoryBean是一个接口&#xff0c;需要创建一个类来实现该接口&#xff0c;该接口中有三个方法&#xff0c;通过重写其中的两个方法&#xff0c;获得一个对象&#xff0c;三个方法分别是&#xff1a; 1.getObject():通过一个对象交给IOC容器管理2.getObjectType(…

ArcGIS在洪水灾害普查、风险评估及淹没制图中应用教程

详情点击链接&#xff1a;ArcGIS在洪水灾害普查、风险评估及淹没制图中应用教程 一&#xff1a;洪水普查技术规范 1.1 全国水旱灾害风险普查实施方案 1.2 洪水风险区划及防治区划编制技术要求 1.3 山丘区中小河流洪水淹没图编制技术要求 二&#xff1a;ArcGIS及数据管理 …

REDIS主从配置

目录 前言 一、概述 二、作用 三、缺点 四、redis主从复制的流程 五、搭建redis主从复制 总结 前言 Redis的主从配置是指在Redis集群中&#xff0c;将一个Redis节点配置为主节点&#xff08;master&#xff09;&#xff0c;其他节点配置为从节点&#xff08;slave&#xff09;…

用友移动管理系统 任意文件上传漏洞复现(HW0day)

0x01 产品简介 用友移动系统管理是用友公司推出的一款移动办公解决方案&#xff0c;旨在帮助企业实现移动办公、提高管理效率和员工工作灵活性。它提供了一系列功能和工具&#xff0c;方便用户在移动设备上管理和处理企业的系统和业务。 0x02 漏洞概述 用友移动管理系统 uploa…

【学会动态规划】买卖股票的最佳时机 III(17)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

【ARM64 常见汇编指令学习 15 -- ARM 标志位的学习】

文章目录 ARM 标志位介绍Zero Condition flag(零标志位)零标志位判断实例 上篇文章&#xff1a;ARM64 常见汇编指令学习 14 – ARM 汇编 .balign,.balignw,.balign 伪指令学习 下篇文章&#xff1a;ARM64 常见汇编指令学习 16 – ARM64 SMC 指令 ARM 标志位介绍 在ARM架构中&am…

JavaWeb-Servlet服务连接器(二)

目录 Request&#xff08;获取请求信息&#xff09; 1.获取请求行内容 2.解决乱码问题 3.获取请求头部分 4.获取请求体 5.其他功能 Request&#xff08;获取请求信息&#xff09; 工作流程&#xff1a; 1.通过请求的url的资源路径&#xff0c;tomcat会生成相应的Servlet实…

Mysql:Access denied for user ‘root‘@‘localhost‘ (using password:YES)解决方案

最近在配置Maven以及Mybatis时&#xff0c;连接localhost数据库时出现无法连接&#xff0c;用cmd测试时报错&#xff1a;Access denied for user ‘ODBC’‘localhost’ (using password: NO)&#xff0c;这个意思就是不允许远程访问&#xff0c;一开始笔者进入mysql试了一下是…

由于找不到d3dx9_42.dll,无法继续执行代码。重新安装程序可能会解决此问题

d3dx9_42.dll是一个动态链接库文件&#xff0c;它是Microsoft DirectX 9的一部分。这个文件包含了DirectX 9的一些函数和资源&#xff0c;用于支持计算机上运行基于DirectX 9的应用程序和游戏。它通常用于提供图形、音频和输入设备的支持&#xff0c;以及其他与图形和游戏相关的…

Playable 动画系统

Playable 基本用法 Playable意思是可播放的&#xff0c;可运行的。Playable整体是树形结构&#xff0c;PlayableGraph相当于一个容器&#xff0c;所有元素都被包含在里面&#xff0c;图中的每个节点都是Playable&#xff0c;叶子节点的Playable包裹原始数据&#xff0c;相当于输…

Vue+SpringBoot后台管理系统:Vue3+TypeScript项目搭建(一)

写在开始:一个搬砖程序员的随缘记录文章目录 一、Node安装二、Vue CLI安装三、相关的版本四、创建Vue3TypeScript项目五、Vue项目初始化六、项目启动 一、Node安装 查看Note版本 node -v查看npm版本 npm -v然后将npm升级至最新版本 npm -g install npm将npm下载源换至http:…

RS-232标准

目录 1、概述2、RS-232接口的特点3、RS-232接口协议【仿真】 1、概述 RS-232接口是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是“数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换…

C语言 二级指针和多级指针

什么是二级指针&#xff1f; 假设&#xff1a; int a 10;int * p &a;如上&#xff0c;p是指针变量&#xff0c;寄存的是a的地址&#xff0c;指向的是元素a 那么&#xff0c;指针变量p有地址吗&#xff1f;指针变量p的指针指向的是&#xff1f; int * * pp &p; …
最新文章