So konvertierst du COCO-Annotationen in das YOLO-Format#
Für das Training von Ultralytics YOLO-Modellen sind Annotationen im YOLO-Format erforderlich, aber viele beliebte Annotationstools exportieren stattdessen im COCO-JSON-Format. Diese Anleitung zeigt dir, wie du deine COCO-Annotationen in das YOLO-Format konvertierst und mit dem Training von Modellen für Objekterkennung, Instanzsegmentierung und Posenschätzung beginnst.
Um direkt mit COCO JSON zu trainieren, ohne .txt-Dateien zu erzeugen, siehe YOLO mit COCO JSON ohne Konvertierung trainieren.
Warum von COCO zu YOLO konvertieren?#
Das COCO-JSON-Format speichert alle Annotationen in einer einzigen Datei, während YOLO für jedes Bild eine eigene Textdatei mit normalisierten Koordinaten verwendet. Eine Konvertierung ist erforderlich, weil:
- YOLO-Modelle benötigen
.txt-Labeldateien mit einer Datei pro Bild, dieclass x_center y_center width heightin normalisierten Koordinaten enthalten. - COCO JSON verwendet Pixelkoordinaten im
[x_min, y_min, width, height]-Format mit einer einzigen JSON-Datei für alle Bilder. - Die Klassen-IDs unterscheiden sich — COCO verwendet beliebige
category_id-Werte, während YOLO nullbasierte Klassen-IDs benötigt.
| Merkmal | COCO JSON | YOLO TXT |
|---|---|---|
| Struktur | Eine einzelne JSON-Datei für alle Bilder | Eine .txt-Datei pro Bild |
| BBox-Format | [x_min, y_min, width, height] in Pixeln | class x_center y_center width height normalisiert (0–1) |
| Klassen-IDs | category_id (kann mit einer beliebigen Zahl beginnen) | Nullbasiert (beginnt bei 0) |
| Segmentierung | Polygonarrays im Feld segmentation | Polygonkoordinaten nach der Klassen-ID |
| Keypoints | [x, y, visibility, ...] in Pixeln | [x, y, visibility, ...] normalisiert |
Schnellstart#
Der schnellste Weg, COCO-Annotationen zu konvertieren und mit dem Training zu beginnen:
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)
)Ordne nach der Konvertierung deine Verzeichnisstruktur, erstelle eine dataset.yaml und starte das Training. Die vollständige Schritt-für-Schritt-Anleitung findest du weiter unten.
Der Standardwert cls91to80=True ist nur für den standardmäßigen COCO-Datensatz mit 80 Objektklassen vorgesehen. Dabei werden 91 nicht zusammenhängende Kategorie-IDs auf 80 zusammenhängende Klassen-IDs abgebildet. Für jeden benutzerdefinierten Datensatz musst du cls91to80=False setzen — andernfalls werden deine Klassen-IDs unbemerkt falsch zugeordnet und dein Modell lernt die falschen Klassen.
Schritt-für-Schritt-Anleitung zur Konvertierung#
1. COCO-Datensatz vorbereiten#
Ein typischer, aus Annotationstools exportierter Datensatz im COCO-Format hat folgende Struktur:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ ├── img_002.jpg
│ │ └── ...
│ └── val/
│ ├── img_100.jpg
│ └── ...
└── annotations/
├── instances_train.json
└── instances_val.jsonJede JSON-Datei folgt der Spezifikation des COCO-Datenformats mit drei erforderlichen Feldern — images, annotations und 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. Annotationen konvertieren#
Verwende die Funktion convert_coco(), um deine COCO-JSON-Annotationen in das YOLO-.txt-Format zu konvertieren:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
cls91to80=False,
)convert_coco() schreibt für jedes annotierte Bild eine .txt-Datei in ein labels/-Unterverzeichnis, das nach der jeweiligen JSON-Datei benannt ist, wobei das Präfix instances_ entfernt wird (aus instances_train.json wird also labels/train/). Bilder ohne Annotationen werden übersprungen und erhalten keine Labeldatei. Daher muss der labels/-Baum nicht jedes Bild enthalten:
my_dataset/converted/
├── images/ # created but left empty
└── labels/
├── train/ # from instances_train.json
│ ├── img_001.txt
│ └── ...
└── val/ # from instances_val.json
└── ...convert_coco() überschreibt niemals eine vorhandene save_dir: Wenn my_dataset/converted/ bereits existiert, schreibt eine erneute Ausführung stattdessen nach my_dataset/converted-2/. Lösche die vorherige Ausgabe (oder ändere save_dir), bevor du den Vorgang erneut ausführst, da die nächsten Schritte sonst veraltete Labels einlesen.
3. Verzeichnisstruktur organisieren#
Nach der Konvertierung müssen die Labeldateien neben deinen Bildern abgelegt werden. YOLO erwartet ein labels/-Verzeichnis, das die Struktur des images/-Verzeichnisses widerspiegelt:
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))Deine endgültige Datensatzstruktur sollte folgendermaßen aussehen:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ └── ...
│ └── val/
│ └── ...
├── labels/
│ ├── train/
│ │ ├── img_001.txt
│ │ └── ...
│ └── val/
│ └── ...
└── dataset.yaml4. dataset.yaml erstellen#
Erstelle eine dataset.yaml-Konfigurationsdatei, die deine COCO-Kategorien den YOLO-Klassennamen zuordnet. Diese Datei teilt YOLO mit, wo sich deine Daten befinden und welche Klassen erkannt werden sollen:
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)Die resultierende YAML-Datei:
path: /absolute/path/to/my_dataset
train: images/train
val: images/val
names:
0: helmet
1: vestWeitere Informationen zum YAML-Format für Datensätze findest du in der Anleitung zur Datensatzkonfiguration.
5. YOLO-Modell trainieren#
Sobald dein konvertierter Datensatz bereit ist, trainierst du ein YOLO-Modell:
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # load a pretrained model
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)Trainingstipps und bewährte Verfahren findest du in der Anleitung zum Modelltraining.
6. Konvertierung überprüfen#
Überprüfe vor dem Training stichprobenartig einige Labeldateien, um zu bestätigen, dass Klassen-IDs und Koordinaten korrekt sind:
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}"Wenn du negative Klassen-IDs siehst, verwendet dein COCO-JSON wahrscheinlich category_id, das bei 0 beginnt. Addiere vor der Ausführung von convert_coco() zu allen category_id-Werten in deiner JSON-Datei 1, da die Klassen-IDs als category_id - 1 abgebildet werden.
Fehlerbehebung bei häufigen Problemen#
Falsche Klassen-IDs nach der Konvertierung#
Wenn dein Modell zwar trainiert wird, aber falsche Objektklassen erkennt, verwendest du wahrscheinlich cls91to80=True (Standard) für einen benutzerdefinierten Datensatz. Dabei werden deine category_id-Werte über die COCO-91-zu-80-Zuordnungstabelle abgebildet, was nur für den standardmäßigen COCO-Datensatz korrekt ist. Eine category_id ohne entsprechendes COCO-80-Gegenstück wird auf nichts abgebildet und löst während der Konvertierung einen TypeError: must be real number, not NoneType aus, anstatt falsche Labels zu erzeugen.
Lösung: Verwende für benutzerdefinierte Datensätze immer cls91to80=False.
Beim Training wurden keine Labels gefunden#
Wenn der Label-Scan 0 images, N backgrounds meldet und das Training anschließend mit ValueError: train: No labels found in .../labels/train.cache abgebrochen wird, befinden sich deine Labeldateien nicht im erwarteten Verzeichnis. convert_coco() speichert Labels in einem separaten Ausgabeordner (z. B. save_dir/labels/train/), aber YOLO erwartet labels/ parallel zu images/ in deinem Datensatzverzeichnis.
Lösung: Verschiebe die Labeldateien so, dass sie der erwarteten Verzeichnisstruktur entsprechen. Stelle sicher, dass labels/train/ ein Geschwisterverzeichnis von images/train/ ist.
KeyError während der Konvertierung#
Wenn bei der Ausführung von convert_coco() ein KeyError: 'bbox' oder ein ähnlicher Fehler auftritt, enthält dein labels_dir-Verzeichnis wahrscheinlich JSON-Dateien ohne Instanzannotationen (z. B. captions_train2017.json) mit einer anderen Annotationsstruktur.
Lösung: Lege im labels_dir-Verzeichnis nur JSON-Dateien mit Instanzannotationen ab (z. B. instances_train2017.json).
Leere Labeldateien nach der Konvertierung#
Wenn die Konvertierung abgeschlossen ist, aber .txt-Dateien leer sind oder fehlen, enthalten möglicherweise alle Annotationen iscrowd: 1 (häufig bei von SAM erzeugten Masken), oder Bounding Boxes haben eine Breite oder Höhe von null. Die Ausführung mit use_keypoints=True für einen reinen Objekterkennungsexport führt zum gleichen Ergebnis, da Annotationen ohne ein keypoints-Feld vollständig übersprungen werden.
Lösung: Überprüfe deine JSON-Annotationen auf iscrowd-Werte. Wenn du SAM-Masken verwendest, verarbeite die JSON-Datei vorab und setze iscrowd: 0. Wenn du use_keypoints=True übergeben hast, stelle sicher, dass deine Annotationen tatsächlich keypoints enthalten.
Rechteckige Polygone aus Maskenannotationen#
Wenn use_segments=True annotations without a usable polygon protokolliert, enthalten einige Annotationen keinen segmentation-Wert oder keinen Wert, der aus mindestens drei Koordinatenpaaren bestehenden Liste ist. Die üblichen Ursachen sind reine Objekterkennungsexporte, bei denen das Feld fehlt oder leer ist, sowie die COCO-Lauflängenkodierung ({"counts": ..., "size": ...}), die Bitmaskenexporter wie SAM schreiben. Auch eine flache Koordinatenliste ohne umschließende Polygonliste, Umrisse mit einem oder zwei Punkten und andere fehlerhafte Werte werden auf dieselbe Weise behandelt. Eine Annotation behält alle verbleibenden Polygone und verwendet ersatzweise eine Segmentzeile in der Form ihrer Bounding Box, wenn keine Polygone vorhanden sind. Dadurch bleiben die Labels gültig, aber diese Zeilen enthalten keine Maskendetails.
Lösung: Exportiere die Annotationen erneut mit Polygonsegmentierungen, dekodiere die RLE-Masken vor der Ausführung von convert_coco() in Polygone oder korrigiere fehlerhafte segmentation-Werte.
Lücken in Klassen-IDs der konvertierten Labels#
Wenn die Klassen-IDs in den Labeldateien nicht zusammenhängend sind (z. B. 0, 4, 9 statt 0, 1, 2), verwendet dein Annotationstool nicht zusammenhängende category_id-Werte.
Lösung: Überprüfe, ob die Klassen-IDs in deinen .txt-Dateien mit dem names-Wörterbuch in dataset.yaml übereinstimmen. Bilde die IDs bei Bedarf auf zusammenhängende Werte ab.
Die vollständigen API-Details und Parameterbeschreibungen findest du in der API-Referenz zu convert_coco.
FAQ#
Verwende die Funktion
convert_coco()aus Ultralytics, um COCO-JSON-Annotationen in das YOLO-.txt-Format zu konvertieren. Setze für benutzerdefinierte Datensätzecls91to80=False:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)Ordne deine Labeldateien nach der Konvertierung neu an, sodass
labels/die Struktur desimages/-Verzeichnisses widerspiegelt, und erstelle anschließend einedataset.yaml-Datei. Den vollständigen Ablauf findest du in der Schritt-für-Schritt-Anleitung.Das passiert, weil
convert_coco()Labels in einem Unterverzeichnis vonsave_dir/labels/speichert (z. B.save_dir/labels/train/) und nicht direkt imlabels/train/-Verzeichnis deines Datensatzes nebenimages/train/. YOLO erwartet, dass die Labels parallel zu den Bildern liegen — beispielsweise benötigtimages/train/img.jpglabels/train/img.txt. Verschiebe deine konvertierten Labels entsprechend dieser Struktur. Siehe Verzeichnisstruktur korrigieren.Der Parameter
cls91to80steuert, wie COCO-category_id-Werte YOLO-Klassen-IDs zugeordnet werden. WennTrue(Standard) verwendet wird, kommt die für den standardmäßigen COCO-Datensatz entwickelte Zuordnungstabellecoco91_to_coco80_class()zum Einsatz. Dieser Datensatz umfasst 80 Klassen mit nicht zusammenhängenden IDs (1–90). Für benutzerdefinierte Datensätze musst du immercls91to80=Falsesetzen — dadurch wird einfach 1 von jedemcategory_idsubtrahiert, um nullbasierte Klassen-IDs zu erzeugen.Nicht ohne benutzerdefinierten Code. Die standardmäßige Trainingspipeline erwartet YOLO-
.txt-Labels mit einer Datei pro Bild. Führe daher entwederconvert_coco()aus und folge dieser Schritt-für-Schritt-Anleitung, oder leite den Datensatz ab, um COCO JSON während der Laufzeit zu verarbeiten — siehe YOLO mit COCO JSON ohne Konvertierung trainieren. Weitere Informationen zu unterstützten Formaten findest du unter Datensatzformate.Ja, verwende
use_segments=Truebeim Aufruf vonconvert_coco(), um Polygonsegmentierungsmasken in die konvertierten YOLO-Labels einzuschließen. Dadurch entstehen Labeldateien, die mit YOLO-Segmentierungsmodellen kompatibel sind:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)Verwende
use_keypoints=True, um COCO-Keypoint-Annotationen für das Training zur Posenschätzung zu konvertieren:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)Beachte, dass bei
use_segmentsunduse_keypoints, die beide aufTruegesetzt sind, nur Keypoints in die Labeldateien geschrieben werden — Segmente werden stillschweigend ignoriert.