Link to this section如何将 COCO 标注转换为 YOLO 格式#
训练 Ultralytics YOLO 模型需要 YOLO 格式的标注,但许多流行的 标注 工具导出的是 COCO JSON 格式。本指南将向你展示如何将 COCO 标注转换为 YOLO 格式,并开始训练 目标检测、实例分割 和 姿态估计 模型。
如需直接使用 COCO JSON 进行训练而无需生成 .txt 文件,请参阅 Train YOLO on COCO JSON Without Conversion。
Link to this section为什么要从 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, ...](归一化) |
Link to this section快速入门#
转换 COCO 标注并开始训练的最快方法:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/", # directory containing your JSON files
save_dir="my_dataset/converted/", # where to save converted labels
cls91to80=False, # set False for custom datasets (see warning below)
)转换完成后,组织目录结构、创建 dataset.yaml 并 开始训练。请查看下方的完整 分步指南。
默认的 cls91to80=True 仅适用于具有 80 个对象类别的标准 COCO 数据集,它将 91 个不连续的类别 ID 映射到 80 个连续的类别 ID。对于任何自定义数据集,你 必须 设置 cls91to80=False,否则你的类别 ID 将被静默错误地映射,导致模型学习到错误的类别。
Link to this section分步转换指南#
Link to this section准备你的 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" }
]
}Link to this section转换标注#
使用 convert_coco() 函数将你的 COCO JSON 标注转换为 YOLO .txt 格式:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
cls91to80=False,
)convert_coco() 会为每个已标注的图像生成一个 .txt 文件,存入以对应 JSON 文件命名的 labels/ 子目录中,并移除 instances_ 前缀(例如 instances_train.json 会生成 labels/train/)。没有标注的图像会被跳过,且不会生成对应的标签文件,因此 labels/ 目录结构可能无法与所有图像完全对应:
my_dataset/converted/
└── labels/
├── train/ # from instances_train.json
│ ├── img_001.txt
│ └── ...
└── val/ # from instances_val.json
└── ...convert_coco() 绝不会覆盖已有的 save_dir:如果 my_dataset/converted/ 已经存在,再次运行时会将文件写入 my_dataset/converted-2/。请在重新运行前删除之前的输出(或更改 save_dir),否则后续步骤将会读取到旧的标签。
Link to this section组织目录结构#
转换后,标签文件需要放置在图像文件旁边。YOLO 要求 labels/ 目录与 images/ 目录镜像对应:
import shutil
from pathlib import Path
converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")
# convert_coco names each subdirectory after its JSON file (minus the "instances_" prefix),
# so iterate the actual subdirectories instead of assuming "train"/"val".
for src in converted_dir.iterdir():
if not src.is_dir():
continue
dst = dataset_dir / "labels" / src.name
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.yamlLink to this section创建 dataset.yaml#
创建一个 dataset.yaml 配置文件,将你的 COCO 类别映射到 YOLO 类名。此文件告知 YOLO 数据所在位置以及要检测的类别:
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 格式的更多详细信息,请参阅 数据集配置指南。
Link to this section训练你的 YOLO 模型#
准备好转换后的数据集后,训练 YOLO 模型:
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # load a pretrained model
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)有关训练技巧和最佳实践,请参阅 模型训练指南。
Link to this section验证你的转换#
训练前,抽查几个标签文件以确认类别 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}"If you see negative class IDs, your COCO JSON likely uses category_id starting from 0. Add 1 to all category_id values in your JSON before running convert_coco(), since it maps class IDs as category_id - 1.
Link to this section常见问题排查#
Link to this section转换后类别 ID 错误#
如果你的模型可以训练但检测到的对象类别错误,你很可能在自定义数据集上使用了(默认的)cls91to80=True。这会通过 COCO 91 到 80 的查找表映射你的 category_id 值,该表仅适用于标准 COCO 数据集。
解决方法:对于自定义数据集,始终使用 cls91to80=False。
Link to this section训练期间未找到标签#
如果训练时显示 WARNING: No labels found 或 0 images, N backgrounds,说明你的标签文件不在预期的目录下。convert_coco() 将标签保存到独立的输出目录(例如 save_dir/labels/train/),但 YOLO 要求 labels/ 目录与数据集中的 images/ 目录并列。
解决方法:移动标签文件以匹配预期的 目录结构。确保 labels/train/ 是 images/train/ 的兄弟目录。
Link to this section转换期间出现 KeyError#
If you get KeyError: 'bbox' or similar errors when running convert_coco(), your labels_dir likely contains non-instance JSON files (e.g., captions_train2017.json) that have a different annotation structure.
解决方法:仅将实例标注 JSON 文件(例如 instances_train2017.json)放入 labels_dir。
Link to this section转换后标签文件为空#
如果转换完成但 .txt 文件为空或缺失,可能是所有标注都具有 iscrowd: 1(在使用 SAM 生成的掩码时很常见),或者 边界框 的宽度或高度为零。
Solution: Inspect your JSON annotations for iscrowd values. If using SAM masks, preprocess the JSON to set iscrowd: 0.
Link to this section转换后的标签中类别 ID 不连续#
如果标签文件中的类别 ID 不连续(例如 0、4、9 而不是 0、1、2),则说明你的标注工具使用了不连续的 category_id 值。
Solution: Verify the class IDs in your .txt files match the names dictionary in dataset.yaml. Remap IDs to contiguous values if needed.
有关完整的 API 详细信息和参数说明,请参阅 convert_coco API 参考。
Link to this section常见问题解答#
Link to this section如何将 COCO JSON 标注转换为 YOLO 格式?#
使用 Ultralytics 的 convert_coco() 函数将 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 文件。请参阅 分步指南 以了解完整的工作流程。
Link to this section为什么 COCO 转换后 YOLO 训练显示 "No labels found"?#
这是因为 convert_coco() 将标签保存到 save_dir/labels/ 内的子目录中(例如 save_dir/labels/train/),而不是直接保存在数据集的 labels/train/ 中(与 images/train/ 平行)。YOLO 希望标签与图像位置平行——例如,images/train/img.jpg 需要对应的 labels/train/img.txt。请移动你的转换后的标签以匹配此结构。请参阅 修复目录结构。
Link to this sectionWhat does cls91to80 do in convert_coco()?#
The cls91to80 parameter controls how COCO category_id values are mapped to YOLO class IDs. When True (default), it applies the coco91_to_coco80_class() lookup table designed for the standard COCO dataset, which has 80 classes with non-contiguous IDs (1-90). For custom datasets, always set cls91to80=False — this simply subtracts 1 from each category_id to create zero-indexed class IDs.
Link to this section我可以直接在 COCO JSON 上训练 YOLO 而无需转换吗?#
在当前的 YOLO 训练流程中不可以——标注必须采用 YOLO .txt 格式,且每张图像对应一个文件。请先使用 convert_coco() 转换你的 COCO JSON,然后按照此 指南 进行组织和训练。有关支持格式的更多信息,请参阅 数据集格式。
Link to this section我可以将 COCO 分割标注转换为 YOLO 格式吗?#
Yes, use use_segments=True when calling convert_coco() to include polygon segmentation masks in the converted YOLO labels. This produces label files compatible with YOLO segmentation models:
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)Link to this section如何将 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,则只有关键点会被写入标签文件 —— 分割部分将被静默忽略。