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

news2024/11/26 20:22:36

Fast SAM与YOLOV8检测模型一起使用
VX 搜索”晓理紫“ 关注并回复yolov8+fastsam获取核心代码
晓理紫

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 核心代码

VX 搜索”晓理紫“ 关注并回复yolov8+fastsam获取核心代码在这里插入图片描述

晓理紫记录学习!

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

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

相关文章

Redis原理简述

Redis原理简述 Redis 有哪些特性 1. 特性 key-value 型内存数据库单线程——原子化操作支持lua脚本发布与订阅可持久化逐出与过期……2. 持久化 RDB:经过压缩的二进制文件;fork子进程进行操作AOF:保存所有写命令;先写缓存再同步至AOF文件;文件过大时会触发AOF重写3. 过期…

4. 发布确认

4.1. 发布确认原理 生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm 模式&#xff0c;所有在该信道上面发布的 消息都将会被指派一个唯一的 ID(从 1 开始)&#xff0c;一旦消息被投递到所有匹配的队列之后&#xff0c;broker 就会发送一个确认给生产者(包含消…

[python]RuntimeError: Can‘t decrement id ref count (unable to close file...

使用spectralspatial模型进行EEG分类时&#xff0c;出现以下错误 RuntimeError: Cant decrement id ref count (unable to close file, errno 5, error message Input/output error) Segmentation fault (core dumped) 猜测是因为存储的model太大了导致的&#xff0c;找到了…

QGIS3.28的二次开发八:显示shp的属性表

这里实现两个基本的 GIS 软件需求&#xff1a;矢量图层的属性表显示&#xff0c;以及根据属性筛选要素。 具体需求如下&#xff1a; 加载一个矢量图层并打开其属性表&#xff1b;输入筛选条件确认无误后&#xff0c;画布上和属性表中均只显示筛选后的要素。 QGIS 提供了若干…

V3s uboot 通过env 修改LCD 参数信息

实际项目中我们可能使用各种参数的LCD 显示器&#xff0c;有7吋&#xff0c;4.3 寸等等&#xff0c;我这里使用的uboot 版本是U-Boot 2017.01-rc2 &#xff0c;在make menuconfig 时候会填入lcd 配置信息&#xff0c;如下&#xff1a; 所以这里使用起来很不方便&#xff0c;查看…

Vulnhub: DriftingBlues: 3靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.192 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.192 查看robots.txt得到提示 访问eventadmins提示littlequeenofspades.html 查看littlequeenofspades.html源码 base64解密…

掌握Python的X篇_35_用Python为美女打码_图像库Pillow

本篇将会介绍python中的一个图像库Pillow。 文章目录 1. Pillow与PIL的关系2. 调整大小3. 加滤镜4. 剪裁5. 生成验证码 1. Pillow与PIL的关系 我们在网上搜python的图像库的话&#xff0c;可能搜到的时PIL。实际上之前python发展的时候就是PIL&#xff0c;这个库比较好用&…

IL汇编语言做一个窗体

网上看到一段代码&#xff0c; .assembly extern mscorlib {} .assembly Classes { .ver 1:0:1:0 } .namespace MyForm { .class public TestForm extends [System.Windows.Forms]System.Windows.Forms.Form { .field private class [System]…

C语言快速回顾(二)

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》&#xff0c;结合我自己的工作学习经历&#xff0c;我准备写一个音视频系列blog。C/C是音视频必…

房屋中介系统springboot框架jsp房产信息管理java源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 房屋中介系统springboot框架 系统有1权限&#xff1a…

SAP MM学习笔记19- SAP中的库存处理 单纯的退货,交货不足和过量交货

下面这篇文章讲了 SAP中的库存类型。本篇讲一些库存处理场景。 SAP MM学习笔记19- SAP中的库存类型&#xff0c;以及 保留在库的利用场景_东京老树根的博客-CSDN博客 1&#xff0c;单纯的退货 收货之后发现不合格货物&#xff0c;然后就想退货。而且退货之后不想再要了&#…

RES 系列 GRES: Generalized Referring Expression Segmentation 论文阅读笔记

RES 系列 GRES: Generalized Referring Expression Segmentation 论文阅读笔记 一、Abstract二、引言三、相关工作有关的指代任务和数据集指代分割方法 四、任务设置及数据集4.1 GRES 设置RES 回顾一般化的 RES评估 4.2 gRefCOCO&#xff1a;一个大尺度的 GRES 数据集多目标样本…

使用腾讯云轻量服务器Matomo应用模板建网站流量统计系统

腾讯云百科分享使用腾讯云轻量应用服务器Matomo应用模板搭建网站流量统计系统&#xff0c;Matomo 是一款开源的网站数据统计软件&#xff0c;可以用于跟踪、分析您的网站的流量&#xff0c;同时充分保障数据安全性、隐私性。该镜像基于 CentOS 7.6 64位操作系统&#xff0c;已预…

Docker技术入门教程

Docker技术入门教程 一、docker概念 一款产品从开发到上线&#xff0c;从操作系统&#xff0c;到运行环境&#xff0c;再到应用配置。作为开发运维之间的协作我们需要关心很多东西&#xff0c;这也是很多互联网公司都不得不面对的问题&#xff0c;特别是各种版本的迭代之后&a…

Digital thread中文术语标准化|Digital thread何时是“数字主螺纹”的意思?

文章仅供个人学习使用&#xff0c;请勿传播&#xff01; 原文来源&#xff1a; 段海波 数字孪生体实验室 2021-12-30 18:22 https://mp.weixin.qq.com/s/-bgMkSewxOsjhTiagUnfsw 作者一直以来主张区分数字孪生系统和数字孪生体&#xff0c;进而构建系统化的数字孪生概念和术语体…

时序预测 | MATLAB实现基于BiLSTM双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于BiLSTM双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于BiLSTM双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 Matlab实现BiLST…

个人对哈希数据结构学习总结 -- 理论篇

个人对哈希数据结构学习总结 -- 理论篇 引言哈希表设计思考哈希冲突Hash Functions冲突解决开放地址法(Open Addressing)分离链表法(Separate Chaining)Two-way Chaining Dynamic Hash Tableschained Hashingextendible hashinglinear hashing说明 spiral storage 使用场景小结…

深入了解 Postman Test 校验的使用方法

Postman 是一个广泛使用的 API 开发工具&#xff0c;它允许开发人员测试 API 的各个方面&#xff0c;包括请求、响应、身份验证等等&#xff0c;其中最常用的功能之一就是 Test 校验。那今天就一起来看看 Postman 的 Test 校验该如何使用。 Test 校验是什么&#xff1f; Test…

Java中的继承

目标&#xff1a; 1&#xff0c;认识继承 Java中提供了一个关键字extends&#xff0c;用这个关键字&#xff0c;可以让一个类和另一个类建立起父子关系。 继承的特点&#xff1a; 子类可以继承父类的非私有成员&#xff08;成员变量&#xff0c;成员方法&#xff09;&#x…

LeetCode_04Java_88. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff1a;最终&#xff0c;合并后数组…