如何将 COCO 注释转换为 YOLO 格式
训练 Ultralytics YOLO 模型需要 YOLO 格式的注释,但许多流行的 注释 工具却以 COCO JSON 格式导出。本指南将向您展示如何将您的 COCO 注释转换为 YOLO 格式,并开始训练 目标 detect、实例 segment 和 姿势估计 模型。
为什么要从 COCO 转换为 YOLO?
COCO JSON 格式将所有注释存储在一个文件中,而 YOLO 对每张图像使用一个文本文件,其中包含归一化坐标。转换是必要的,原因如下:
- YOLO 模型需要
.txt标签文件 每张图像一个文件,包含class x_center y_center width height归一化坐标。 - COCO JSON 使用像素坐标 在
[x_min, y_min, width, height]格式,所有图像共用一个 JSON 文件。 - 类别 ID 不同 — COCO 使用任意的
category_id值,而 YOLO 需要从零开始索引的类别 ID。
| 特性 | COCO JSON | YOLO TXT |
|---|---|---|
| 结构 | 所有图像共用一个 JSON 文件 | 一 .txt 每张图像一个文件 |
| BBox 格式 | [x_min, y_min, width, height] 像素坐标 | class x_center y_center width height 归一化 (0-1) |
| 类别 ID | category_id (可以从任意数字开始) | 零索引(从0开始) |
| 分割 | 多边形数组位于 segmentation 字段 | 类别ID后的多边形坐标 |
| 关键点 | [x, y, visibility, ...] 像素坐标 | [x, y, visibility, ...] 已标准化 |
快速入门
转换COCO标注并开始训练的最快方法:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="path/to/annotations/", # directory containing your JSON files
save_dir="path/to/output/", # where to save converted labels
cls91to80=False, # IMPORTANT: set False for custom datasets
)
转换后,组织您的目录结构,创建dataset.yaml,并开始训练。请参阅下面的完整分步指南。
自定义数据集:始终使用 cls91to80=False
字段 cls91to80=True 默认设计为 仅 以了解标准 COCO 数据集 包含80个对象类别,它将91个非连续类别ID映射到80个连续类别ID。对于任何自定义数据集,您 必须 设置 cls91to80=False — 否则您的类别ID将被静默错误映射,并且您的模型将学习到错误的类别。
分步转换指南
1. 准备您的 COCO 数据集
从标注工具导出的典型COCO格式数据集具有以下结构:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ ├── img_002.jpg
│ │ └── ...
│ └── val/
│ ├── img_100.jpg
│ └── ...
└── annotations/
├── instances_train.json
└── instances_val.json
每个JSON文件都遵循 COCO数据格式 规范,包含三个必需字段 — images, annotations和 categories:
{
"images": [{ "id": 1, "file_name": "img_001.jpg", "width": 640, "height": 480 }],
"annotations": [
{
"id": 1,
"image_id": 1,
"category_id": 1,
"bbox": [100, 50, 200, 150],
"area": 30000,
"iscrowd": 0
}
],
"categories": [
{ "id": 1, "name": "helmet" },
{ "id": 2, "name": "vest" }
]
}
2. 转换注释
使用 convert_coco() 函数,用于将您的COCO JSON标注转换为YOLO .txt 格式:
将COCO转换为YOLO格式
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
cls91to80=False,
)
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
use_segments=True,
cls91to80=False,
)
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
use_keypoints=True,
cls91to80=False,
)
3. 组织目录结构
转换后,标签文件需要与您的图像放在一起。YOLO期望一个 labels/ 目录,镜像 images/ 目录:
import shutil
from pathlib import Path
# Paths
converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")
# Move labels next to images for each split
for split in ["train", "val"]:
src = converted_dir / split # convert_coco strips "instances_" prefix from JSON filename
dst = dataset_dir / "labels" / split
dst.mkdir(parents=True, exist_ok=True)
for f in src.glob("*.txt"):
shutil.move(str(f), str(dst / f.name))
您的最终数据集结构应如下所示:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ └── ...
│ └── val/
│ └── ...
├── labels/
│ ├── train/
│ │ ├── img_001.txt
│ │ └── ...
│ └── val/
│ └── ...
└── dataset.yaml
4. 创建 dataset.yaml
创建一个 dataset.yaml 配置文件,用于将您的COCO类别映射到YOLO类名。此文件告诉YOLO您的数据在哪里以及要detect哪些类别:
import json
from pathlib import Path
import yaml
# Read categories from your COCO JSON
with open("my_dataset/annotations/instances_train.json") as f:
coco = json.load(f)
# Build class names matching convert_coco output (category_id - 1)
categories = sorted(coco["categories"], key=lambda x: x["id"])
names = {cat["id"] - 1: cat["name"] for cat in categories}
# NOTE: convert_coco maps class IDs as category_id - 1, so category_id must
# start from 1. If your categories start from 0, add 1 to each ID first.
# Create dataset.yaml
dataset = {
"path": str(Path("my_dataset").resolve()),
"train": "images/train",
"val": "images/val",
"names": names,
}
with open("my_dataset/dataset.yaml", "w") as f:
yaml.dump(dataset, f, default_flow_style=False)
生成的YAML文件:
path: /absolute/path/to/my_dataset
train: images/train
val: images/val
names:
0: helmet
1: vest
有关数据集 yaml 格式的更多详细信息,请参阅数据集配置指南。
5. 训练您的 YOLO 模型
转换后的数据集准备就绪后,即可训练 YOLO 模型:
在转换后的 COCO 数据上训练
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # load a pretrained model
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)
yolo detect train model=yolo26n.pt data=my_dataset/dataset.yaml epochs=100 imgsz=640
有关训练技巧和最佳实践,请参阅模型训练指南。
6. 验证您的转换
在训练之前,请抽查一些标签文件,以确认类别 ID 和坐标是否正确:
from pathlib import Path
label_file = Path("my_dataset/labels/train/img_001.txt")
for line in label_file.read_text().strip().splitlines():
parts = line.split()
cls_id = int(parts[0])
coords = [float(v) for v in parts[1:5]]
assert cls_id >= 0, f"Negative class ID {cls_id} — category_id in your JSON may start from 0"
assert all(0 <= v <= 1 for v in coords), f"Coordinates out of [0, 1] range: {coords}"
提示
如果您看到负数类别 ID,您的 COCO JSON 可能使用 category_id 从 0 开始。将所有 category_id JSON 中的值在运行 convert_coco(),因为它将类别 ID 映射为 category_id - 1.
常见问题排查
转换后类别 ID 错误
如果您的模型训练成功但 detect 到错误的物体类别,您可能正在使用 cls91to80=True (默认)在自定义数据集上。这会将您的 category_id 值通过 COCO 91 到 80 的查找表,这仅对标准 COCO 数据集.
解决方案:始终使用 cls91to80=False 用于自定义数据集。
训练期间未找到标签
如果训练显示 WARNING: No labels found 或 0 images, N backgrounds,您的标签文件不在预期的目录中。 convert_coco() 将标签保存到单独的输出目录(例如, save_dir/labels/train/),但 YOLO 期望 labels/ 与...并行 images/ 在您的数据集目录内。
解决方案:移动标签文件以匹配预期的 目录结构。确保 labels/train/ 是...的同级目录 images/train/.
转换期间出现 KeyError
如果您得到 KeyError: 'bbox' 或运行时的类似错误 convert_coco(),您的 labels_dir 可能包含非实例JSON文件(例如, captions_train2017.json),它们具有不同的标注结构。
解决方案:仅放置实例标注JSON文件(例如, instances_train2017.json)在 labels_dir.
转换后标签文件为空
如果转换完成但 .txt 文件为空或缺失,则所有标注可能具有 iscrowd: 1 (常见于 SAM-生成的掩码),或者 边界框 宽度或高度为零。
解决方案:检查您的JSON标注以查找 iscrowd 值。如果使用SAM掩码,请预处理JSON以设置 iscrowd: 0.
转换后的标签中存在类别 ID 空隙
如果标签文件中的类别ID不连续(例如,0、4、9而不是0、1、2),则您的标注工具使用不连续的 category_id 值。
解决方案:验证您的 .txt 文件中的类别ID与 names 字典在 dataset.yaml匹配。如有需要,将ID重新映射为连续值。
有关完整的API详细信息和参数说明,请参阅 convert_coco API参考.
常见问题
如何将 COCO JSON 注释转换为 YOLO 格式?
使用 convert_coco() Ultralytics的函数,用于将COCO JSON标注转换为YOLO .txt 格式。设置 cls91to80=False 用于自定义数据集:
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)
转换后,重新组织您的标签文件,使 labels/ 镜像 images/ 目录,然后创建一个 dataset.yaml 文件。请参阅 分步指南 以了解完整的工作流程。
为什么在 COCO 转换后 YOLO 训练会显示“未找到标签”?
出现这种情况是因为 convert_coco() 将标签保存到其内部的一个子目录中 save_dir/labels/ (例如, save_dir/labels/train/)而不是直接保存到您的数据集的 labels/train/ 伴随 images/train/中。YOLO 要求标签与图像并行存放 — 例如, images/train/img.jpg 需要 labels/train/img.txt。请将转换后的标签移动以匹配此结构。请参阅 修复目录结构.
在 cls91to80 中有什么作用? convert_coco()?
字段 cls91to80 参数控制 COCO category_id 值如何映射到 YOLO 类别 ID。当 True (默认)时,它使用为标准 COCO 数据集设计的查找表,该表包含 80 个具有非连续 ID(1-90)的类别。对于 自定义数据集,请始终设置 cls91to80=False — 这只是从每个 category_id 中减去 1 以创建零索引类别 ID。
我可以直接在 COCO JSON 上训练 YOLO 而无需转换吗?
不适用于当前的 YOLO 训练管道 — 注释必须采用 YOLO .txt 格式,每个图像一个文件。请使用 convert_coco() 首先转换您的 COCO JSON,然后按照此 指南 进行组织和训练。有关更多支持的格式,请参阅 数据集格式.
我可以将 COCO segment 注释转换为 YOLO 格式吗?
是的,使用 use_segments=True 在调用时 convert_coco() 以在转换后的YOLO标签中包含多边形分割掩码。这会生成与以下兼容的标签文件 YOLO分割模型:
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)
如何将 COCO 关键点注释转换为 YOLO 格式?
使用 use_keypoints=True 用于转换COCO关键点标注以进行 姿势估计 训练:
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)
请注意,如果同时 use_segments 和 use_keypoints 都设置为 True,则只有关键点会被写入标签文件 — segment会被静默忽略。