3、YOLOv5数据准备与标注:从原始图像到训练集

数据准备这件事,说简单也简单,说复杂能让你崩溃三天。我刚开始做YOLO项目时,花在数据上的时间比调模型还多。后来才明白——数据质量直接决定模型上限。这一章,咱们就把数据准备的整套流程捋清楚。

核心观点:标注数据不是体力活,是技术活。好的数据集能让YOLOv5收敛更快、泛化更强。

3.1 标注工具:LabelImg实战

LabelImg是我用得最顺手的标注工具。它轻量、开源、支持PascalVOC和YOLO两种格式。说白了,你画个框,它帮你存坐标。

安装与启动

# 方式一:pip安装(推荐)
pip install labelImg
labelImg

# 方式二:源码运行
git clone https://github.com/tzutalin/labelImg
cd labelImg
python labelImg.py

我个人习惯用pip安装,省事。启动后界面长这样:左边是图像区,右边是标注列表,顶部工具栏有「打开目录」「改变保存格式」等按钮。

标注流程(5步走)

  1. 设置保存格式:点击「PascalVOC」按钮,切换到YOLO格式(会显示为YOLO)。
  2. 打开图像目录:选择你存放原始图片的文件夹。
  3. 创建类别标签:在右侧「标签列表」里预定义类别,比如person、car、bicycle。
  4. 画框标注:鼠标左键拖拽,框住目标物体。松开后输入类别。
  5. 保存与下一张:Ctrl+S保存,Ctrl+D切换到下一张。

小技巧:快捷键能大幅提升效率。W键画框,A/D切换图片,Ctrl+S保存。我一天能标500张,全靠快捷键。

避坑指南

我曾经犯过一个低级错误:标注时没注意图片尺寸,结果YOLO训练时报错「图像尺寸不匹配」。后来养成习惯——标注前统一把所有图片resize到640x640,省去后续麻烦。

另外,标注框不要太小(小于32x32像素),YOLOv5下采样后可能直接忽略。你想想看,一个10x10的框经过5次下采样,还剩几个像素?

3.2 数据集格式:COCO与VOC互转

YOLOv5原生支持两种格式:YOLO格式(.txt)和COCO格式(.json)。但很多公开数据集是PascalVOC格式(.xml)。所以格式转换是必备技能。

三种格式对比

格式 存储方式 坐标表示 典型文件
YOLO 每张图一个.txt 归一化的中心点+宽高 img0001.txt
PascalVOC 每张图一个.xml 左上角+右下角坐标 img0001.xml
COCO 整个数据集一个.json 左上角+宽高坐标 annotations.json

YOLO格式的坐标是归一化的,范围0~1。举个例子:一张640x640的图,框的左上角在(160, 320),右下角在(480, 480)。转换成YOLO格式就是:

类别ID  中心x  中心y  宽度  高度
0       0.5    0.625  0.5   0.25

计算过程:中心x = (160+480)/2/640 = 0.5,宽度 = (480-160)/640 = 0.5。嗯,数学不难,但容易算错。

VOC转YOLO脚本

我在项目中写过一个转换脚本,核心逻辑就这几行:

import xml.etree.ElementTree as ET

def voc_to_yolo(xml_file, classes):
    tree = ET.parse(xml_file)
    root = tree.getroot()
    size = root.find('size')
    w_img = int(size.find('width').text)
    h_img = int(size.find('height').text)
    
    yolo_lines = []
    for obj in root.iter('object'):
        cls = obj.find('name').text
        cls_id = classes.index(cls)
        bbox = obj.find('bndbox')
        xmin = int(bbox.find('xmin').text)
        ymin = int(bbox.find('ymin').text)
        xmax = int(bbox.find('xmax').text)
        ymax = int(bbox.find('ymax').text)
        
        # 归一化
        x_center = (xmin + xmax) / 2 / w_img
        y_center = (ymin + ymax) / 2 / h_img
        width = (xmax - xmin) / w_img
        height = (ymax - ymin) / h_img
        
        yolo_lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
    
    return yolo_lines

注意:classes列表的顺序必须和YOLO训练时的data.yaml一致。我见过有人把person和car的顺序搞反,模型把行人识别成汽车——这锅数据背得冤。

3.3 数据增强策略:让模型见多识广

数据增强说白了就是「无中生有」。YOLOv5内置了丰富的增强策略,训练时自动应用。但理解这些策略的原理,能帮你更好地调参。

YOLOv5内置增强

我打开YOLOv5的augmentations.py看过,核心增强包括:

  • Mosaic:把4张图拼成1张,小目标检测效果提升明显。
  • MixUp:两张图按比例混合,模型更鲁棒。
  • HSV变换:随机调整色相、饱和度、明度。
  • 随机缩放/裁剪:模拟不同距离的视角。
  • 翻转:水平翻转,相当于数据集翻倍。

这些增强在训练时通过超参数控制。比如在hyp.scratch.yaml里:

hsv_h: 0.015    # 色相增强幅度
hsv_s: 0.7      # 饱和度增强幅度
hsv_v: 0.4      # 明度增强幅度
degrees: 0.0    # 旋转角度(0表示不旋转)
translate: 0.1  # 平移比例
scale: 0.5      # 缩放比例
mosaic: 1.0     # Mosaic概率(1.0表示100%应用)

什么时候该调增强参数?

我总结了一个经验表格:

场景 建议调整 原因
小目标多 增大mosaic、scale 让小目标在拼接图中更突出
光照变化大 增大hsv_h、hsv_s 模拟不同光照条件
数据量少 增大flip、mixup 增加样本多样性
目标旋转多 适当增加degrees 但不要超过30°,否则框会变形

警告:增强不是越多越好。我试过把degrees设到45°,结果模型把横着的汽车识别成竖着的——因为训练数据里汽车都是横的,旋转后特征变了。增强要符合真实场景。

3.4 本章知识体系

下面这张图概括了数据准备的完整流程:

YOLOv5数据准备流程 YOLOv5数据准备流程 原始图像 LabelImg标注 VOC (.xml) YOLO (.txt) 格式转换脚本 数据增强策略 最终训练集 增强策略包括: Mosaic / MixUp / HSV / 翻转

从原始图像到最终训练集,中间经过标注、格式转换、数据增强三个关键步骤。每一步都有坑,但踩过之后你就知道怎么避开了。

3.5 实战建议

  • 先标100张测试流程:别上来就标5000张。先标100张,跑通训练流程,确认格式没问题再大规模标注。
  • 统一图片尺寸:标注前把所有图片resize到640x640,避免后续处理麻烦。
  • 备份原始标注:增强后的数据不要覆盖原始标注文件。我习惯把原始标注放在raw/目录,增强后的放在aug/目录。
  • 验证数据分布:训练前用脚本统计各类别数量,确保没有严重类别不平衡。

最后说一句:数据准备占项目时间的60%以上,别急。模型调参可以快,数据质量必须稳。你想想看,垃圾进垃圾出——再好的YOLOv5也救不了烂数据。