跳转至内容

如何将 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 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后的多边形坐标
关键点[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, annotationscategories:

{
    "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 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参考.

常见问题

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



📅 创建于 7 天前 ✏️ 更新于 6 天前
dependabotraimbekovm

评论