YOLOv8 实例分割详解

一、引言

实例分割(Instance Segmentation)是计算机视觉中的一项关键任务,它不仅可以检测物体的位置,还能为每个目标生成精确的像素级掩码。YOLOv8 在目标检测的基础上,新增了实例分割(segmentation)功能,使得该模型可以高效地进行语义分割和目标分割任务。本文将详细介绍如何使用 YOLOv8 进行实例分割,包括数据准备、模型训练、推理、评估及优化等内容。


二、YOLOv8 实例分割简介

YOLOv8 的实例分割版本采用了基于掩码(Mask-Based)的分割方法,结合目标检测的能力,预测每个目标的精确轮廓。它的主要特性如下:

  • 端到端训练:只需提供标注数据,即可训练分割模型。
  • 高效推理:支持实时推理,适用于资源受限的设备。
  • 灵活部署:支持PyTorch、ONNX、TensorRT、OpenVINO 等多种格式导出和部署。

三、环境配置

在开始实例分割之前,确保你的环境满足以下要求:

1. 硬件要求

  • 操作系统:Windows 10 / Linux
  • GPU:NVIDIA 计算能力 6.1 以上(推荐)
  • CUDA 版本:11.6 及以上
  • 内存:16GB 及以上

2. 软件依赖

安装 PyTorch 和 YOLOv8:

pip install ultralytics

如果需要 GPU 训练,请安装 PyTorch 适用于 CUDA 的版本:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu116

检查 YOLOv8 是否安装成功:

yolo --version

四、数据准备

YOLOv8 需要的数据格式与目标检测类似,但要增加分割掩码(mask)信息。

1. 数据集格式

YOLOv8 支持COCO格式YOLO格式的分割数据。以下是 YOLO 格式的示例:

datasets/custom_segmentation/
├── images/
│   ├── train/
│   ├── valid/
│   ├── test/
├── labels/
│   ├── train/
│   ├── valid/
│   ├── test/
├── dataset.yaml

每个 labels 目录中的 .txt 文件包含。

<class_id> <x1,y1,x2,y2,x3,y3,...> <confidence>

其中,<x1,y1> 是目标的掩码点坐标,适用于多边形分割

我先通过lableme手动标注实例分割数据集,生成json文件。将json文件转换成txt文件,自行写一个脚本即可,以下附带我所写的脚本:

# -*- coding: gbk -*-
import os
import json
import cv2

def convert_labelme_json_to_yolov8_txt(root_json_dir, img_dir, output_dir):
    """
    将 Labelme 标注生成的 JSON 文件转换为适用于 YOLOv8 实例分割的 TXT 文件。

    :param root_json_dir: 包含 JSON 文件的根目录,支持子文件夹
    :param img_dir: 图像文件所在的目录
    :param output_dir: 转换后的 TXT 文件保存的目录
    """
    # 全局的类别映射
    global_class_mapping = {}

    # 处理 train 和 valid 子文件夹
    for sub_dir in ['train', 'valid']:
        sub_json_dir = os.path.join(root_json_dir, sub_dir)
        sub_img_dir = os.path.join(img_dir, sub_dir)
        sub_output_dir = os.path.join(output_dir, sub_dir)

        # 确保输出子目录存在,如果不存在则创建
        if not os.path.exists(sub_output_dir):
            os.makedirs(sub_output_dir)

        # 递归遍历子 JSON 目录及其子文件夹
        for root, _, files in os.walk(sub_json_dir):
            for json_file in files:
                if json_file.endswith('.json'):
                    # 构建 JSON 文件的完整路径
                    json_path = os.path.join(root, json_file)
                    try:
                        # 读取 JSON 文件
                        with open(json_path, 'r', encoding='utf-8') as f:
                            data = json.load(f)
                    except Exception as e:
                        print(f"Failed to load {json_path}: {e}")
                        continue

                    # 获取图像文件名
                    img_name = data.get('imagePath')
                    if not img_name:
                        print(f"Missing 'imagePath' in {json_path}, skipping...")
                        continue

                    # 处理路径分隔符
                    img_name = img_name.replace('\\', '/')
                    # 规范化路径
                    img_name = os.path.normpath(img_name)

                    # 提取文件名
                    img_filename = os.path.basename(img_name)

                    # 尝试直接使用 img_name 构建路径
                    img_path = os.path.join(sub_img_dir, img_name)
                    if not os.path.exists(img_path):
                        # 如果直接构建的路径不存在,使用文件名构建路径
                        img_path = os.path.join(sub_img_dir, img_filename)

                    if not os.path.exists(img_path):
                        print(f"Image file does not exist: {img_path}")
                        continue

                    try:
                        # 读取图像以获取尺寸
                        img = cv2.imread(img_path)
                        if img is None:
                            print(f"Failed to read image: {img_path}")
                            continue
                        img_height, img_width, _ = img.shape
                    except Exception as e:
                        print(f"Error reading image {img_path}: {e}")
                        continue

                    # 准备输出的 TXT 文件路径
                    txt_file = os.path.splitext(img_filename)[0] + '.txt'
                    txt_path = os.path.join(sub_output_dir, txt_file)

                    try:
                        # 打开 TXT 文件以写入
                        with open(txt_path, 'w', encoding='utf-8') as txt_f:
                            for shape in data.get('shapes', []):
                                label = shape['label']
                                # 如果类别名称不在全局映射中,添加新的映射
                                if label not in global_class_mapping:
                                    global_class_mapping[label] = len(global_class_mapping)
                                class_index = global_class_mapping[label]
                                points = shape['points']

                                # 归一化多边形点坐标
                                normalized_points = []
                                for point in points:
                                    x = point[0] / img_width
                                    y = point[1] / img_height
                                    # 确保归一化后的坐标在 [0, 1] 范围内
                                    x = max(0, min(1, x))
                                    y = max(0, min(1, y))
                                    normalized_points.extend([x, y])

                                # 写入一行标注信息
                                line = [str(class_index)] + [str(round(coord, 6)) for coord in normalized_points]
                                txt_f.write(' '.join(line) + '\n')
                        print(f"Converted {json_path} to {txt_path}")
                    except Exception as e:
                        print(f"Error writing to {txt_path}: {e}")

    # 打印类别映射
    print("类别映射:")
    for label, index in global_class_mapping.items():
        print(f"{label}: {index}")

# 示例使用
root_json_dir = '/data/mask.json/'  # 假设 JSON 文件存放在这个目录下,包含 train 和 valid 子文件夹
img_dir = '/data/images'  # 图像文件所在目录,包含 train 和 valid 子文件夹
output_dir = '/data/labels1/'  # 输出 TXT 文件的目录,会自动创建 train 和 valid 子文件夹
convert_labelme_json_to_yolov8_txt(root_json_dir, img_dir, output_dir)

2. 数据标注

可以使用LabelMe、Roboflow、CVAT等标注工具来生成分割数据集。

3. 数据集配置

dataset.yaml 文件中定义数据集路径:

path: datasets/custom_segmentation
train: images/train
val: images/valid
test: images/test
nc: 2  # 类别数
names: ['car', 'person']

五、训练 YOLOv8 实例分割模型

YOLOv8 提供了 task=segment 模式来进行实例分割训练。

1. 训练命令

yolo task=segment mode=train model=yolov8s-seg.pt data=dataset.yaml epochs=50 imgsz=640 batch=16 device=0

2. 训练参数

参数说明
task=segment指定实例分割任务
mode=train训练模式
model=yolov8s-seg.pt预训练模型
data=dataset.yaml数据集配置文件
epochs=50训练轮数
imgsz=640训练图片尺寸
batch=16批量大小
device=0使用 GPU 训练

3. 训练过程

训练过程中,YOLOv8 会输出每个 Epoch 的损失值和评估指标,如 mAP@50mAP@50:95

4. 训练结果

训练完成后,模型会保存在 runs/segment/train/weights/best.pt和 runs/segment/train/weights/last.pt


六、模型推理

训练完成后,我们可以使用 predict 模式对新图像进行实例分割推理。

1. 运行推理

yolo task=segment mode=predict model=runs/segment/train/weights/best.pt source=images/test/ save=True

推理结果将自动保存在 runs/segment/predict/ 目录下。

2. 可视化分割结果

可以使用 Matplotlib 读取并展示结果:

import cv2
import matplotlib.pyplot as plt

image = cv2.imread("runs/segment/predict/image.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

plt.imshow(image)
plt.axis("off")
plt.show()


七、模型评估

训练完成后,我们需要对模型进行评估,以判断其泛化能力和分割效果。

1. 评估指标

  • mAP(Mean Average Precision):衡量检测和分割的准确度
  • IoU(Intersection over Union):衡量分割掩码的精度
  • Precision / Recall:评估分类性能

2. 运行验证

yolo task=segment mode=val model=runs/segment/train/weights/best.pt data=dataset.yaml

输出示例:

mAP@50: 85.2%
mAP@50:95: 67.8%
IoU: 75.4%

八、模型优化

如果模型的分割效果不够理想,我们可以采用以下优化方法:

1. 增加训练数据

  • 扩展数据集,加入更多不同场景的样本
  • 使用数据增强,如翻转、裁剪、颜色变换等

2. 训练更大模型

尝试使用 yolov8m-seg.ptyolov8l-seg.pt

yolo task=segment mode=train model=yolov8m-seg.pt data=dataset.yaml epochs=100 imgsz=640 batch=32 device=0

3. 量化和剪枝

如果需要加速推理,可以采用量化剪枝技术:

yolo task=segment mode=export model=best.pt format=onnx simplify=True

九、总结

本文详细介绍了如何使用 YOLOv8 进行实例分割,包括:

  1. 数据准备:如何整理数据集并进行标注
  2. 模型训练:使用 YOLOv8 进行实例分割训练
  3. 模型推理:如何使用训练好的模型进行分割
  4. 模型评估:计算 mAP、IoU 及其他指标
  5. 模型优化:提高分割效果的方法

YOLOv8 使得实例分割任务变得更加简单和高效,适用于自动驾驶、医学图像分析、安防监控等多个领域。🚀🚀🚀


感谢大家点赞评论关注!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值