Ultralytics YOLO27: ウェイティングリストに登録してください。
はじめる

COCOアノテーションをYOLO形式に変換する方法#

Ultralytics YOLOモデルの学習にはYOLO形式のアノテーションが必要ですが、多くの一般的なアノテーションツールでは、代わりにCOCO JSON形式でエクスポートされます。このガイドでは、COCOアノテーションをYOLO形式に変換し、物体検出、インスタンスセグメンテーション、ポーズ推定モデルの学習を開始する方法を説明します。

変換を省略しますか?

.txtファイルを生成せずにCOCO JSONを直接使って学習するには、変換せずにCOCO JSONでYOLOを学習するを参照してください。

COCOからYOLOに変換する理由#

COCO JSON形式ではすべてのアノテーションが1つのファイルに保存されますが、YOLOでは画像ごとに1つのテキストファイルを使用し、座標は正規化されています。変換が必要な理由は次のとおりです。

  • YOLOモデルでは、画像ごとに1つの.txtラベルファイルが必要です。各ファイルには、正規化座標で表したclass x_center y_center width heightが含まれます。
  • COCO JSONではピクセル座標を使用します。すべての画像を1つのJSONファイルにまとめた[x_min, y_min, width, height]形式です。
  • クラスIDが異なります — COCOでは任意のcategory_id値が使われますが、YOLOでは0始まりのクラスIDが必要です。
機能COCO JSONYOLO TXT
構造すべての画像を1つのJSONファイルに格納画像ごとに1つの.txtファイル
BBox形式ピクセル単位の[x_min, y_min, width, height]class x_center y_center width heightで正規化(0~1)
クラスIDcategory_id(任意の番号から開始できます)0始まり(0から開始)
セグメンテーションsegmentationフィールド内のポリゴン配列またはRLEマスククラスIDの後に続くポリゴン座標
キーポイントピクセル単位の[x, y, visibility, ...][x, y, visibility, ...]で正規化

クイックスタート#

COCOアノテーションを変換してトレーニングを開始する最も簡単な方法:

from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="my_dataset/annotations/",  # JSONファイルを含むディレクトリ
    save_dir="my_dataset/converted/",  # 変換済みラベルの保存先
    cls91to80=False,  # カスタムデータセットではFalseに設定してください(下記の警告を参照)
)

変換後、ディレクトリ構造を整理し、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ファイルは、必須の3つのフィールド(images、annotations、categories)を含むCOCOデータ形式の仕様に従います:

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

convert_coco()は、アノテーション付き画像ごとに1つの.txtファイルを、各JSONファイル名に基づいたlabels/サブディレクトリに書き込みます。その際、instances_プレフィックスは削除されます(つまり、instances_train.jsonからlabels/train/が生成されます)。アノテーションのない画像はスキップされ、ラベルファイルも作成されないため、labels/ツリーにはすべての画像が含まれるとは限りません:

my_dataset/converted/
├── images/      # created but left empty
└── 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を変更してください。そうしないと、次の手順で古いラベルが読み込まれます。

3. ディレクトリ構造を整理する#

変換後、ラベルファイルを画像と同じ場所に配置する必要があります。YOLOでは、labels/ディレクトリがimages/ディレクトリと同じ構造になっている必要があります:

import shutil
from pathlib import Path

converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")

# convert_cocoは各サブディレクトリにJSONファイル名(「instances_」プレフィックスを除く)を付けます。
# そのため、「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.yaml

4. dataset.yamlを作成する#

COCOカテゴリをYOLOクラス名に対応付けるdataset.yaml設定ファイルを作成します。このファイルで、YOLOにデータの場所と検出対象のクラスを指定します:

import json
from pathlib import Path

from ultralytics.utils import YAML

# COCO JSONからカテゴリを読み込む
with open("my_dataset/annotations/instances_train.json") as f:
    coco = json.load(f)

# convert_cocoの出力に合うクラス名を作成する(category_id - 1)
categories = sorted(coco["categories"], key=lambda x: x["id"])
names = {cat["id"] - 1: cat["name"] for cat in categories}
# 注意: convert_cocoはクラスIDをcategory_id - 1として対応付けるため、category_idは1から
# 開始する必要があります。カテゴリが0から始まる場合は、各IDに1を加えてください。

# dataset.yamlを作成する
dataset = {
    "path": str(Path("my_dataset").resolve()),
    "train": "images/train",
    "val": "images/val",
    "names": names,
}

YAML.save("my_dataset/dataset.yaml", dataset)

生成される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")  # 事前トレーニング済みモデルを読み込む
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から始まっている可能性があります。convert_coco()を実行する前に、JSON内のすべてのcategory_id値に1を加えてください。これは、クラスIDをcategory_id - 1として対応付けるためです。

よくある問題のトラブルシューティング#

変換後のクラスIDが誤っている#

モデルの学習はできても、誤った物体クラスを検出する場合は、カスタムデータセットでcls91to80=True(デフォルト)を使用している可能性があります。この設定では、category_idの値がCOCOの91から80へのルックアップテーブルを通じてマッピングされますが、これは標準のCOCOデータセットでのみ正しい処理です。COCO-80に対応するクラスがないcategory_idは何にもマッピングされず、誤ったラベルを生成するのではなく、変換時にTypeError: must be real number, not NoneTypeが発生します。

解決策: カスタムデータセットでは、必ずcls91to80=Falseを使用してください。

トレーニング中にラベルが見つからない#

ラベルスキャンで0 images, N backgroundsと報告され、その後トレーニングがValueError: train: No labels found in .../labels/train.cacheで中断する場合、ラベルファイルが想定されたディレクトリにありません。convert_coco()はラベルを別の出力ディレクトリ(例: save_dir/labels/train/)に保存しますが、YOLOではデータセットディレクトリ内でimages/と並列になるようにlabels/を配置する必要があります。

解決策: 想定されるディレクトリ構造に合うようにラベルファイルを移動します。labels/train/がimages/train/と同じ階層にあることを確認してください。

変換中のKeyError#

convert_coco()の実行時にKeyError: 'bbox'などのエラーが発生する場合、labels_dirに、異なるアノテーション構造を持つインスタンス以外のJSONファイル(例: captions_train2017.json)が含まれている可能性があります。

解決策: インスタンスアノテーションJSONファイル(例: instances_train2017.json)のみをlabels_dirに配置してください。

変換後のラベルファイルが空#

変換が完了しても.txtファイルが空、または見つからない場合は、すべてのアノテーションにiscrowd: 1が設定されている可能性があります。この値はconvert_coco()によってスキップされます(たとえば、CVATではマスクアノテーションがcrowd領域としてエクスポートされます)。または、バウンディングボックスの幅または高さが0になっています。検出のみのエクスポートに対してuse_keypoints=Trueを指定して実行した場合も、keypointsフィールドのないアノテーションはすべてスキップされるため、同じ結果になります。

解決策: JSONアノテーションのiscrowdの値を確認してください。CVATのマスクエクスポートのように、crowdフラグが付いた各マスクが単一のオブジェクトを囲んでいる場合は、iscrowd: 0を設定してuse_segments=TrueがRLEマスクを変換できるようにします。複数のオブジェクトを含む実際のcrowd領域にはフラグを付けたままにしてください。use_keypoints=Trueを渡した場合は、アノテーションに実際にkeypointsが含まれていることを確認してください。

マスクアノテーションからボックス形状のポリゴンが生成される#

use_segments=Trueがannotations without a usable polygonをログに出力する場合、一部のアノテーションにsegmentationの値が設定されていません。この値はCOCOのランレングス符号化({"counts": ..., "size": ...})で、sizeが画像の[height, width]と一致しないもの、マスクが空のもの、または3点では輪郭を描けないほど小さい領域や細い領域しか含まないものも該当します。また、RLEでも3組以上の座標ペアからなるリストでもない値も該当します。よくある原因は検出のみのエクスポートで、フィールドが欠落または空になります。ポリゴンリストで囲まれていない平坦な座標リスト、1点または2点だけの輪郭、その他の不正な値も同様に処理されます。アノテーションには有効なポリゴンが残っていればそのポリゴンが保持され、残っていなければバウンディングボックスと同じ形状のセグメント行が代わりに使われます。そのためラベルは有効なままですが、該当する行にマスクの詳細は含まれません。

countsが欠落している、またはデコードできないRLE値(切り詰められた文字列や、合計がsizeにならないランなど)がある場合、フォールバックは行われず、エラーで変換が停止します。

解決策: ポリゴンまたはRLEセグメンテーションを含めてアノテーションを再エクスポートするか、不正なsegmentationの値を修正してください。

変換済みラベルのクラスIDに欠番がある#

ラベルファイル内のクラスIDが連続していない(例: 0、1、2ではなく0、4、9)場合、アノテーションツールが連続していないcategory_id値を使用しています。

解決策: .txtファイル内のクラスIDが、dataset.yaml内のnames辞書と一致することを確認してください。必要に応じて、IDを連続した値に再割り当てします。

APIの詳細とパラメーターの説明については、convert_coco APIリファレンスをご覧ください。

よくある質問#

  • 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ファイルを作成します。ワークフロー全体については、手順ガイドをご覧ください。

  • これは、convert_coco()がラベルをsave_dir/labels/内のサブディレクトリ(例: save_dir/labels/train/)に保存し、データセットのlabels/train/内でimages/train/と並ぶ場所に直接保存しないためです。YOLOでは、画像と並列にラベルを配置する必要があります。たとえば、images/train/img.jpgにはlabels/train/img.txtが必要です。この構造に合うように変換済みラベルを移動してください。ディレクトリ構造の修正もご覧ください。

  • cls91to80パラメーターは、COCOのcategory_id値をYOLOのクラスIDに対応付ける方法を制御します。True(デフォルト)の場合、80クラスと連続していないID(1~90)を持つ標準のCOCOデータセット向けに設計されたcoco91_to_coco80_class()ルックアップテーブルが適用されます。カスタムデータセットでは、常にcls91to80=Falseを設定してください。これにより、各category_idから1を引き、0始まりのクラスIDを作成します。

  • カスタムコードなしではできません。デフォルトのトレーニングパイプラインは、画像ごとに1つのファイルを持つYOLOの.txtラベルを想定しています。そのため、convert_coco()を実行してこの手順ガイドに従うか、データセットをサブクラス化してCOCO JSONをその場で解析してください。詳しくは変換せずにCOCO JSONでYOLOをトレーニングするをご覧ください。対応形式については、データセット形式をご覧ください。

  • はい、変換後のYOLOラベルにセグメンテーションマスクを含めるには、convert_coco()の呼び出し時にuse_segments=Trueを使用してください。ポリゴンセグメンテーションはそのまま変換され、ランレングス符号化(RLE)マスクは圧縮形式、非圧縮形式のいずれもfaster-coco-evalでデコードされ(JSONファイルにRLEマスクが含まれている場合は自動的にインストールされます)、各領域の外側の輪郭に変換されます。複数のポリゴンまたはマスク領域に分割されたオブジェクトは1つのポリゴン行に統合されます。また、YOLOのポリゴンでは穴を表現できないため、マスクの穴は塗りつぶされます。crowdアノテーション(iscrowd: 1)はスキップされます。これにより、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のキーポイントアノテーションを変換します:

    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に設定されている場合、ラベルファイルにはキーポイントのみが書き込まれ、セグメントは警告なしで無視されます。

コントリビューター
GLglenn-jocher5RAraimbekovm5DEDevulapalli Naga Sri Vaishnavi1PDpderrenger1

コメント

質問したり、結果を共有したり、ほかの人をサポートしたりできます。