YOLO目标检测应用——基于 YOLOv8目标检测和 SAM 零样本分割实现指定目标分割

概述

在当前的计算机视觉领域,目标分割技术正变得越来越重要。市面上有许多分割模型,它们的工作原理大致相似,通常包括收集数据、配置模型以及训练分割模型等步骤。最终目标是实现精确的目标分割。而随着 SAM(Segment Anything Model)的出现,这一过程变得更加高效。SAM 的独特之处在于,它只需要用户向模型提供某种坐标信息,就能自动完成所有分割工作,极大地简化了操作流程。


在深入探讨之前,可能会提出这样一个问题:为何选择 YOLO 模型作为我们的工具? 答案十分明确:SAM(Segment Anything Model)本身并不具备直接输出目标类别标签的功能。 它仅能依据用户提供的位置信息来执行分割任务。而 YOLO 模型的引入,恰到好处地填补了这一空白。借助目标检测模型,我们能够精准地定位目标的位置,并获取其对应的类别标签。随后,利用这些位置数据引导 SAM 进行分割操作,从而最终实现目标的清晰分割,并为分割结果赋予明确的类别标注。

与传统分割模型不同,SAM(Segment Anything Model)在执行分割任务时,需要用户主动提供目标的位置信息。这些位置信息有三种主要类型:

  1. 单点输入:仅提供一个坐标点(x,y),用于指示目标的大致位置。
  2. 边界框输入:提供一个边界框的坐标(x1,y1,x2,y2),明确指定目标的区域范围。
  3. 多点输入:同时输入多个正点和负点,以更精细地引导模型进行分割。

鉴于我们采用的是 YOLO 模型,边界框方法无疑是最佳选择。YOLO 模型能够直接输出目标的边界框坐标,这与 SAM 的输入需求完美契合。因此,我们可以无缝地将 YOLO 模型的输出作为 SAM 的输入,从而实现高效的目标检测与分割。在接下来的内容中,我们将详细阐述如何将 YOLO 与 SAM 结合,以实现这一目标。

YOLOv8 目标检测

在正式展开本文内容之前,若对如何从零开始训练自定义的 YOLO 模型抱有兴趣,不妨参考我过往撰写的一篇文章《YOLOV8目标识别——详细记录从环境配置、自定义数据、模型训练到模型推理部署》。不过,在本文中,为了便于快速上手和聚焦于核心问题,我将直接调用预训练好的 yolov8n.pt 模型。若您选择采用这一预训练模型,仅需运行以下代码,系统便会自动为您完成模型的下载工作。

conda create -n yolo_sam python==3.10
conda activate yolo_sam
pip install ultralytics
from ultralytics import YOLO# 加载模型
model = YOLO("yolov8n.pt")  # 预训练的 YOLOv8n 模型# 对一系列图像进行批量推理
results = model([r"ball.jpg"])  # 返回一个 Results 对象列表# 处理结果列表
for result in results:boxes = result.boxes  # 用于边界框输出的 Boxes 对象masks = result.masks  # 用于分割掩码输出的 Masks 对象keypoints = result.keypoints  # 用于姿态输出的 Keypoints 对象probs = result.probs  # 用于分类输出的 Probs 对象obb = result.obb  # 用于 OBB 输出的 Oriented boxes 对象result.show()  # 显示到屏幕result.save(filename="result.jpg")  # 保存到磁盘

检测 + 分割与 SAM

在开始之前,你需要下载 SAM 模型。你可以从 Hugging Face 下载它(链接)。

1. 安装必要的库

pip install git+https://github.com/facebookresearch/segment-anything.git
pip install opencv-python mediapipe ultralytics numpy torch matplotlib

2. 导入库

import torch
import cv2
import numpy as np
import matplotlib.pyplot as plt
from ultralytics import YOLO
from segment_anything import sam_model_registry, SamPredictor

3. 加载模型

# 加载 YOLO 模型
model = YOLO("yolov8n.pt") # 加载 SAM 模型
sam_checkpoint = "sam_vit_b_01ec64.pth"  # 替换为你的模型路径
model_type = "vit_b"
device = "cuda" if torch.cuda.is_available() else "cpu"
print(device)sam = sam_model_registry[model_type](checkpoint=sam_checkpoint)
sam.to(device=device)
predictor = SamPredictor(sam)

4. 检测 + 分割

# 加载图像
image_path = r"ball.jpg"
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # 转换为 RGB 格式以供 SAM 使用# 运行 YOLO 推理
results = model(image, conf=0.3)# 遍历检测结果
for result in results:# 获取边界框for box, cls in zip(result.boxes.xyxy, result.boxes.cls):   x1, y1, x2, y2 = map(int, box)  # 转换为整数# 获取 IDclass_id = int(cls)  # 类别 ID# 获取类别标签class_label = model.names[class_id]   # 准备 SAMpredictor.set_image(image_rgb)# 定义一个边界框提示供 SAM 使用input_box = np.array([[x1, y1, x2, y2]])# 获取 SAM 掩码masks, _, _ = predictor.predict(box=input_box, multimask_output=False)# 创建原始图像的副本以叠加掩码highlighted_image = image_rgb.copy()# 将掩码以半透明蓝色应用于图像mask = masks[0]# 创建一个空白图像blue_overlay = np.zeros_like(image_rgb, dtype=np.uint8)  # 蓝色用于分割区域(RGB)blue_overlay[mask == 1] = [0, 0, 255]   # 使用透明度将蓝色叠加层与原始图像混合alpha = 0.7  # 叠加层的透明度highlighted_image = cv2.addWeighted(highlighted_image, 1 - alpha, blue_overlay, alpha, 0)# 在边界框上方添加标签(类别名称)font = cv2.FONT_HERSHEY_SIMPLEXlabel = f"{class_label}"  # 标签为类别名称cv2.putText(highlighted_image, label, (x1, y1 - 10), font, 2, (255, 255, 0), 2, cv2.LINE_AA)   # 可选:保存带有边界框和突出显示的分割结果的图像output_filename = f"highlighted_output.png"cv2.imwrite(output_filename, cv2.cvtColor(highlighted_image, cv2.COLOR_RGB2BGR))

交互加分割

使用 OpenCV 鼠标事件来画框交互,并将框的坐标传入 SAM 进行分割,是一种非常直观且灵活的方法。

1. 代码实现

import cv2
import numpy as np
import torch
from segment_anything import sam_model_registry, SamPredictor# 初始化全局变量
start_point = None
end_point = None
drawing = False# 鼠标回调函数
def draw_rectangle(event, x, y, flags, param):global start_point, end_point, drawingif event == cv2.EVENT_LBUTTONDOWN:start_point = (x, y)drawing = Trueelif event == cv2.EVENT_MOUSEMOVE:if drawing:end_point = (x, y)elif event == cv2.EVENT_LBUTTONUP:drawing = Falseend_point = (x, y)cv2.rectangle(image, start_point, end_point, (0, 255, 0), 2)cv2.imshow("Image", image)# 加载 SAM 模型
sam_checkpoint = "sam_vit_b_01ec64.pth"  # 替换为你的模型路径
model_type = "vit_b"
device = "cuda" if torch.cuda.is_available() else "cpu"sam = sam_model_registry[model_type](checkpoint=sam_checkpoint)
sam.to(device=device)
predictor = SamPredictor(sam)# 加载图像
image_path = "example.jpg"
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # 转换为 RGB 格式# 创建窗口并绑定鼠标回调函数
cv2.namedWindow("Image")
cv2.setMouseCallback("Image", draw_rectangle)while True:cv2.imshow("Image", image)if cv2.waitKey(1) & 0xFF == ord('q'):break# 如果框已经画好,进行分割if start_point and end_point:# 转换为 SAM 需要的边界框格式input_box = np.array([start_point[0], start_point[1], end_point[0], end_point[1]])input_box = np.array([min(input_box[0], input_box[2]), min(input_box[1], input_box[3]),max(input_box[0], input_box[2]), max(input_box[1], input_box[3])])# 生成分割掩码predictor.set_image(image_rgb)masks, _, _ = predictor.predict(box=input_box, multimask_output=False)# 显示分割结果highlighted_image = image_rgb.copy()mask = masks[0]blue_overlay = np.zeros_like(image_rgb, dtype=np.uint8)blue_overlay[mask == 1] = [0, 0, 255]  # 蓝色掩码highlighted_image = cv2.addWeighted(highlighted_image, 1, blue_overlay, 0.7, 0)cv2.imshow("Segmented Image", cv2.cvtColor(highlighted_image, cv2.COLOR_RGB2BGR))cv2.waitKey(0)cv2.destroyAllWindows()breakcv2.destroyAllWindows()

实现效果:
在这里插入图片描述### 2. 代码说明

  1. 全局变量

    • start_pointend_point 用于记录鼠标点击和释放时的坐标。
    • drawing 用于标记是否正在绘制矩形。
  2. 鼠标回调函数

    • draw_rectangle 函数用于处理鼠标事件,包括按下、移动和释放。
    • 当鼠标按下时,记录起始点。
    • 当鼠标移动时,更新终点。
    • 当鼠标释放时,绘制矩形并更新图像。
  3. 加载 SAM 模型

    • 使用 sam_model_registry 加载预训练的 SAM 模型。
    • 将模型移动到 GPU(如果可用)。
  4. 加载图像

    • 使用 OpenCV 读取图像,并将其转换为 RGB 格式以供 SAM 使用。
  5. 创建窗口并绑定鼠标回调

    • 使用 cv2.namedWindow 创建窗口。
    • 使用 cv2.setMouseCallback 绑定鼠标回调函数。
  6. 主循环

    • 显示图像并等待用户操作。
    • 如果用户绘制了矩形,将矩形的坐标转换为 SAM 需要的格式,并调用 SAM 进行分割。
    • 显示分割结果。

3. 运行效果

  1. 绘制矩形

    • 运行程序后,使用鼠标在图像上绘制一个矩形框,表示需要分割的目标区域。
  2. 显示分割结果

    • 按下 q 键后,程序会根据绘制的矩形框调用 SAM 进行分割,并显示分割结果。

4. 注意事项

  • 图像路径:确保 image_path 指向正确的图像文件。
  • 模型路径:确保 sam_checkpoint 指向正确的 SAM 模型文件。
  • 环境依赖:确保安装了必要的依赖库,如 opencv-pythontorchsegment_anything

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

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

相关文章

在Flutter中使用BottomNavigationBar和IndexedStack可以实现一个功能完整的底部导航栏

在Flutter中,使用BottomNavigationBar和IndexedStack可以实现一个功能完整的底部导航栏。BottomNavigationBar用于显示底部的导航按钮,而IndexedStack则用于管理页面的切换,确保每个页面的状态得以保留(即页面不会因为切换而重新构…

【10】数据结构的矩阵与广义表篇章

目录标题 二维以上矩阵矩阵存储方式行序优先存储列序优先存储 特殊矩阵对称矩阵稀疏矩阵三元组方式存储稀疏矩阵的实现三元组初始化稀疏矩阵的初始化稀疏矩阵的创建展示当前稀疏矩阵稀疏矩阵的转置 三元组稀疏矩阵的调试与总代码十字链表方式存储稀疏矩阵的实现十字链表数据标签…

微服务篇——SpringCloud

服务注册 Spring Cloud5大组件有哪些? 服务注册和发现是什么意思?Spring Cloud如何实现服务注册发现? nacos与eureka的区别 负载均衡 如何实现负载均衡? Ribbon负载均衡的策略有哪些? 如何自定义负载均衡的策略&…

【小沐杂货铺】基于Three.JS绘制三维数字地球Earth(GIS 、WebGL、vue、react,提供全部源代码)

🍺三维数字地球系列相关文章如下🍺:1【小沐学GIS】基于C绘制三维数字地球Earth(456:OpenGL、glfw、glut)第一期2【小沐学GIS】基于C绘制三维数字地球Earth(456:OpenGL、glfw、glut)第二期3【小沐…

Cursor 在前端需求开发工作流中的应用|得物技术

一、引言 很高兴与大家分享现阶段 Cursor 在我的工作中的使用体验。首先是预期管理,本篇文章不会分享 x 个你可能不知道的小技巧,也不会让你拥有无需自行编码的能力,同时不涉及 Cursor 工程化方面内容。仅仅是围绕个人开发流程中的已有问题&…

PyQt学习记录

PyQt学习记录 要在界面上 创建一个控件,就需要在程序代码中 创建 这个 控件对应类 地一个 实例对象。 在Qt系统中,控件(widget)是 层层嵌套 的,除了最顶层的控件,其他的控件都有父控件。 几个函数 函数mo…

react: styled-components实现原理 标签模版

styled-components是针对react中一个前端广泛使用的css-in-js样式库B站 利用标签模版 利用ES6中的 标签模版文档标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。 let a 5; let b 10;…

网络安全应急响应之文件痕迹排查:从犯罪现场到数字狩猎的进化论

凌晨3点,某金融企业的服务器突然告警,核心数据库出现未知进程访问。安全团队紧急介入时,攻击者已抹去日志痕迹。在这场与黑客的时间赛跑中,文件痕迹排查成为破局关键。本文将带您深入数字取证的"案发现场",揭…

多模态大语言模型arxiv论文略读(七)

MLLM-DataEngine: An Iterative Refinement Approach for MLLM ➡️ 论文标题:MLLM-DataEngine: An Iterative Refinement Approach for MLLM ➡️ 论文作者:Zhiyuan Zhao, Linke Ouyang, Bin Wang, Siyuan Huang, Pan Zhang, Xiaoyi Dong, Jiaqi Wang,…

idea插件:AICommit,智能生成Git提交信息

AICommit:智能生成Git提交信息的IDEA插件指南 一、AICommit插件介绍 AICommit是一款专为开发者设计的IntelliJ IDEA插件,它利用人工智能技术自动生成清晰、规范的Git提交信息(Commit Message)。该插件能够分析你的代码变更,理解修改的上下文…

js 拷贝-包含处理循环引用问题

在 JavaScript 中,拷贝对象和数组时需要特别注意,因为对象和数组是引用类型,直接赋值只会复制引用,而不是实际的数据。以下是几种常见的拷贝方法及其应用场景: 1. 浅拷贝(Shallow Copy) 浅拷贝…

oracle将varchar2 转为clob类型存储。 oracle不支持直接使用sql,将 varchar2 到clob的类型转换,需要下面操作

将一个现有表中的 VARCHAR2 列数据迁移到一个 CLOB 列的过程。以下是对每一步操作的说明: 1. 添加一个新的 CLOB 类型列 首先,向表中添加一个新的 CLOB 类型的列。这个列将用来存储原本的 VARCHAR2 数据。 ALTER TABLE your_table ADD (new_column CL…

Dynamics 365 Business Central Recurring Sales Lines 经常购买销售行 来作 订阅

#D365 BC ERP# #Navision# 前面有节文章专门介绍了BC 2024 Wave 2 支持的更好的Substription & Recurring Billing。 其实在D365 BC ERP中一直有一个比较简单的订阅模块Recrring Sales Lines。本文将介绍一下如何用Recurring Sales Lines来 实施简易的订阅Substription。具…

算法比赛中常用的数学知识

一、求某个整数的正约数个数与正约数之和 1.1求某个正整数N的正约数个数 public class Main {public static void main(String[] args) {System.out.println(count(360));//结果为24}public static long count(long number){long count1;for(long i2;i<Math.sqrt(number);…

虚拟Ubuntu系统 开机提示:SMBus Host controller not enabled 后正常启动,去除这个提示提升开机速度。

如题&#xff0c;虚拟机中的Ubuntu系统开机提示&#xff1a;SMBus Host controller not enabled&#xff0c;虽然能正常启动&#xff0c;但不仅影响开机速度&#xff0c;而且还膈应人。 使用命令查看模块 lsmod | grep piix4 发现i2c_piix4有问题&#xff0c; 禁止 i2c_piix4…

NLP基础知识 与 词向量的转化方法 发展

目录 1.NLP 基础知识点 为什么需要自然语言处理? 自然语言处理有哪些分类? 自然语言处理有哪些实际应用? 为什么需要自然语言处理? 自然语言处理有哪些分类? 自然语言处理有哪些实际应用? 自然语言处理的技术/工作原理是什么? 2.NLP文本转化为词向量的方法 2…

【FPGA基础学习】状态机思想实现流水灯

目录 一、用状态机实现LED流水灯1.状态机思想简介1. 1基本概念1.2.核心要素1.3分类与模型 2.LED流水灯 二、CPLD与FPGA1.技术区别2.应用场景3.设计选择建议 三、HDLbits组合逻辑题目 一、用状态机实现LED流水灯 1.状态机思想简介 1. 1基本概念 ​ 状态机&#xff08;Finite …

CSS语言的游戏AI

CSS语言的游戏AI探讨 随着技术的飞速发展&#xff0c;游戏行业也在不断地革命和演变。游戏中的人工智能&#xff08;AI&#xff09;作为一种重要的设计元素&#xff0c;其复杂性和智能程度对游戏的体验、玩法和整体表现都有着深远的影响。近年来&#xff0c;CSS&#xff08;Ca…

docker配置redis容器时配置文件docker-compose.yml示例

1.配置数据节点&#xff08;主从节点&#xff09; version: 3.7 services:master:image: redis:5.0.9container_name: redis-masterrestart: alwayscommand: redis-server --appendonly yesports:- 6379:6379slave1:image: redis:5.0.9container_name: redis-slave1restart: a…

【WPF】IOC控制反转的应用:弹窗但不互相调用ViewModel

全称&#xff1a;Inversion of Control&#xff0c;控制反转 场景&#xff1a;A页面需要调用B/C页面等&#xff0c;防止直接在VM中新建别的页面实例&#xff0c;使用IOC设计架构&#xff1b; 创建Service&#xff0c;在Service中实现页面的实例创建和定义页面输入输出参数。 在…