第4章:数据集准备与标注——从原始图像到训练燃料
做目标检测,有个绕不开的坎——数据。模型再牛,没有高质量的数据集,也是白搭。我见过太多同学花大把时间调参,结果模型效果差,最后发现是标注数据出了问题。这一章,咱们就把数据准备这件事彻底讲透。
4.1 标注工具怎么选?
市面上标注工具不少,但真正好用的就那么几个。我个人习惯根据项目阶段来选:
| 工具 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| LabelImg | 个人/小团队,快速标注 | 轻量、离线、免费 | 功能单一,无协同 |
| CVAT | 团队协作,中大型项目 | Web端、自动标注、多人协同 | 部署稍复杂 |
| Roboflow | 数据管理与增强一体化 | 标注+增强+导出一条龙 | 免费版有数量限制 |
4.1.1 LabelImg:最朴实的入门选择
LabelImg 是我最早用的工具。它就是个 Python 写的桌面应用,打开就能用。操作很简单:
- 用
pip install labelImg安装 - 终端输入
labelImg启动 - 选择图片目录,按
W键画框 - 输入类别名,保存
嗯,这里要注意——LabelImg 默认保存为 Pascal VOC 格式(XML),但 YOLO 需要的是 TXT 格式。你需要在菜单里切换一下:View → Auto Save Mode 和 PascalVOC → YOLO。
classes.txt 写好,这样标注时直接下拉选择,不用每次都手打。能省不少时间。
4.1.2 CVAT:团队协作的利器
如果你带团队做项目,CVAT 是更好的选择。它是个 Web 应用,部署在服务器上,大家用浏览器就能标注。
我曾经在一个智慧城市项目里,5个人同时标注10万张图片。用 CVAT 的自动标注功能,先拿一个预训练模型跑一遍,人工再修正,效率提升了至少3倍。
部署方式我推荐用 Docker:
docker run -p 8080:8080 \
-e CVAT_HOST=your-server-ip \
cvat/cvat:latest
启动后访问 http://localhost:8080,注册账号就能用了。
4.1.3 Roboflow:数据管理的一站式方案
Roboflow 是我最近比较喜欢的工具。它不只是标注,还能做数据增强、格式转换、版本管理。说白了,它把数据准备的全流程都包了。
你上传图片,在线标注,然后一键导出为 YOLO 格式。它还内置了各种增强策略,比如旋转、裁剪、色彩抖动。我一般用它来做快速原型验证。
4.2 格式转换:COCO 与 VOC 的相爱相杀
做目标检测,绕不开两个格式:Pascal VOC 和 COCO。很多公开数据集用的是 COCO 格式,但 YOLO 训练需要的是 TXT 格式。所以格式转换是基本功。
| 格式 | 存储方式 | 坐标表示 | 典型工具 |
|---|---|---|---|
| Pascal VOC | XML 文件,每张图一个 | xmin, ymin, xmax, ymax | LabelImg |
| COCO JSON | 一个 JSON 文件包含所有标注 | x, y, width, height | COCO API |
| YOLO TXT | TXT 文件,每张图一个 | class_id, x_center, y_center, w, h | YOLO 训练脚本 |
为什么会有这么多格式?说白了,历史原因。VOC 是早期标准,COCO 是微软推的,YOLO 为了效率自己搞了一套。你想想看,如果每个框架都用不同格式,那转换代码就得写一堆。
我写了个简单的转换脚本,把 COCO JSON 转成 YOLO TXT:
import json
import os
def coco_to_yolo(coco_json_path, output_dir):
with open(coco_json_path, 'r') as f:
coco = json.load(f)
# 建立类别映射
categories = {cat['id']: cat['name'] for cat in coco['categories']}
for img in coco['images']:
img_id = img['id']
img_w = img['width']
img_h = img['height']
txt_path = os.path.join(output_dir, img['file_name'].replace('.jpg', '.txt'))
with open(txt_path, 'w') as f:
for ann in coco['annotations']:
if ann['image_id'] != img_id:
continue
# COCO 格式: [x, y, w, h] 左上角坐标
x, y, w, h = ann['bbox']
# 转成 YOLO 格式: 中心点坐标 + 宽高,归一化
x_center = (x + w / 2) / img_w
y_center = (y + h / 2) / img_h
w_norm = w / img_w
h_norm = h / img_h
class_id = ann['category_id'] - 1 # COCO 类别从1开始
f.write(f"{class_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}\n")
[x, y, width, height],其中 (x, y) 是左上角坐标。YOLO 需要的是 [class_id, x_center, y_center, width, height],全部归一化到 [0, 1]。这个转换做不对,模型训练出来就是废的。
4.3 数据增强策略:让有限的数据发挥无限价值
数据不够?增强来凑。但增强不是乱加,得有策略。我见过有人把图片旋转90度,结果人倒着站,模型学了一堆错误特征。
下面是我在项目中验证过最有效的几种增强策略:
4.3.1 Mosaic 增强
Mosaic 是 YOLOv4 开始引入的,说白了就是把4张图拼成1张。这样做有几个好处:
- 小目标检测能力提升——因为图片缩小了,小目标相对变大
- 上下文信息更丰富——模型能看到更多场景
- 相当于变相增加了 batch size
实现思路很简单:
def mosaic_augmentation(images, labels, img_size=640):
# 随机选择4张图
# 随机确定拼接中心点
# 把4张图分别放到左上、右上、左下、右下
# 处理边界框的坐标变换
# 返回拼接后的图和标签
pass # 具体实现参考 YOLOv5 源码
嗯,这里要注意——Mosaic 增强后,有些边界框会被切掉。YOLOv5 的做法是只保留中心点在拼接图内的框,或者框面积大于一定阈值的。
4.3.2 MixUp 增强
MixUp 更狠——它把两张图按比例混合。比如 0.7 的猫 + 0.3 的狗,标签也按同样比例混合。模型看到的是模糊的、叠加的图像,但学到的特征更鲁棒。
我曾经在一个工业缺陷检测项目里,用了 MixUp 后,模型的泛化能力提升了 5 个点。为什么?因为缺陷样本太少,MixUp 相当于生成了无数种中间态。
4.3.3 其他常用增强
| 增强方法 | 作用 | 适用场景 | 注意事项 |
|---|---|---|---|
| HSV 色彩抖动 | 改变亮度、饱和度、色相 | 光照变化大的场景 | 色相变化不要超过 0.1 |
| 随机缩放 | 模拟远近变化 | 多尺度检测 | 缩放后要保证目标不畸变 |
| 随机裁剪 | 模拟遮挡 | 遮挡场景 | 裁剪比例不要超过 30% |
| 水平翻转 | 增加对称性 | 左右对称的场景 | 文字、车牌等不要翻转 |
4.4 数据准备全流程
说了这么多,咱们把整个流程串起来。下面这张图是我做项目时用的标准流程:
这个流程我用了很多年,基本没出过大问题。每一步都有坑,我踩过不少,下面分享几个:
- 标注完才发现类别名拼写错误——比如 "person" 写成 "persom",模型直接忽略这个类别
- 格式转换时坐标归一化忘记除以图片宽高——训练出来的模型框全偏了
- Mosaic 增强后标签没同步更新——模型学了一堆错误位置
4.5 数据质量检查清单
最后,我整理了一份检查清单。每次准备数据集,我都会过一遍:
- 图片质量:分辨率是否一致?有没有损坏的图片?
- 标注完整性:每张图都有对应的标注文件吗?
- 类别平衡:各类别样本数量差距大吗?要不要做重采样?
- 边界框质量:有没有框超出图片边界?框面积是不是太小?
- 格式正确性:YOLO 的坐标是不是在 [0,1] 范围内?
- 增强后验证:增强后的图片和标签是否对应?
你想想看,如果这些基础工作没做好,后面调参、改网络结构都是白费力气。数据质量决定了模型效果的上限,算法只是逼近这个上限的手段。