YOLO11实例分割训练任务——从构建数据集到训练的完整教程

一、YOLO11分割数据集的核心特性

实例分割的核心是"既要识别目标类别,又要勾勒目标轮廓",这决定了YOLO11分割数据集与传统检测数据集的本质区别。在动手构建前,必须先明确其核心定义和格式规范。

1.1 分割数据集与检测数据集的核心差异

目标检测数据集仅需标注目标的边界框(x,y,w,h),而分割数据集在此基础上,还需要用像素级的掩码(Mask)精准描述目标的形状。形象地说,检测是"给目标画框",分割是"给目标涂色"。这种差异使得分割数据集能为YOLO11提供更细粒度的特征信息,支撑模型学习物体的边缘细节。

YOLO11之所以能高效处理分割任务,得益于其架构改进:引入BiFormer注意力机制捕捉边界特征,增强的C2PSA模块实现跨尺度像素建模,再配合CBAM通道-空间双重注意力,让模型能精准区分目标与背景。而这些能力的发挥,完全依赖于数据集提供的精准轮廓标注。

1.2 YOLO11分割数据集的标准格式

YOLO11采用"图像+文本标注"的轻量格式,无需复杂的二进制文件,每个图像对应一个同名的.txt标注文件,同时可搭配可选的掩码图像用于可视化。核心格式规范如下:

标注文件格式(归一化坐标):每一行代表一个目标实例,格式为 [class_id] [x_center] [y_center] [width] [height] [segmentation_points...]

各参数说明:

  • class_id:目标类别编号(从0开始,如0代表行人、1代表汽车)

  • x_center/y_center:目标轮廓中心点的x/y坐标(相对于图像宽度/高度归一化,范围0-1)

  • width/height:目标边界框的宽/高(同样归一化)

  • segmentation_points:轮廓点坐标对,格式为x1 y1 x2 y2 ... xn yn(所有坐标均归一化,点数越多轮廓越精准)

示例:一张包含"行人"(class_id=0)的图像,其标注可能为: 0 0.45 0.62 0.38 0.75 0.32 0.41 0.35 0.28 0.48 0.22 0.61 0.25 0.65 0.43 0.62 0.68 0.48 0.78 0.35 0.75

二、数据集准备

数据集质量直接决定模型性能,低质量数据(如标注模糊、场景单一)会导致模型泛化能力差。以下流程从数据采集到预处理,全程保障数据质量。

2.1 数据采集

分割任务对数据多样性要求极高,需覆盖实际应用中可能遇到的各种场景。核心原则是"全面性、代表性、无冗余"。

(1)数据来源渠道
  • 公开数据集复用:优先使用成熟数据集的标注逻辑,如COCO(通用场景)、Cityscapes(城市场景)、Mask R-CNN官方数据集,可直接提取其中的分割标注并适配YOLO11格式。

  • 实地采集:针对特定场景(如工厂巡检、农业病虫害识别),需自行拍摄。建议使用高清相机,按"多角度、多光照、多遮挡"原则采集------例如识别货架商品时,需包含正面、侧面、堆叠、被遮挡等多种状态。

  • 视频抽帧:从监控视频中按固定间隔(如30帧抽1帧)提取图像,适合动态场景数据积累。可使用OpenCV实现自动化抽帧,代码示例如下:

python 复制代码
import os
import cv2
​
def video_to_frames(video_path, output_dir, interval=30):
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    cap = cv2.VideoCapture(video_path)
    frame_count = 0  # 视频总帧数
    save_count = 0   # 保存的帧数
    
    while True:
        ret, frame = cap.read()
        if not ret:
            break  # 视频读取完毕
        # 按间隔保存帧
        if frame_count % interval == 0:
            save_path = os.path.join(output_dir, f"frame_{save_count:06d}.jpg")
            cv2.imwrite(save_path, frame)
            save_count += 1
        frame_count += 1
    
    cap.release()
    print(f"成功提取 {save_count} 帧图像,保存至 {output_dir}")
​
# 调用示例:从交通视频中抽帧
video_to_frames("traffic.mp4", "./dataset/images/raw", interval=20)

合成数据补充:对小目标或稀有场景(如火灾、故障设备),可使用Blender等工具生成3D合成图像及精准掩码,弥补真实数据不足。

(2)数据量与质量要求

数据量需根据类别复杂度调整,参考标准如下:

任务复杂度 类别数量 单类数据量(最低要求) 图像分辨率建议
简单任务(如单一物体分割) 1-3类 500-1000张 640×640
中等任务(如日常场景) 4-10类 300-500张 1280×1280
复杂任务(如工业质检) 10类以上 150-300张 1280×1280及以上

图像质量需满足:无严重模糊、光照均匀(需包含强光、逆光等极端情况)、背景多样化(避免单一背景导致过拟合)。

2.2 数据标注

分割标注的核心是"轮廓精准",手动标注效率低,需借助专业工具。以下是3款主流工具的对比及实操技巧:

(1)主流标注工具对比
工具名称 核心优势 适用场景 格式转换
LabelMe 开源免费、轻量、支持多边形标注 个人或小团队,中小规模数据集 可通过官方脚本导出为YOLO格式
LabelStudio 支持团队协作、多任务标注(检测+分割) 企业级团队,大规模数据集 自定义导出模板,直接生成YOLO标注
VGG Image Annotator 浏览器端操作,无需安装,支持像素级掩码 快速原型标注,临时需求 需手动处理为YOLO格式
(2)LabelMe实操:从标注到YOLO格式导出

LabelMe是入门首选,步骤如下:

  1. 安装:pip install labelme

  2. 启动标注:命令行输入labelme,选择数据集图像目录

  3. 标注操作:点击左侧"Create Polygons",沿目标轮廓点击描点,闭合后输入类别名称(如"Car")

  4. 格式转换:标注完成后生成.json文件,使用以下脚本转换为YOLO格式:

python 复制代码
import json
import os
import cv2
​
def labelme2yolo(labelme_dir, output_label_dir, class_mapping):
    os.makedirs(output_label_dir, exist_ok=True)
    # 遍历所有json标注文件
    for json_file in os.listdir(labelme_dir):
        if not json_file.endswith(".json"):
            continue
        # 读取json
        with open(os.path.join(labelme_dir, json_file), 'r') as f:
            data = json.load(f)
        # 获取图像尺寸(用于坐标归一化)
        img_h = data["imageHeight"]
        img_w = data["imageWidth"]
        # 生成标注文件(与图像同名)
        label_txt = os.path.join(output_label_dir, json_file.replace(".json", ".txt"))
        with open(label_txt, 'w') as f:
            for shape in data["shapes"]:
                class_name = shape["label"]
                if class_name not in class_mapping:
                    continue  # 跳过未定义类别
                class_id = class_mapping[class_name]
                # 提取轮廓点并归一化
                points = shape["points"]
                norm_points = []
                for (x, y) in points:
                    norm_x = round(x / img_w, 6)
                    norm_y = round(y / img_h, 6)
                    norm_points.extend([norm_x, norm_y])
                # 计算边界框(YOLO格式需要)
                x_list = [p[0] for p in points]
                y_list = [p[1] for p in points]
                x_center = round((min(x_list) + max(x_list)) / (2 * img_w), 6)
                y_center = round((min(y_list) + max(y_list)) / (2 * img_h), 6)
                width = round((max(x_list) - min(x_list)) / img_w, 6)
                height = round((max(y_list) - min(y_list)) / img_h, 6)
                # 写入标注信息
                line = f"{class_id} {x_center} {y_center} {width} {height} " + " ".join(map(str, norm_points)) + "\n"
                f.write(line)
​
# 调用示例:将Car映射为1,Pedestrian映射为0
class_mapping = {"Car": 1, "Pedestrian": 0}
labelme2yolo("./labelme_annotations", "./dataset/labels/train", class_mapping)
(3)标注精度控制技巧
  • 轮廓描点:曲线部分每5-10像素描一个点,直线部分可适当稀疏,确保轮廓与目标边缘误差不超过2像素。

  • 类别一致性:同一类目标名称统一(如避免"行人"和"Pedestrian"混用),可提前制定标注手册。

  • 标注审核:随机抽取10%-20%的标注文件,用可视化工具检查------将标注的轮廓绘制在原图上,确认无漏标、错标。

三、训练过程

3.1、导入训练数据

下载YOLO项目压缩包,解压在任意本地workspace文件夹中。

下载YOLO预训练分割模型,导入到ultralytics-main项目根目录下。

​​

ultralytics-main 项目根目录下,创建data文件夹,并在data文件夹下创建子文件夹:images、labels, 其中,将YOLO格式的TXT文件 手动导入到Annotations文件夹中,将JPG格式的图像数据导入到images文件夹中。

(注:数据集文件包中train、test、valid三个文件夹的images和labels合并)

data目录结构如下:

​​​​​​

3.2、数据划分

首先在ultralytics-main目录下创建一个split.py文件,运行文件之后会在ultralytics-main目录下生成datasets文件夹,具体目录如下:

训练集、验证集、测试集已经完成划分。

python 复制代码
import shutil
import random
import os

# 原始路径
image_original_path = "data/images/"
label_original_path = "data/labels/"

# 数据集划分比例(可以自定义)
train_percent = 0.8
val_percent = 0.1
test_percent = 0.1

cur_path = os.getcwd()
# 训练集路径
train_image_path = os.path.join(cur_path, "datasets/images/train/")
train_label_path = os.path.join(cur_path, "datasets/labels/train/")

# 验证集路径
val_image_path = os.path.join(cur_path, "datasets/images/val/")
val_label_path = os.path.join(cur_path, "datasets/labels/val/")

# 测试集路径
test_image_path = os.path.join(cur_path, "datasets/images/test/")
test_label_path = os.path.join(cur_path, "datasets/labels/test/")

# 训练集目录
list_train = os.path.join(cur_path, "datasets/train.txt")
list_val = os.path.join(cur_path, "datasets/val.txt")
list_test = os.path.join(cur_path, "datasets/test.txt")

def del_file(path):
    for i in os.listdir(path):
        file_data = path + "\\" + i
        os.remove(file_data)

def mkdir():
    if not os.path.exists(train_image_path):
        os.makedirs(train_image_path)
    else:
        del_file(train_image_path)
    if not os.path.exists(train_label_path):
        os.makedirs(train_label_path)
    else:
        del_file(train_label_path)

    if not os.path.exists(val_image_path):
        os.makedirs(val_image_path)
    else:
        del_file(val_image_path)
    if not os.path.exists(val_label_path):
        os.makedirs(val_label_path)
    else:
        del_file(val_label_path)

    if not os.path.exists(test_image_path):
        os.makedirs(test_image_path)
    else:
        del_file(test_image_path)
    if not os.path.exists(test_label_path):
        os.makedirs(test_label_path)
    else:
        del_file(test_label_path)

def clearfile():
    if os.path.exists(list_train):
        os.remove(list_train)
    if os.path.exists(list_val):
        os.remove(list_val)
    if os.path.exists(list_test):
        os.remove(list_test)


def main():
    mkdir()
    clearfile()

    file_train = open(list_train, 'w')
    file_val = open(list_val, 'w')
    file_test = open(list_test, 'w')

    total_txt = os.listdir(label_original_path)
    num_txt = len(total_txt)
    list_all_txt = range(num_txt)

    num_train = int(num_txt * train_percent)
    num_val = int(num_txt * val_percent)
    num_test = num_txt - num_train - num_val

    train = random.sample(list_all_txt, num_train)
    # train从list_all_txt取出num_train个元素
    # 所以list_all_txt列表只剩下了这些元素
    val_test = [i for i in list_all_txt if not i in train]
    # 再从val_test取出num_val个元素,val_test剩下的元素就是test
    val = random.sample(val_test, num_val)

    print("训练集:{}, 验证集:{}, 测试集:{}".format(len(train), len(val), len(val_test) - len(val)))
    for i in list_all_txt:
        name = total_txt[i][:-4]

        srcImage = image_original_path + name + '.jpg'
        srcLabel = label_original_path + name + ".txt"

        if i in train:
            dst_train_Image = train_image_path + name + '.jpg'
            dst_train_Label = train_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_train_Image)
            shutil.copyfile(srcLabel, dst_train_Label)
            file_train.write(dst_train_Image + '\n')
        elif i in val:
            dst_val_Image = val_image_path + name + '.jpg'
            dst_val_Label = val_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_val_Image)
            shutil.copyfile(srcLabel, dst_val_Label)
            file_val.write(dst_val_Image + '\n')
        else:
            dst_test_Image = test_image_path + name + '.jpg'
            dst_test_Label = test_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_test_Image)
            shutil.copyfile(srcLabel, dst_test_Label)
            file_test.write(dst_test_Image + '\n')

    file_train.close()
    file_val.close()
    file_test.close()


if __name__ == "__main__":
    main()

3.3、修改数据集配置文件

以道路裂缝为例:

在ultralytics-main目录下创建一个data.yaml文件

python 复制代码
path: ../datasets/images
train: train  # 数据集路径下的train
val: val  # 数据集路径下的val
test: test  # 数据集路径下的test

# 标签个数
nc: 3
# Classes标签名称
names: ['Alligator_crack', 'Longitudinal_crack', 'Transverse_crack']

3.4、执行命令

在ultralytics-main目录下创建一个train.py文件,运行

python 复制代码
from ultralytics import YOLO

if __name__ == '__main__':
    model = YOLO("yolo11s-seg.pt")
    model.train(data=r'data.yaml',
                imgsz=640,
                epochs=100,
                batch=16,
                workers=0,
                device='0'
                )

也可以在终端执行下述命令:

bash 复制代码
yolo segment train data=data.yaml model=yolo11s-seg.pt epochs=200 imgsz=640 batch=16 workers=0 device=0
相关推荐
檐下翻书1732 小时前
从入门到精通:流程图制作学习路径规划
论文阅读·人工智能·学习·算法·流程图·论文笔记
CoderYanger2 小时前
B.双指针——3194. 最小元素和最大元素的最小平均值
java·开发语言·数据结构·算法·leetcode·职场和发展·1024程序员节
SalvoGao2 小时前
Python学习 | 怎么理解epoch?
数据结构·人工智能·python·深度学习·学习
搬砖者(视觉算法工程师)3 小时前
自动驾驶汽车技术的工程原理与应用
人工智能·计算机视觉·自动驾驶
CV实验室3 小时前
2025 | 哈工大&鹏城实验室等提出 Cascade HQP-DETR:仅用合成数据实现SOTA目标检测,突破虚实鸿沟!
人工智能·目标检测·计算机视觉·哈工大
aitoolhub4 小时前
培训ppt高效制作:稿定设计 + Prompt 工程 30 分钟出图指南
人工智能·prompt·aigc
oranglay4 小时前
提示词(Prompt Engineering)核心思维
人工智能·prompt
极速learner4 小时前
【Prompt分享】自学英语教程的AI 提示语:流程、范例及可视化实现
人工智能·prompt·ai写作
大怪v4 小时前
我TM被AI骗的自己PUA了自己😂 😂 !细思极恐~
人工智能·chatgpt·grok