1. COCO与YOLO格式规范深度解析
在计算机视觉领域,数据标注格式的标准化对模型训练至关重要。COCO(Common Objects in Context)和YOLO(You Only Look Once)作为两种主流标注格式,各有其设计哲学和应用场景。
1.1 COCO格式规范详解
COCO格式采用JSON文件存储所有标注信息,其数据结构包含三个核心字段:
json复制{
"images": [
{
"id": 1,
"file_name": "image1.jpg",
"width": 640,
"height": 480
}
],
"annotations": [
{
"id": 1,
"image_id": 1,
"category_id": 1,
"bbox": [100, 120, 200, 150],
"area": 30000,
"iscrowd": 0
}
],
"categories": [
{"id": 1, "name": "person"},
{"id": 2, "name": "car"}
]
}
关键特性:
- 集中存储:所有图像的标注信息保存在单个JSON文件中
- 像素坐标系:边界框使用[x_min, y_min, width, height]的绝对像素值
- 灵活类别ID:category_id可以是任意数值,不要求连续
- 多任务支持:同一格式支持目标检测、实例分割和关键点检测
注意:COCO格式中iscrowd字段标记目标是否被遮挡或成组出现,值为1时表示该标注可能不精确
1.2 YOLO格式规范详解
YOLO格式采用分散式存储,每个图像对应一个.txt文件,内容示例:
code复制0 0.453125 0.491667 0.3125 0.3125
1 0.781250 0.408333 0.1875 0.316667
核心特征:
- 归一化坐标:使用[class x_center y_center width height]格式,所有值归一化到0-1
- 零基索引:类别ID必须从0开始连续编号
- 文件对应:每个图像文件必须有同名标注文件
- 多行支持:单个文件可包含多个目标标注
坐标转换公式:
code复制x_center = (x_min + width/2) / image_width
y_center = (y_min + height/2) / image_height
width = bbox_width / image_width
height = bbox_height / image_height
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 格式转换技术实现
2.1 转换核心逻辑
使用Ultralytics官方转换工具时,主要处理以下数据转换:
- 坐标系统转换:将像素坐标转为归一化坐标
- ID重新映射:处理不连续的category_id
- 文件结构重组:从单一JSON到分散的TXT文件
典型转换代码:
python复制from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="coco/annotations/",
save_dir="yolo_labels/",
cls91to80=False, # 自定义数据集必须设为False
use_segments=True # 是否转换分割标注
)
2.2 目录结构处理
转换前后目录结构对比:
COCO原始结构:
code复制dataset/
├── images/
│ ├── train/
│ └── val/
└── annotations/
├── instances_train.json
└── instances_val.json
YOLO转换后结构:
code复制dataset/
├── images/
│ ├── train/
│ └── val/
├── labels/
│ ├── train/
│ └── val/
└── dataset.yaml
关键操作:
python复制import shutil
from pathlib import Path
# 移动标签文件到正确位置
for split in ["train", "val"]:
src = Path(f"yolo_labels/labels/{split}")
dst = Path(f"dataset/labels/{split}")
dst.mkdir(parents=True, exist_ok=True)
for file in src.glob("*.txt"):
shutil.move(str(file), str(dst / file.name))
3. 数据生产全流程
3.1 标注工具选择
常用工具对比:
| 工具 | COCO支持 | YOLO支持 | 特点 |
|---|---|---|---|
| LabelImg | ❌ | ✔ | 轻量级,适合简单检测任务 |
| Labelme | ✔ | ❌ | 支持多边形标注 |
| CVAT | ✔ | ✔ | 企业级,支持视频标注 |
| Roboflow | ✔ | ✔ | 在线服务,带预处理功能 |
3.2 标注质量控制
关键检查点:
- 边界框完整性:确保完全包围目标
- 遮挡处理:正确标记iscrowd属性
- 类别一致性:相同目标使用相同category_id
- 尺寸阈值:过滤过小目标(通常<32x32像素)
使用pycocotools进行验证:
python复制from pycocotools.coco import COCO
coco = COCO("annotations/instances_train.json")
print(coco.getCatIds()) # 检查类别ID连续性
3.3 数据增强策略
YOLO训练推荐增强组合:
yaml复制# dataset.yaml
augment:
hsv_h: 0.015 # 色相增强
hsv_s: 0.7 # 饱和度增强
hsv_v: 0.4 # 明度增强
degrees: 10 # 旋转角度
translate: 0.1 # 平移比例
scale: 0.5 # 缩放幅度
shear: 0.0 # 剪切幅度
perspective: 0.0 # 透视变换
flipud: 0.0 # 上下翻转概率
fliplr: 0.5 # 左右翻转概率
4. 实战问题排查
4.1 常见错误解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 训练时报"No labels found" | 标签文件路径错误 | 检查dataset.yaml中的路径是否使用绝对路径 |
| 类别预测错误 | cls91to80参数设置不当 | 自定义数据集必须设置cls91to80=False |
| 标注文件为空 | iscrowd=1或无效bbox | 预处理JSON文件过滤无效标注 |
| 坐标值超出[0,1] | 归一化计算错误 | 检查图像宽高是否读取正确 |
4.2 高级转换场景
分割标注转换:
python复制convert_coco(
labels_dir="coco/annotations/",
use_segments=True,
segment_format="polygon" # 可选'polygon'或'mask'
)
关键点标注转换:
python复制convert_coco(
labels_dir="coco/annotations/",
use_keypoints=True,
keypoints_format="coco" # 支持'coco'或'yolo'
)
5. 性能优化技巧
5.1 大规模数据处理
使用多进程加速转换:
python复制from multiprocessing import Pool
def process_annotation(json_file):
convert_coco(labels_dir=json_file.parent, save_dir="converted/")
with Pool(4) as p: # 4个进程并行
p.map(process_annotation, Path("annotations").glob("*.json"))
5.2 存储优化
将小文件打包成TFRecord:
python复制import tensorflow as tf
def make_tfrecord(image_path, label_path):
image = tf.io.read_file(image_path)
label = tf.io.read_file(label_path)
feature = {
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image.numpy()])),
'label': tf.train.Feature(bytes_list=tf.train.BytesList(value=[label.numpy()]))
}
return tf.train.Example(features=tf.train.Features(feature=feature))
writer = tf.io.TFRecordWriter("dataset.tfrecord")
for img_path in Path("images").glob("*.jpg"):
label_path = Path("labels") / f"{img_path.stem}.txt"
example = make_tfrecord(str(img_path), str(label_path))
writer.write(example.SerializeToString())
writer.close()
在实际项目中,我们发现使用TFRecord格式可以将IO时间减少60%以上,特别适合大规模数据集训练。
