YOLOv5自定义数据集:COCO、VOC格式转换指南
引言:解决自定义数据集的格式痛点
你是否在训练YOLOv5模型时因数据集格式不兼容而困扰?是否面对COCO的JSON标注和VOC的XML文件感到无从下手?本文将系统讲解如何将COCO和VOC格式的数据集转换为YOLOv5支持的TXT格式,帮助你快速搭建训练流程。读完本文后,你将掌握:
- 数据集格式转换的核心原理与步骤
- VOC XML到YOLO TXT的批量转换方法
- COCO JSON标注文件的解析与转换技巧
- 自定义数据集的目录结构规范
- 转换后的数据验证与错误排查
数据集格式基础:从原理到结构
三种格式的核心差异
| 格式 | 标注文件类型 | 坐标表示 | 优势场景 | 兼容性 |
|---|---|---|---|---|
| VOC | XML | 绝对像素值 | 目标检测入门教学 | 支持多数框架 |
| COCO | JSON | 绝对像素值 | 大规模数据集 | 学术研究首选 |
| YOLO | TXT | 相对归一化 | 模型训练效率 | YOLO系列专用 |
YOLOv5要求的目录结构
datasets/
└── custom_dataset/
├── images/
│ ├── train/
│ └── val/
├── labels/
│ ├── train/
│ └── val/
└── data.yaml # 数据集配置文件
VOC格式转YOLOv5:完整实现流程
1. 原始VOC数据集结构
VOCdevkit/
└── VOC2007/
├── Annotations/ # XML标注文件
├── ImageSets/
│ └── Main/ # 训练/验证集划分
└── JPEGImages/ # 图片文件
2. 转换核心代码实现
VOC转YOLO的核心在于将XML中的边界框坐标转换为相对归一化坐标。以下是从VOC.yaml提取的转换函数:
def convert_label(path, lb_path, year, image_id):
def convert_box(size, box):
# 将像素坐标转换为相对坐标
dw, dh = 1. / size[0], 1. / size[1]
x = (box[0] + box[1]) / 2.0 - 1 # 中心点x
y = (box[2] + box[3]) / 2.0 - 1 # 中心点y
w = box[1] - box[0] # 宽度
h = box[3] - box[2] # 高度
return x * dw, y * dh, w * dw, h * dh
in_file = open(path / f'VOC{year}/Annotations/{image_id}.xml')
out_file = open(lb_path, 'w')
tree = ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
names = list(yaml['names'].values()) # 类别名称列表
for obj in root.iter('object'):
cls = obj.find('name').text
if cls in names and int(obj.find('difficult').text) != 1:
xmlbox = obj.find('bndbox')
# 提取xmin, xmax, ymin, ymax
bb = convert_box((w, h), [float(xmlbox.find(x).text)
for x in ('xmin', 'xmax', 'ymin', 'ymax')])
cls_id = names.index(cls) # 获取类别ID
out_file.write(f"{cls_id} {' '.join(map(str, bb))}\n")
3. 批量转换执行步骤
- 准备目录结构:
mkdir -p datasets/custom_voc/images/train datasets/custom_voc/labels/train
- 修改VOC.yaml配置:
path: ../datasets/custom_voc
train: images/train
val: images/val
names:
0: aeroplane
1: bicycle
... # 其他类别
- 执行转换脚本:
python -c "from utils.general import yaml_load; yaml = yaml_load('VOC.yaml'); exec(yaml['download'])"
COCO格式转YOLOv5:JSON到TXT的转换
1. COCO数据集结构解析
coco/
├── annotations/
│ ├── instances_train2017.json # 训练集标注
│ └── instances_val2017.json # 验证集标注
├── train2017/ # 训练图片
└── val2017/ # 验证图片
2. COCO转YOLO核心步骤
COCO标注使用JSON格式存储所有标注信息,转换需要解析JSON并生成每个图片对应的TXT文件:
import json
def convert_coco_to_yolo(json_path, img_dir, label_dir, names):
with open(json_path) as f:
data = json.load(f)
# 创建图片ID到文件名的映射
img_id_map = {img['id']: img['file_name'] for img in data['images']}
# 按图片ID分组标注
annotations_by_img = {}
for ann in data['annotations']:
img_id = ann['image_id']
if img_id not in annotations_by_img:
annotations_by_img[img_id] = []
annotations_by_img[img_id].append(ann)
# 生成YOLO格式标签文件
for img_id, anns in annotations_by_img.items():
img_file = img_id_map[img_id]
label_file = label_dir / Path(img_file).with_suffix('.txt').name
with open(label_file, 'w') as f:
for ann in anns:
cls_id = ann['category_id'] - 1 # COCO类别ID从1开始
bbox = ann['bbox'] # x, y, width, height
x_center = (bbox[0] + bbox[2]/2) / ann['image_width']
y_center = (bbox[1] + bbox[3]/2) / ann['image_height']
width = bbox[2] / ann['image_width']
height = bbox[3] / ann['image_height']
f.write(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")
3. 执行转换命令
# 下载COCO数据集(约20GB)
python -c "from utils.general import yaml_load; yaml = yaml_load('data/coco.yaml'); exec(yaml['download'])"
# 手动转换(如果需要自定义处理)
python convert_coco.py --json_path datasets/coco/annotations/instances_train2017.json \
--img_dir datasets/coco/images/train2017 \
--label_dir datasets/coco/labels/train2017 \
--names data/coco.yaml
自定义数据集配置文件详解
data.yaml关键参数设置
# 自定义数据集配置示例
path: ../datasets/custom_dataset # 数据集根目录
train: images/train # 训练集图片路径
val: images/val # 验证集图片路径
test: # 测试集(可选)
# 类别名称与ID映射
names:
0: person
1: car
2: bicycle
# 其他类别...
# 类别数量(可选,自动从names推导)
nc: 3
目录结构验证工具
使用以下脚本检查数据集结构是否符合要求:
from utils.general import check_dataset
# 验证数据集配置和结构
data = check_dataset('data/custom.yaml')
print(f"数据集验证通过: 类别数={data['nc']}, 训练集图片数={len(data['train'])}")
转换后数据集验证与错误排查
1. 数据可视化检查
import cv2
import matplotlib.pyplot as plt
def visualize_labels(img_path, label_path, names):
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
h, w = img.shape[:2]
with open(label_path) as f:
labels = [list(map(float, line.split())) for line in f.readlines()]
for label in labels:
cls_id, xc, yc, bw, bh = label
x1 = int((xc - bw/2) * w)
y1 = int((yc - bh/2) * h)
x2 = int((xc + bw/2) * w)
y2 = int((yc + bh/2) * h)
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(img, names[int(cls_id)], (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
plt.figure(figsize=(10, 10))
plt.imshow(img)
plt.axis('off')
plt.show()
# 可视化示例图片
visualize_labels('datasets/custom/images/train/img1.jpg',
'datasets/custom/labels/train/img1.txt',
data['names'])
2. 常见错误及解决方法
| 错误类型 | 可能原因 | 解决方案 |
|---|---|---|
| 边界框越界 | 坐标转换错误 | 检查convert_box函数,确保相对坐标在[0,1]范围内 |
| 类别ID不匹配 | names列表顺序错误 | 确保标注文件中的类别ID与data.yaml中的names顺序一致 |
| 文件路径错误 | path配置不正确 | 使用绝对路径或相对于YOLOv5根目录的相对路径 |
| 图片与标签数量不匹配 | 转换过程遗漏 | 使用ls images/train | wc -l和ls labels/train | wc -l验证数量一致 |
高级应用:自动化转换脚本开发
多功能转换工具实现
import argparse
from pathlib import Path
import yaml
import xml.etree.ElementTree as ET
import json
def convert_voc_to_yolo(voc_dir, output_dir, class_names):
"""批量转换VOC格式到YOLO格式"""
# 实现转换逻辑...
def convert_coco_to_yolo(coco_json, output_dir, class_names):
"""批量转换COCO格式到YOLO格式"""
# 实现转换逻辑...
def main():
parser = argparse.ArgumentParser(description='数据集格式转换工具')
parser.add_argument('--input', required=True, help='输入目录或文件')
parser.add_argument('--output', required=True, help='输出目录')
parser.add_argument('--format', required=True, choices=['voc', 'coco'], help='输入格式')
parser.add_argument('--names', required=True, help='类别名称配置文件(yaml)')
args = parser.parse_args()
with open(args.names) as f:
class_names = yaml.safe_load(f)['names']
output_dir = Path(args.output)
output_dir.mkdir(parents=True, exist_ok=True)
if args.format == 'voc':
convert_voc_to_yolo(Path(args.input), output_dir, class_names)
elif args.format == 'coco':
convert_coco_to_yolo(Path(args.input), output_dir, class_names)
print(f"转换完成,结果保存至: {output_dir}")
if __name__ == '__main__':
main()
使用Docker实现一键转换
FROM python:3.9-slim
WORKDIR /yolov5
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
ENTRYPOINT ["python", "tools/convert_dataset.py"]
构建并运行容器:
docker build -t yolov5-converter .
docker run --rm -v $(pwd):/data yolov5-converter \
--input /data/voc_dataset \
--output /data/yolo_dataset \
--format voc \
--names /data/custom_names.yaml
总结与扩展应用
本文详细介绍了VOC和COCO格式到YOLOv5格式的转换方法,包括:
- 两种主流标注格式的解析与转换原理
- 完整的批量转换实现步骤
- 数据集配置文件的正确设置
- 转换后的数据验证与错误处理
通过掌握这些知识,你可以轻松处理自定义数据集,为YOLOv5模型训练打下基础。下一步,你可以探索:
- 半自动化标注工具的集成
- 数据集增强与预处理 pipeline
- 跨格式转换性能优化
希望本文能帮助你高效构建高质量的YOLOv5训练数据集!如有任何问题,欢迎在项目GitHub仓库提交issue或参与讨论。
提示:转换后的数据集建议进行版本控制,使用DVC(Data Version Control)等工具跟踪数据变化,确保实验可复现性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



