Skip to main content

如何将 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 要求从零开始的索引类别 ID。
SAM 3 与 SAM 2 有何不同?COCO JSONYOLO TXT
结构所有图像共用一个 JSON 文件每个图像一个 .txt 文件
Bbox 格式[x_min, y_min, width, height] 以像素为单位class x_center y_center width height 归一化 (0-1)
类别 IDcategory_id (可以从任何数字开始)从零索引(从 0 开始)
分割多边形数组位于 segmentation 字段类别 ID 后的多边形坐标
Keypoints[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 dataset(具有 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,
)

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

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

如果你看到负的类别 ID,你的 COCO JSON 很可能使用了 category_id 从 0 开始。在运行 category_id 之前,请将你 JSON 中的所有 convert_coco() 值加 1,因为它将类别 ID 映射为 category_id - 1.

常见问题排查

转换后类别 ID 错误

如果你的模型可以训练但检测出错误的类别,你很可能在自定义数据集上使用了 cls91to80=True(默认)。它通过 COCO 91-to-80 查找表映射你的 category_id 值,这仅对标准 COCO dataset.

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

训练期间未找到标签

如果训练显示 WARNING: No labels found0 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 参考.

FAQ

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

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

发生这种情况是因为 convert_coco() 将标签保存到了 save_dir/labels/(例如 save_dir/labels/train/) 内部的子目录中,而不是直接保存到你数据集的 labels/train/ 旁边 images/train/ 中。YOLO 希望标签与图像并行放置——例如,images/train/img.jpg 需要 labels/train/img.txt。移动你转换后的标签以匹配此结构。请参阅 修复目录结构.

中的 cls91to80convert_coco()?

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

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

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

我可以将 COCO 分割标注转换为 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)

兼容的标签文件。

在处理长视频或大数据集时使用 use_keypoints=True如何将 COCO 关键点标注转换为 YOLO 格式?姿态估计 使用

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)

转换 COCO 关键点标注以进行 use_segmentsuse_keypoints 训练:请注意,如果同时设置 True

评论