Fast SAM与YOLOV8检测模型一起使用实现实例分割以及指定物体分割

news2024/12/23 0:10:04

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等参数
部署核心代码

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

  • 加载模型并初始化核心代码
  cudaSetDevice(DEVICE);
  INPUT_W = input_w;
  INPUT_H = input_h;
  in_size = 1 * 3 * INPUT_W * INPUT_H;
  w = INPUT_W;
  h = INPUT_H;
  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 num_dets_idx = this->engine->getBindingIndex(NUM_DETS);
  const nvinfer1::Dims num_dets_dims =
      this->context->getBindingDimensions(num_dets_idx);
  this->out_sizes[num_dets_idx - NUM_INPUT].first =
      get_size_by_dims(num_dets_dims);
  this->out_sizes[num_dets_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(num_dets_idx));

  const int32_t bboxes_idx = this->engine->getBindingIndex(BBOXES);
  const nvinfer1::Dims bboxes_dims =
      this->context->getBindingDimensions(bboxes_idx);

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

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

  const int32_t labels_idx = this->engine->getBindingIndex(LABELS);
  const nvinfer1::Dims labels_dims =
      this->context->getBindingDimensions(labels_idx);
  this->out_sizes[labels_idx - NUM_INPUT].first = get_size_by_dims(labels_dims);
  this->out_sizes[labels_idx - NUM_INPUT].second =
      DataTypeToSize(this->engine->getBindingDataType(labels_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.3效果视频

效果视频

3 核心代码

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

晓理紫记录学习!

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

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

相关文章

Vue实现详细界面里面有一个列表

目录 Vue实现详细界面里面有一个列表 理一下思路&#xff1a; 效果如下&#xff1a; 1、 主页面正常写 2、详细界面(重点) 3、详细界面里面的列表(重点) 要点&#xff1a; Vue实现详细界面里面有一个列表 理一下思路&#xff1a; 1、首先需要这条数据的主键id&#xff…

包装类+初识泛型

目录 1 .包装类 1.1 基本数据类型对应的包装类 1.2.1装箱 ​1.2.2拆箱 2.初识泛型 2.1什么是泛型 2.2泛型类 2.3裸类型 2.4泛型的上界 2.5泛型方法 1 .包装类 基本数据类型所对应的类类型 在 Java 中&#xff0c;由于基本类型不是继承自 Object &#xff0c;为了在泛型…

LeetCode150道面试经典题--同构字符串(简单)

1.题目 给定两个字符串 s 和 t &#xff0c;判断它们是否是同构的。如果 s 中的字符可以按某种映射关系替换得到 t &#xff0c;那么这两个字符串是同构的。每个出现的字符都应当映射到另一个字符&#xff0c;同时不改变字符的顺序。不同字符不能映射到同一个字符上&#xff0c…

2022年06月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;倒序输出 依次输入4个整数a、b、c、d,将他们倒序输出&#xff0c;即依次输出d、c、b、a这4个数。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 一行4个整数a、b、c、d&#xff0c;以空格分隔。 0 < a,b,c,d < 108 输出 一行4个整数d、c、…

11.集群调度

文章目录 集群调度调度约束list-watc机制的概念pod的创建流程 调度过程Scheduler 作用预选策略优选策略指定调度节点nodeNamenodeSelector 亲和性node亲和pod亲和pod反亲和 污点&#xff08;Taint&#xff09;和容忍&#xff08;Tolerations&#xff09;污点(Taint)容忍(Tolera…

QT的界面切换

QT的界面切换 步骤一: 创建一个新的 ui 界面

pycharm配置conda虚拟环境

&#x1f4d5;作者简介&#xff1a;热编程的贝贝&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步健身&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于贝贝的日常汇报系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏深度学习、…

安装paddlehub后测试运行报错

昨晚按照官网提示安装paddle和paddlehub后&#xff0c;运行paddle测试成功了。但是当我测试paddlehub的时候总是提示缺少模块&#xff0c;非常纳闷&#xff0c;后面发现是官方的坑&#xff0c;所以在这里做个笔记。 测试paddlehub报错&#xff1a; #安装paddlehub命令 pip in…

权限管理之admin数据不可编辑

效果图 在线地址&#xff1a;https://codesandbox.io/s/authorizedbyrole-yzy4r2?file/src/util/directive.js 当前用户为非管理员角色 环境 vuetify2.6.6 vuex javascript 事情经过 一般的系统&#xff0c;都是采用**RBAC模型&#xff1a;基于用户-角色-权限控制** 所以在…

前端接口修改工具 Requestly具体操作

更新于2023年8月12日18:17:56&#xff0c;插件版本可能会变&#xff0c;界面可能会有所变化 插件下载地址&#xff1a;https://chrome.google.com/webstore/detail/requestly-open-source-htt/mdnleldcmiljblolnjhpnblkcekpdkpa 注意&#xff0c;必须用谷歌浏览器&#xff0c;…

安达发|APS车间排产软件对PCB企业有哪些意义?

PCB(printed circuit board)即印制线路板&#xff0c;简称印制板&#xff0c;是电子工业的重要部件之一。几乎每种电子设备&#xff0c;小到电子手表、计算器&#xff0c;大到计算机、通信电子设备、军用武器系统&#xff0c;只要有集成电路等电子元件&#xff0c;为了使各个元…

中科亿海微乘法器(LPMMULT)

引言 FPGA&#xff08;可编程逻辑门阵列&#xff09;是一种可在硬件级别上重新配置的集成电路。它具有灵活性和可重构性&#xff0c;使其成为处理各种应用的理想选择&#xff0c;包括数字信号处理、图像处理、通信、嵌入式系统等。在FPGA中&#xff0c;乘法器是一种重要的硬件资…

WPS-0DAY-20230809的分析和利用复现

WPS-0DAY-20230809的分析和初步复现 一、漏洞学习1、本地复现环境过程 2、代码解析1.htmlexp.py 3、通过修改shellcode拿shell曲折的学习msf生成sc 二、疑点1、问题2、我的测试测试方法测试结果 一、漏洞学习 强调&#xff1a;以下内容仅供学习和测试&#xff0c;一切行为均在…

STM32CubeMX之freeRTOS中断系统

任何中断的优先级都大于任务 优先级是从5-15 而不是0-15 因为前几个已经被freertos所控制了&#xff0c;因为操作系统不是万能的&#xff0c;所以我们需要弄一些中断凌驾在我们操作系统之上&#xff0c;中断中必须使用中断相关的函数&#xff01; 中断不能使用阻塞函数&#…

数据结构:力扣OJ题

目录 ​编辑题一&#xff1a;链表分割 思路一&#xff1a; 题二&#xff1a;相交链表 思路一&#xff1a; 题三&#xff1a;环形链表 思路一&#xff1a; 题四&#xff1a;链表的回文结构 思路一&#xff1a; 链表反转&#xff1a; 查找中间节点&#xff1a; 本人实力…

特语云用Linux和MCSM面板搭建 我的世界基岩版插件服 教程

Linux系统 用MCSM和DockerWine 搭建 我的世界 LiteLoaderBDS 服务器 Minecraft Bedrock Edition 也就是我的世界基岩版&#xff0c;这是 Minecraft 的另一个版本。Minecraft 基岩版可以运行在 Win10、Android、iOS、XBox、switch。基岩版不能使用 Java 版的服务器&#xff0c;…

Java多线程(十)

目录 一、synchronized基本特点 二、synchronized加锁工作过程 2.1 无锁 2.2 偏向锁 2.3 轻量级锁 2.4 重量级锁 三、synchronized其他优化操作 3.1 锁消除 3.2 锁粗化 一、synchronized基本特点 开始是乐观锁&#xff0c;如果锁冲突频繁就会转换成悲观锁开始是轻量级锁&#x…

python小白之matplotlib使用实战项目:随机漫步

文章目录 随机漫步1.1 创建RandomWalk类1.2 选择方向1.3 绘制随机漫步图1.4 模拟多次随机漫步1.5 设置随机漫步图样式1.5.1 给点着色1.5.2 重新绘制起点和终点1.5.3 隐藏坐标轴1.5.4 增加点数1.5.5 调整图片尺寸以适应屏幕 附录&#xff08;项目代码&#xff09;random_walk.py…

Linux 外部命令 - cat

Linux 外部命令 cat 英文帮助 NAME cat - concatenate files and print on the standard output SYNOPSIS cat [OPTION]... [FILE]... DESCRIPTION Concatenate FILE(s) to standard output. With no FILE, or when FILE is -, read standard input.…

ChatAI的几十种高级用法,可能是比较全的了(文末送书)

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…