yolov8-seg 分割推理流程

本文详细介绍了使用TensorRT对YOLOv8进行图像检测的推理流程,包括图像预处理(如padding、通道转换和归一化),PyTorch推理,以及后处理(NMS、mask生成和裁剪)和可视化。展示了完整PyTorch代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、分割+检测

二、图像预处理

二、推理

三、后处理与可视化

3.1、后处理

3.2、mask可视化

四、完整pytorch代码


一、分割+检测

注:本篇只是阐述推理流程,tensorrt实现后续跟进。

yolov8-pose的tensorrt部署代码稍后更新,还是在仓库:GitHub - FeiYull/TensorRT-Alpha: 🔥🔥🔥TensorRT-Alpha supports YOLOv8、YOLOv7、YOLOv6、YOLOv5、YOLOv4、v3、YOLOX、YOLOR...🚀🚀🚀CUDA IS ALL YOU NEED.🍎🍎🍎It also supports end2end CUDA C acceleration and multi-batch inference.

也可以关注:TensorRT系列教程-CSDN博客

以下是官方预测代码:

from ultralytics import YOLO
model = YOLO(model='yolov8n-pose.pt')
model.predict(source="d:/Data/1.jpg", save=True)

推理过程无非是:图像预处理 -> 推理 -> 后处理 + 可视化,这三个关键步骤在文件大概247行:D:\CodePython\ultralytics\ultralytics\engine\predictor.py,代码如下:

# Preprocess
with profilers[0]:
	im = self.preprocess(im0s) # 图像预处理

# Inference
with profilers[1]:
	preds = self.inference(im, *args, **kwargs) # 推理

# Postprocess
with profilers[2]:
	self.results = self.postprocess(preds, im, im0s) # 后处理

二、图像预处理

通过debug,进入上述self.preprocess函数,看到代码实现如下。处理流程大概是:padding(满足矩形推理),图像通道转换,即:BGR装RGB,检查图像数据是否连续,存储顺序有HWC转为CHW,然后归一化。需要注意,原始pytorch框架图像预处理的时候,会将图像缩放+padding为HxW的图像,其中H、W为32倍数,而导出tensorrt的时候,为了高效推理,H、W 固定为640x640。

def preprocess(self, im):
	"""Prepares input image before inference.

	Args:
		im (torch.Tensor | List(np.ndarray)): BCHW for tensor, [(HWC) x B] for list.
	"""
	not_tensor = not isinstance(im, torch.Tensor)
	if not_tensor:
		im = np.stack(self.pre_transform(im))
		im = im[..., ::-1].transpose((0, 3, 1, 2))  # BGR to RGB, BHWC to BCHW, (n, 3, h, w)
		im = np.ascontiguousarray(im)  # contiguous
		im = torch.from_numpy(im)

	img = im.to(self.device)
	img = img.half() if self.model.fp16 else img.float()  # uint8 to fp16/32
	if not_tensor:
		img /= 255  # 0 - 255 to 0.0 - 1.0
	return img

二、推理

图像预处理之后,直接推理就行了,这里是基于pytorch推理。

def inference(self, im, *args, **kwargs):
	visualize = increment_path(self.save_dir / Path(self.batch[0][0]).stem,
							   mkdir=True) if self.args.visualize and (not self.source_type.tensor) else False
	return self.model(im, augment=self.args.augment, visualize=visualize)

三、后处理与可视化

3.1、后处理

640x640输入之后,有两个输出,其中

  • output1:尺寸为:116X8400,其中116=4+80+32,32为seg部分特征,经过NMS之后,输出为:N*38,其中38=4 + 2 + 32
  • output2:尺寸为32x160x160,拿上面NMS后的特征图后面,即:N*38矩阵后面部分N*32的特征图和output2作矩阵乘法,得到N*160*160的矩阵,接着执行sigmiod,然后拉平得到N*160*160 的mask。

然后将bbox缩放160*160的坐标系,如下代码,用于截断越界的mask,就是如下函数。最后,将所有mask上采样到640*640,然后用阀值0.5过一下。最后mask中只有0和1了,结束。

有关def crop_mask(masks, boxes):的理解:

def crop_mask(masks, boxes):
    """
    It takes a mask and a bounding box, and returns a mask that is cropped to the bounding box

    Args:
      masks (torch.Tensor): [n, h, w] tensor of masks
      boxes (torch.Tensor): [n, 4] tensor of bbox coordinates in relative point form

    Returns:
      (torch.Tensor): The masks are being cropped to the bounding box.
    """
    n, h, w = masks.shape
    x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1)  # x1 shape(n,1,1)
    r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :]  # rows shape(1,1,w)
    c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None]  # cols shape(1,h,1)

    return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))

上面代码最后一句return,如下图理解,mask中所有点,例如点(r,c)必须在bbox内部。做法就是将bbox缩放到和mask一样的坐标系(160x160)如下图,然后使用绿色的bbox将mask进行截断:

3.2、mask可视化

直接将mask从灰度图转为彩色图,然后将类别对应的颜色乘以0.4,最后加在彩色图上就行了。

四、完整pytorch代码

将以上流程合并起来,并加以修改,完整代码如下:

import torch
import cv2 as cv
import numpy as np
from ultralytics.data.augment import LetterBox
from ultralytics.utils import ops
from ultralytics.engine.results import Results
import copy

# path = 'd:/Data/1.jpg'
path = 'd:/Data/640640.jpg'
device = 'cuda:0'
conf = 0.25
iou = 0.7

# preprocess
im = cv.imread(path)
# letterbox
im = [im]
orig_imgs = copy.deepcopy(im)
im = [LetterBox([640, 640], auto=True, stride=32)(image=x) for x in im]
im = im[0][None] # im = np.stack(im)
im = im[..., ::-1].transpose((0, 3, 1, 2))  # BGR to RGB, BHWC to BCHW, (n, 3, h, w)
im = np.ascontiguousarray(im)  # contiguous
im = torch.from_numpy(im)
img = im.to(device)
img = img.float()
img /= 255
# load model pt
ckpt = torch.load('yolov8n-seg.pt', map_location='cpu')
model = ckpt['model'].to(device).float()  # FP32 model
model.eval()

# inference
preds = model(img)

# poseprocess
p = ops.non_max_suppression(preds[0], conf, iou, agnostic=False, max_det=300, nc=80, classes=None)
results = []
# 如果导出onnx,第二个输出维度是1,应该就是mask,需要后续上采样
proto = preds[1][-1] if len(preds[1]) == 3 else preds[1]  # second output is len 3 if pt, but only 1 if exported???????
for i, pred in enumerate(p):
    orig_img = orig_imgs[i]
    if not len(pred):  # save empty boxes
        results.append(Results(orig_img=orig_img, path=path, names=model.names, boxes=pred[:, :6]))
        continue
    masks = ops.process_mask(proto[i], pred[:, 6:], pred[:, :4], img.shape[2:], upsample=True)  # HWC
    if not isinstance(orig_imgs, torch.Tensor):
        pred[:, :4] = ops.scale_boxes(img.shape[2:], pred[:, :4], orig_img.shape)
    results.append(Results(orig_img=orig_img, path=path, names=model.names, boxes=pred[:, :6], masks=masks))

# show
plot_args = {'line_width': None,'boxes': True,'conf': True, 'labels': True}
plot_args['im_gpu'] = img[0]
result = results[0]
plotted_img = result.plot(**plot_args)
cv.imshow('plotted_img', plotted_img)
cv.waitKey(0)
cv.destroyAllWindows()

### YOLOv8-Seg 分割模型概述 YOLOv8-Seg 是基于 YOLOv8 的实例分割扩展版本,继承了 YOLOv8 在目标检测方面的高效性和灵活性,并针对语义分割和实例分割任务进行了优化。其核心设计思路是在保持高性能的同时降低计算复杂度,从而实现更高效的推理速度和更高的精度。 #### 主要特点 - **Backbone 改进**: 使用 CSP (Cross Stage Partial Network) 思想构建网络骨架[^1]。相比传统的 C3 模块,YOLOv8 中引入了更加轻量化的 C2f 模块,减少了参数数量并提升了运行效率。 - **Neck 设计**: PAN-FPN (Path Aggregation Network with Feature Pyramid Network) 被继续沿用,但在结构上有所简化。具体来说,去掉了上采样阶段中的冗余卷积层,并将原有的 C3 模块替换为 C2f 模块,进一步降低了计算开销[^1]。 - **头部解耦 (Decoupled Head)**: 不同于之前的共享权重设计,YOLOv8 采用了分离式的预测头,分别负责不同类型的输出(如分类、边界框回归以及掩码生成)。这种设计有助于提升各分支的独立性,进而提高整体性能。 - **无锚点机制 (Anchor-Free)**: 抛弃了传统的目标检测方法中依赖预定义锚框的设计,转而采用动态分配策略来确定候选区域的位置和大小。这种方式不仅简化了训练过程,还提高了模型对于小物体检测的能力。 - **新型损失函数**: VFL (Varifocal Loss) 被用于衡量分类置信度误差;而对于位置估计,则结合 DFL (Distributed Focal Loss) 和 CIoU Loss 来共同指导学习过程[^1]。 - **样本匹配方式更新**: Task-Aligned Assigner 替代了旧版 IOU 或双边比例分配方案,在正负样本划分方面表现出更强适应能力。 --- ### 功能介绍 YOLOv8-Seg 提供了一套完整的解决方案,支持从数据准备到最终部署全流程操作: 1. **数据配置文件**: 类似于 `coco128-seg.yaml` 这样的 YAML 文件可以用来描述特定应用场景下的标注信息格式及其存储路径等细节[^2]。这使得开发者能够轻松定制自己的项目需求。 2. **预训练模型加载**: 利用官方提供的初始权重文件(例如 `yolov5s-seg.pt`),用户可以直接启动微调流程或将这些权值迁移到其他相关领域当中[^2]。 3. **命令行工具集成**: 提供简单易用的 Python 命令接口完成各项基本任务,比如执行单张图片测试可以通过如下指令实现: ```bash python detect.py --task segment --weights yolov5s-seg.pt --source image.jpg ``` 4. **后处理逻辑封装**: 对原始输出结果进行必要的转换处理以便直观展示给终端使用者查看效果如何。 --- ### 示例代码片段 以下是利用 YOLOv8-Seg 执行图像分割的一个典型例子: ```python from ultralytics import YOLO model = YOLO('yolov8n-seg.pt') # 加载预训练模型 results = model.predict(source='image.jpg', save=True, show_labels=False) for result in results: boxes = result.boxes.cpu().numpy() # 获取边界框坐标 masks = result.masks.data.cpu().numpy() # 获取像素级掩膜矩阵 ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄家驹beyond

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值