YOLO系列 目标分割txt格式数据增强(YOLOv5-seg YOLOv6-seg YOLOv7-seg YOLOv8-seg YOLOv9-seg YOLOv10-seg)

在近年来的计算机视觉领域,YOLO(You Only Look Once)系列模型已经成为目标检测的黄金标准之一,以其卓越的速度和准确性获得了广泛的认可和应用。随着研究的深入和技术的发展,YOLO不仅在传统的目标检测领域取得了令人瞩目的成绩,更是逐渐拓展到了目标分割领域,诞生了如YOLOv5-seg、YOLOv6-seg、YOLOv7-seg等一系列融合了分割功能的升级版本。这些版本通过精细地区分图像中每一个像素点的归属,为目标检测带来了更丰富的信息和更高级的应用可能。

在训练这些先进的模型时,数据的质量和多样性直接关系到最终模型的性能。为了进一步提升模型在实际应用中的鲁棒性和准确性,数据增强成为了不可或缺的一环。尤其是对于目标分割任务,由于其对图像细节的高度敏感性,适当而有效的数据增强策略可以极大地丰富训练样本,帮助模型学习到更多样的特征表达,从而提高其泛化能力和对各种场景的适应性。

本文将深入探讨在使用YOLO系列目标分割模型(如YOLOv5-seg至YOLOv10-seg)时,如何通过TXT格式的数据增强来优化训练过程。我们会从数据增强的必要性谈起,进而详细介绍几种高效的数据增强技巧,最后探讨如何将这些技巧应用于YOLO系列的分割任务中,以期为读者提供一份实操性强、易于理解且高效的数据增强指南,帮助他们在目标分割领域取得更佳的研究成果和应用效果。

前言

YOLO-Seg 系列模型是将 YOLO 目标检测框架和图像分割技术相结合的方法,旨在同时进行目标检测和分割。与传统的 YOLO 模型相比,YOLO-Seg 不仅需要识别图像中的物体及其位置,还需要精确地分割出物体的每个像素。这使得数据增强变得尤为重要,以下是数据增强在 YOLO-Seg 系列模型训练中的好处:

  1. 改善模型对尺寸和视角的适应性:通过缩放、裁剪和旋转等数据增强技术,可以帮助模型更好地理解对象在不同尺寸和视角下的外观。这对于图像分割尤为重要,因为精确的分割需要模型对目标物体的几何形状和结构有深入的理解。

  2. 增加场景和背景的多样性:通过背景替换、添加噪声或模糊等增强方法,可以训练模型更好地区分前景目标和背景,从而提高分割的精度。这有助于提高模型在不同背景和噪声条件下的鲁棒性。

  3. 提升边缘定位的精确度:图像分割要求模型对像素级别的目标边缘有精确的识别能力。通过适应性的局部扭曲、透视变换等数据增强技术,可以增加模型解析目标边缘和形状变化的能力。

  4. 训练模型处理遮挡和重叠:在真实世界的场景中,目标对象可能会部分或完全被其他对象遮挡。数据增强方法,如随机遮挡、物体插入等,可以模拟这些情况,训练模型学习如何处理遮挡问题,提高对重叠或部分遮挡物体的分割效果。

  5. 模拟不同光照和天气条件:通过调整亮度、对比度、色彩饱和度等因素,数据增强可以帮助模型适应不同的光照和天气条件下的图像分割任务,增强模型的通用性。

  6. 减少数据集偏差和过拟合风险:数据增强通过增加训练数据的多样性,可以降低训练集特定偏差对模型的影响,减少过拟合的风险,提高模型对未知数据的泛化能力。

总之,对 YOLO-Seg 系列模型来说,数据增强不仅能够提高目标检测的精确度和鲁棒性,还对提升分割任务的细节表现、边缘定位精度以及应对复杂场景的能力至关重要。


一、增强步骤

json转txt:链接: json2txt
txt转xml:链接: txt2xml
seg进行数据增强:见第二部分
xml转txt:链接: xml2txt

二、seg进行数据增强

import time
import random
import cv2
import os
import numpy as np
from skimage.util import random_noise
import base64
import json
import re
from copy import deepcopy

# 图像均为cv2读取
class DataAugmentForObjectDetection():
    def __init__(self, change_light_rate=0.5,
                 add_noise_rate=0.5, random_point=0.5, flip_rate=0.5, shift_rate=0.5, rand_point_percent=0.03,
                 is_addNoise=True, is_changeLight=True, is_random_point=True, is_shift_pic_bboxes=True,
                 is_filp_pic_bboxes=True):
        # 配置各个操作的属性
        self.change_light_rate = change_light_rate
        self.add_noise_rate = add_noise_rate
        self.random_point = random_point
        self.flip_rate = flip_rate
        self.shift_rate = shift_rate

        self.rand_point_percent = rand_point_percent

        # 是否使用某种增强方式
        self.is_addNoise = is_addNoise
        self.is_changeLight = is_changeLight
        self.is_random_point = is_random_point
        self.is_filp_pic_bboxes = is_filp_pic_bboxes
        self.is_shift_pic_bboxes = is_shift_pic_bboxes

    # 加噪声
    def _addNoise(self, img):
        return random_noise(img, seed=int(time.time())) * 255

    # 调整亮度
    def _changeLight(self, img):
        alpha = random.uniform(0.8, 1)
        blank = np.zeros(img.shape, img.dtype)
        return cv2.addWeighted(img, alpha, blank, 1 - alpha, 0)

    # 随机的改变点的值
    def _addRandPoint(self, img):
        percent = self.rand_point_percent
        num = int(percent * img.shape[0] * img.shape[1])
        for i in range(num):
            rand_x = random.randint(0, img.shape[0] - 1)
            rand_y = random.randint(0, img.shape[1] - 1)
            if random.randint(0, 1) == 0:
                img[rand_x, rand_y] = 0
            else:
                img[rand_x, rand_y] = 255
        return img

    # 平移
    def _shift_pic_bboxes(self, img, json_info):

        # ---------------------- 平移图像 ----------------------
        h, w, _ = img.shape
        x_min = w
        x_max = 0
        y_min = h
        y_max = 0

        shapes = json_info['shapes']
        for shape in shapes:
            points = np.array(shape['points'])
            x_min = min(x_min, points[:, 0].min())
            y_min = min(y_min, points[:, 1].min())
            x_max = max(x_max, points[:, 0].max())
            y_max = max(y_max, points[:, 0].max())

        d_to_left = x_min  # 包含所有目标框的最大左移动距离
        d_to_right = w - x_max  # 包含所有目标框的最大右移动距离
        d_to_top = y_min  # 包含所有目标框的最大上移动距离
        d_to_bottom = h - y_max  # 包含所有目标框的最大下移动距离

        x = random.uniform(-(d_to_left - 1) / 3, (d_to_right - 1) / 3)
        y = random.uniform(-(d_to_top - 1) / 3, (d_to_bottom - 1) / 3)

        M = np.float32([[1, 0, x], [0, 1, y]])  # x为向左或右移动的像素值,正为向右负为向左; y为向上或者向下移动的像素值,正为向下负为向上
        shift_img = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]))

        # ---------------------- 平移boundingbox ----------------------
        for shape in shapes:
            for p in shape['points']:
                p[0] += x
                p[1] += y
        return shift_img, json_info

    # 镜像
    def _filp_pic_bboxes(self, img, json_info):

        # ---------------------- 翻转图像 ----------------------
        h, w, _ = img.shape

        sed = random.random()

        if 0 < sed < 0.33:  # 0.33的概率水平翻转,0.33的概率垂直翻转,0.33是对角反转
            flip_img = cv2.flip(img, 0)  # _flip_x
            inver = 0
        elif 0.33 < sed < 0.66:
            flip_img = cv2.flip(img, 1)  # _flip_y
            inver = 1
        else:
            flip_img = cv2.flip(img, -1)  # flip_x_y
            inver = -1

        # ---------------------- 调整boundingbox ----------------------
        shapes = json_info['shapes']
        for shape in shapes:
            for p in shape['points']:
                if inver == 0:
                    p[1] = h - p[1]
                elif inver == 1:
                    p[0] = w - p[0]
                elif inver == -1:
                    p[0] = w - p[0]
                    p[1] = h - p[1]

        return flip_img, json_info

    # 图像增强方法
    def dataAugment(self, img, dic_info):

        change_num = 0  # 改变的次数
        while change_num < 1:  # 默认至少有一种数据增强生效

            if self.is_changeLight:
                if random.random() > self.change_light_rate:  # 改变亮度
                    change_num += 1
                    img = self._changeLight(img)

            if self.is_addNoise:
                if random.random() < self.add_noise_rate:  # 加噪声
                    change_num += 1
                    img = self._addNoise(img)
            if self.is_random_point:
                if random.random() < self.random_point:  # 加随机点
                    change_num += 1
                    img = self._addRandPoint(img)
            if self.is_shift_pic_bboxes:
                if random.random() < self.shift_rate:  # 平移
                    change_num += 1
                    img, dic_info = self._shift_pic_bboxes(img, dic_info)
            if self.is_filp_pic_bboxes or 1:
                if random.random() < self.flip_rate:  # 翻转
                    change_num += 1
                    img, dic_info = self._filp_pic_bboxes(img, dic_info)

        return img, dic_info


# xml解析工具
class ToolHelper():
    # 从json文件中提取原始标定的信息
    def parse_json(self, path):
        with open(path)as f:
            json_data = json.load(f)
        return json_data

    # 对图片进行字符编码
    def img2str(self, img_name):
        with open(img_name, "rb")as f:
            base64_data = str(base64.b64encode(f.read()))
        match_pattern = re.compile(r'b\'(.*)\'')
        base64_data = match_pattern.match(base64_data).group(1)
        return base64_data

    # 保存图片结果
    def save_img(self, save_path, img):
        cv2.imwrite(save_path, img)

    # 保存json结果
    def save_json(self, file_name, save_folder, dic_info):
        with open(os.path.join(save_folder, file_name), 'w') as f:
            json.dump(dic_info, f, indent=2)


if __name__ == '__main__':

    need_aug_num = 10  # 每张图片需要增强的次数

    toolhelper = ToolHelper()  # 工具

    is_endwidth_dot = True  # 文件是否以.jpg或者png结尾

    dataAug = DataAugmentForObjectDetection()  # 数据增强工具类

    # 写死的文件路径
    source_img_json_path = 'E:/A/yolov8-tree/dataset/massif/new-json'  # 图片和json文件原始位置
    save_img_json_path = 'E:/A/yolov8-tree/dataset/massif/new-new-json'  # 图片增强结果保存文件

    # 如果保存文件夹不存在就创建
    if not os.path.exists(save_img_json_path):
        os.mkdir(save_img_json_path)

    for parent, _, files in os.walk(source_img_json_path):
        files.sort()  # 排序一下
        for file in files:
            if file.endswith('jpg') or file.endswith('png'):  # 如样本是其他格式,需要自行进行补充
                cnt = 0
                pic_path = os.path.join(parent, file)
                json_path = os.path.join(parent, file[:-4] + '.json')
                json_dic = toolhelper.parse_json(json_path)
                # 如果图片是有后缀的
                if is_endwidth_dot:
                    # 找到文件的最后名字
                    dot_index = file.rfind('.')
                    _file_prefix = file[:dot_index]  # 文件名的前缀
                    _file_suffix = file[dot_index:]  # 文件名的后缀
                img = cv2.imread(pic_path)

                while cnt < need_aug_num:  # 继续增强
                    auged_img, json_info = dataAug.dataAugment(deepcopy(img), deepcopy(json_dic))
                    img_name = '{}_{}{}'.format(_file_prefix, cnt + 1, _file_suffix)  # 图片保存的信息
                    img_save_path = os.path.join(save_img_json_path, img_name)
                    toolhelper.save_img(img_save_path, auged_img)  # 保存增强图片

                    json_info['imagePath'] = img_name
                    base64_data = toolhelper.img2str(img_save_path)
                    json_info['imageData'] = base64_data
                    toolhelper.save_json('{}_{}.json'.format(_file_prefix, cnt + 1),
                                         save_img_json_path, json_info)  # 保存json文件
                    print(img_name)
                    cnt += 1  # 继续增强下一张

### DeepLabV3 和 YOLOv8-Seg 的特点、性能对比及适用场景 #### 模型特点 DeepLabV3 是一种专注于语义分割任务的经典模型,主要通过空间金字塔池化模块 (ASPP) 来捕获多尺度上下文信息,并采用 Atrous 卷积来扩大感受野而不增加计算量[^1]。它适合处理复杂的背景和细节丰富的图像。 YOLOv8-Seg 则是在目标检测基础上扩展到语义分割的任务中,继承了 YOLO 系列快速推理的优势,同时能够提供像素级的预测结果。它的特点是速度快、实时性强,在资源受限环境下表现优异[^2]。 #### 性能对比 在实验设置下,YOLOv8L-seg 达到了 0.516 的验证 mIOU,这一指标高于其他基线模型,表明其在某些特定条件下具有更好的分割能力。然而需要注意的是,这种优势可能依赖于具体的训练配置以及数据分布情况。相比之下,虽然 DeepLabV3 可能在绝对数值上稍逊一筹,但它通常能够在更加复杂的数据集中保持稳定的表现水平。 关于训练数据保留的效果研究显示,当减少多样性较高的样本数量时,所有模型都会经历一定程度上的退步;但对于像 YOLO 这样的轻量化架构而言,影响似乎更为明显一些。这暗示着如果项目允许获取更多样化的高质量图片,则应优先考虑使用传统类型的密集连接结构如 Deeplab 系列产品。 另外值得注意的是,尽管存在不同的标注样式变化,但它们对于最终输出质量几乎没有造成太大干扰——这意味着无论选择哪款解决方案都可以放心忽略此类因素带来的潜在风险。 #### 应用场景 - **DeepLabV3**: 更适用于需要高精度语义理解的应用场合,比如医疗影像中的病灶区域识别或者卫星地图上的土地覆盖分类等领域。由于它可以很好地捕捉细粒度特征并维持全局一致性,因此成为这些任务的理想候选者之一。 - **YOLOv8-Seg**: 非常适合作为移动应用程序的一部分运行,尤其是在那些要求低延迟反馈的情况下,例如增强现实游戏内的物体交互或是无人机导航避障等功能实现过程中都可发挥重要作用。 ```python import torch from ultralytics import YOLO model = YOLO(&#39;yolov8s-seg.pt&#39;) # 加载预训练权重文件 results = model.predict(source=&#39;image.jpg&#39;, conf=0.7, iou=0.5) for result in results: boxes = result.boxes.cpu().numpy() # 获取边界框坐标 masks = result.masks.data.cpu().numpy() # 提取掩码矩阵用于后续操作 ``` 上述代码片段展示了如何加载 YOLOv8-Seg 并执行简单的推断过程。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值