Meet YOLO26: next-gen vision AI.

如何将 COCO 标注转换为 YOLO 格式

训练 Ultralytics YOLO 模型需要使用 YOLO 格式的标注,但许多流行的 标注 工具导出的是 COCO JSON 格式。本指南将向你展示如何将 COCO 标注转换为 YOLO 格式,并开始训练 目标检测实例分割姿态估计 模型。

为什么要从 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 要求使用从 0 开始索引的类别 ID。
特性COCO JSONYOLO TXT
结构所有图像共用一个 JSON 文件每张图像一个 .txt 文件
边界框格式[x_min, y_min, width, height](以像素为单位)class x_center y_center width height(已归一化,范围 0-1)
类别 IDcategory_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 默认设置针对拥有 80 个对象类别的标准 COCO 数据集 设计,它将 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 数据格式 规范,包含三个必需字段 —— imagesannotationscategories

{
    "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,
)

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 数据的位置以及需要检测的类别:

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)

有关训练技巧和最佳实践,请参阅模型训练指南

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}"
提示

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.

常见问题排查

转换后类别 ID 错误

如果模型可以训练但检测到的对象类别错误,说明你可能在自定义数据集上使用了 cls91to80=True(默认值)。这会通过 COCO 91 转 80 的查找表来映射你的 category_id 值,该表仅适用于标准的 COCO 数据集

解决方案:自定义数据集请始终使用 cls91to80=False

训练期间未找到标签

如果训练显示 WARNING: No labels found0 images, N backgrounds,说明你的标签文件不在预期的目录中。convert_coco() 会将标签保存到单独的输出目录(例如 save_dir/labels/train/),但 YOLO 要求 labels/ 目录与数据集目录内的 images/ 目录平行。

解决方案:移动标签文件以符合预期的目录结构。确保 labels/train/images/train/ 的同级目录。

转换期间出现 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.

Solution: Only place instance annotation JSON files (e.g., instances_train2017.json) in the labels_dir.

转换后标签文件为空

如果转换完成但 .txt 文件为空或丢失,说明所有标注可能都具有 iscrowd: 1(在使用 SAM 生成的掩码时很常见),或者边界框的宽度或高度为零。

Solution: Inspect your JSON annotations for iscrowd values. If using SAM masks, preprocess the JSON to set iscrowd: 0.

转换后的标签中存在类别 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 参考

常见问题 (FAQ)

如何将 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 文件。请参阅分步指南获取完整流程。

为什么 COCO 转换后 YOLO 训练显示“未找到标签”?

这是因为 convert_coco() 将标签保存到了 save_dir/labels/ 的子目录(例如 save_dir/labels/train/)中,而不是直接保存到数据集的 labels/train/ 中(与 images/train/ 平行)。YOLO 要求标签与图像平行——例如,images/train/img.jpg 需要对应的 labels/train/img.txt。请移动转换后的标签以匹配此结构。请参阅修复目录结构

What does cls91to80 do in convert_coco()?

cls91to80 参数控制 COCO category_id 值如何映射到 YOLO 类别 ID。当设置为 True(默认值)时,它使用专为标准 COCO 数据集 设计的查找表,该数据集拥有 80 个非连续 ID(1-90)的类别。对于自定义数据集,请始终设置 cls91to80=False —— 这只会从每个 category_id 中减去 1,以创建从 0 开始索引的类别 ID。

可以直接在 COCO JSON 上训练 YOLO 而无需转换吗?

目前的 YOLO 训练流水线不支持这样做——标注必须是 YOLO .txt 格式,且每张图像对应一个文件。请先使用 convert_coco() 转换 COCO JSON,然后按照此指南进行组织和训练。有关支持格式的更多信息,请参阅数据集格式

可以将 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)

如何将 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_segmentsuse_keypoints 都设置为 True,则只有关键点会被写入标签文件——分割信息会被静默忽略。

评论