COCOアノテーションをYOLOフォーマットに変換する方法#
Ultralytics YOLO モデルの学習には YOLO フォーマットのアノテーションが必要ですが、多くの一般的なアノテーションツールは代わりに COCO JSON フォーマットでエクスポートします。このガイドでは、COCO アノテーションを YOLO フォーマットに変換し、物体検出、インスタンスセグメンテーション、および姿勢推定モデルの学習を開始する方法を説明します。
.txt ファイルを生成せずに COCO JSON で直接学習を行うには、変換を行わずに COCO JSON で YOLO を学習するを参照してください。
なぜCOCOからYOLOに変換するのか?#
COCO JSON フォーマットはすべてのアノテーションを単一のファイルに格納しますが、YOLO は画像ごとに正規化された座標を持つ 1 つのテキストファイルを使用します。変換が必要な理由は以下の通りです:
- YOLO モデルには
.txtラベルファイルが必要であり、画像ごとに 1 つのファイルにclass x_center y_center width heightが正規化された座標で含まれています。 - COCO JSON はピクセル座標を使用し、すべての画像に対して単一の JSON ファイル内の
[x_min, y_min, width, height]フォーマットで格納されます。 - クラス ID が異なる — COCO は任意の
category_id値を使用しますが、YOLO は 0 から始まるインデックスのクラス ID を必要とします。
| 機能 | COCO JSON | YOLO TXT |
|---|---|---|
| 構造 | 全画像に対して単一のJSONファイル | 画像ごとに 1 つの .txt ファイル |
| Bboxフォーマット | ピクセル単位の [x_min, y_min, width, height] | 正規化された class x_center y_center width height (0-1) |
| クラスID | category_id (任意の番号から開始可能) | 0から始まるインデックス(0から開始) |
| セグメンテーション | segmentation フィールド内のポリゴン配列 | クラスIDの後のポリゴン座標 |
| キーポイント | ピクセル単位の [x, y, visibility, ...] | 正規化された [x, y, visibility, ...] |
クイックスタート#
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 が暗黙的に誤ってマッピングされ、モデルが誤ったクラスを学習することになります。
ステップバイステップ変換ガイド#
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 data format 仕様に準拠しており、images、annotations、categories の 3 つの必須フィールドが含まれています:
{
"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" }
]
}アノテーションの変換#
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() は、アノテーション付き画像 1 枚につき 1 つの .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 を変更する)か、次のステップで古いラベルが読み込まれることになります。
ディレクトリ構造の整理#
変換後、ラベルファイルを画像と同じ場所に配置する必要があります。YOLO では、images/ ディレクトリをミラーリングする labels/ ディレクトリが必要です:
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.yamldataset.yamlの作成#
COCO カテゴリを YOLO クラス名にマッピングする dataset.yaml 設定ファイルを作成します。このファイルは、データがどこにあり、どのクラスを検出すべきかを 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 フォーマットの詳細については、データセット設定ガイドを参照してください。
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)学習のヒントとベストプラクティスについては、モデル学習ガイドを参照してください。
変換の検証#
トレーニングの前に、いくつかのラベルファイルをチェックして、クラス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 が 0 から始まる category_id を使用している可能性があります。convert_coco() はクラス ID を category_id - 1 としてマッピングするため、実行する前に JSON 内のすべての category_id の値に 1 を加算してください。
一般的な問題のトラブルシューティング#
変換後のクラスIDの誤り#
モデルの学習は成功するが誤ったオブジェクトクラスを検出する場合、カスタムデータセットで cls91to80=True(デフォルト)を使用している可能性があります。これにより、category_id 値が COCO の 91-to-80 ルックアップテーブルを介してマッピングされますが、これは標準の COCO データセットでのみ正しく機能します。
解決策: カスタムデータセットには常に cls91to80=False を使用してください。
トレーニング中にラベルが見つからない#
トレーニングで WARNING: No labels found または 0 images, N backgrounds が表示される場合、ラベルファイルが想定されるディレクトリにありません。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 を持っている(SAM 生成マスクによく見られます)、またはバウンディングボックスの幅または高さがゼロである可能性があります。
解決策: JSON アノテーションの iscrowd 値を確認してください。SAM マスクを使用している場合は、JSON を前処理して iscrowd: 0 を設定してください。
マスクアノテーションから作成されたボックス状の多角形#
use_segments=True が annotations without a usable polygon をログに出力する場合、一部のアノテーションには segmentation の値が含まれていないか、少なくとも3つの座標ペアのリストになっていない値が含まれています。一般的な原因は、検出のみのエクスポートによってフィールドが欠落または空になること、および SAM などのビットマスクエクスポーターが書き込む COCO のランレングス符号化 ({"counts": ..., "size": ...}) です。囲みポリゴンリストのないフラットな座標リスト、1点および2点の輪郭、その他の不正な形式の値も同様に処理されます。アノテーションは残されたポリゴンを保持し、何も残っていない場合はバウンディングボックスの形をしたセグメント行にフォールバックするため、ラベルは有効なままですが、それらの行にはマスクの詳細が含まれません。
解決策: ポリゴンセグメンテーションでアノテーションを再エクスポートするか、convert_coco() を実行する前に RLE マスクをポリゴンにデコードするか、不正な segmentation の値を修正してください。
変換されたラベル内のクラスIDの欠落#
ラベルファイルのクラス ID が非連続(例:0, 1, 2 ではなく 0, 4, 9)である場合、アノテーションツールが非連続な category_id 値を使用しています。
解決策: .txt ファイル内のクラス ID が dataset.yaml 内の names ディクショナリと一致していることを確認します。必要に応じて、ID を連続した値に再マッピングしてください。
完全な API の詳細とパラメータの説明については、convert_coco API リファレンスを参照してください。
よくある質問 (FAQ)#
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()が、データセットのlabels/train/内のimages/train/と並行して直接保存するのではなく、save_dir/labels/内のサブディレクトリ(例:save_dir/labels/train/)にラベルを保存するため発生します。YOLO では、ラベルが画像と並行して配置されている必要があります。たとえば、images/train/img.jpgにはlabels/train/img.txtが必要です。この構造に一致するように変換されたラベルを移動してください。ディレクトリ構造の修正を参照してください。cls91to80パラメータは、COCO のcategory_idの値が YOLO クラス ID にどのようにマッピングされるかを制御します。True(デフォルト)の場合、非連続の ID(1〜90)を持つ 80 のクラスを持つ標準の COCO dataset 用に設計されたcoco91_to_coco80_class()ルックアップテーブルが適用されます。カスタムデータセットの場合は、常にcls91to80=Falseを設定してください。これにより、各category_idから単に 1 が減算され、0 から始まるインデックスのクラス ID が作成されます。現在の YOLO 学習パイプラインではできません。アノテーションは、画像ごとに 1 つのファイルを持つ YOLO
.txtフォーマットである必要があります。まずconvert_coco()を使用して COCO JSON を変換し、その後このガイドに従って整理と学習を行ってください。サポートされているフォーマットの詳細については、データセットフォーマットを参照してください。はい、
convert_coco()を呼び出す際にuse_segments=Trueを使用すると、変換された YOLO ラベルにポリゴンセグメンテーションマスクを含めることができます。これにより、YOLO segmentation models と互換性のあるラベルファイルが生成されます:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)ポーズ推定トレーニング用の COCO キーポイントアノテーションを変換するには、
use_keypoints=Trueを使用します: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に設定されている場合、キーポイントのみがラベルファイルに書き込まれ、セグメントは暗黙的に無視されることに注意してください。