COCO-Annotationen ins YOLO-Format konvertieren#
Zum Trainieren von Ultralytics YOLO-Modellen werden Annotationen im YOLO-Format benötigt. Viele gängige Annotationstools exportieren jedoch stattdessen das COCO-JSON-Format. Diese Anleitung zeigt dir, wie du deine COCO-Annotationen ins YOLO-Format konvertierst und mit dem Training von Modellen für Objekterkennung, Instanzsegmentierung und Posenschätzung beginnst.
Informationen zum direkten Training mit COCO-JSON ohne Erstellung von .txt-Dateien findest du unter YOLO mit COCO-JSON ohne Konvertierung trainieren.
Warum von COCO zu YOLO konvertieren?#
Im COCO-JSON-Format werden alle Annotationen in einer einzigen Datei gespeichert, 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: eine Datei pro Bild mitclass x_center y_center width heightin normalisierten Koordinaten. - COCO-JSON verwendet Pixelkoordinaten im Format
[x_min, y_min, width, height]und speichert alle Bilder in einer einzigen JSON-Datei. - Klassen-IDs unterscheiden sich – COCO verwendet beliebige Werte
category_id, während YOLO Klassen-IDs benötigt, die bei null beginnen.
| Merkmal | COCO-JSON | YOLO-TXT |
|---|---|---|
| Struktur | Eine 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) | Bei null beginnend (beginnt bei 0) |
| Segmentierung | Polygon-Arrays 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/", # Verzeichnis mit deinen JSON-Dateien
save_dir="my_dataset/converted/", # Speicherort für konvertierte Labels
cls91to80=False, # Für benutzerdefinierte Datensätze auf False setzen (siehe Warnung unten)
)Nach der Konvertierung organisierst du deine Verzeichnisstruktur, erstellst eine dataset.yaml und startest das Training. Die vollständige Schritt-für-Schritt-Anleitung findest du weiter unten.
Der Standardwert cls91to80=True ist ausschließlich für den standardmäßigen COCO-Datensatz mit 80 Objektklassen vorgesehen. Dabei werden 91 nicht zusammenhängende Kategorie-IDs 80 zusammenhängenden Klassen-IDs zugeordnet. Für jeden benutzerdefinierten Datensatz musst du cls91to80=False festlegen – andernfalls werden deine Klassen-IDs unbemerkt falsch zugeordnet und dein Modell lernt falsche 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 entspricht der Spezifikation des COCO-Datenformats und enthält drei erforderliche Felder: 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-Format .txt 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 Unterverzeichnis labels/, das nach der jeweiligen JSON-Datei benannt ist; das Präfix instances_ wird entfernt (aus instances_train.json wird also labels/train/). Bilder ohne Annotationen werden übersprungen und erhalten keine Label-Datei. Daher muss die Verzeichnisstruktur labels/ 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 vor einer erneuten Ausführung die vorherige Ausgabe oder ändere save_dir, da die nächsten Schritte sonst veraltete Labels einlesen.
3. Verzeichnisstruktur organisieren#
Nach der Konvertierung müssen die Label-Dateien neben den Bildern abgelegt werden. YOLO erwartet ein Verzeichnis labels/, dessen Struktur der des Verzeichnisses images/ entspricht:
import shutil
from pathlib import Path
converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")
# convert_coco benennt jedes Unterverzeichnis nach seiner JSON-Datei (ohne das Präfix "instances_"),
# durchlaufe daher die vorhandenen Unterverzeichnisse, statt "train"/"val" vorauszusetzen.
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 so aussehen:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ └── ...
│ └── val/
│ └── ...
├── labels/
│ ├── train/
│ │ ├── img_001.txt
│ │ └── ...
│ └── val/
│ └── ...
└── dataset.yaml4. dataset.yaml erstellen#
Erstelle eine Konfigurationsdatei dataset.yaml, die deine COCO-Kategorien den YOLO-Klassennamen zuordnet. Diese Datei gibt YOLO an, wo sich deine Daten befinden und welche Klassen erkannt werden sollen:
import json
from pathlib import Path
import yaml
# Kategorien aus deiner COCO-JSON-Datei lesen
with open("my_dataset/annotations/instances_train.json") as f:
coco = json.load(f)
# Klassennamen passend zur Ausgabe von convert_coco erstellen (category_id - 1)
categories = sorted(coco["categories"], key=lambda x: x["id"])
names = {cat["id"] - 1: cat["name"] for cat in categories}
# HINWEIS: convert_coco ordnet Klassen-IDs als category_id - 1 zu. Daher muss category_id
# bei 1 beginnen. Wenn deine Kategorien bei 0 beginnen, addiere zuerst 1 zu jeder ID.
# dataset.yaml erstellen
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 Format der Dataset-YAML-Datei findest du in der Anleitung zur Dataset-Konfiguration.
5. YOLO-Modell trainieren#
Sobald dein konvertierter Datensatz bereit ist, trainierst du ein YOLO-Modell:
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # Vortrainiertes Modell laden
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)Trainingstipps und bewährte Vorgehensweisen findest du in der Anleitung zum Modelltraining.
6. Konvertierung überprüfen#
Überprüfe vor dem Training stichprobenartig einige Label-Dateien, um sicherzustellen, 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 deine COCO-JSON-Datei wahrscheinlich category_id, beginnend bei 0. Addiere vor dem Ausführen von convert_coco() 1 zu allen Werten von category_id in deiner JSON-Datei, da die Funktion Klassen-IDs als category_id - 1 zuordnet.
Häufige Probleme beheben#
Falsche Klassen-IDs nach der Konvertierung#
Wenn dein Modell zwar trainiert wird, aber falsche Objektklassen erkennt, verwendest du wahrscheinlich cls91to80=True (den Standardwert) mit einem benutzerdefinierten Datensatz. Dadurch werden deine Werte für category_id über die COCO-Zuordnungstabelle von 91 auf 80 Klassen abgebildet, die nur für den standardmäßigen COCO-Datensatz korrekt ist. Ein category_id ohne entsprechendes COCO-80-Gegenstück wird keiner Klasse zugeordnet und löst bei der Konvertierung TypeError: must be real number, not NoneType aus, statt falsche Labels zu erzeugen.
Lösung: Verwende für benutzerdefinierte Datensätze immer cls91to80=False.
Beim Training wurden keine Labels gefunden#
Wenn die Label-Suche 0 images, N backgrounds meldet und das Training anschließend mit ValueError: train: No labels found in .../labels/train.cache abbricht, befinden sich deine Label-Dateien nicht im erwarteten Verzeichnis. convert_coco() speichert Labels in einem separaten Ausgabeverzeichnis (z. B. save_dir/labels/train/), aber YOLO erwartet labels/ parallel zu images/ innerhalb deines Datensatzverzeichnisses.
Lösung: Verschiebe die Label-Dateien so, dass sie der erwarteten Verzeichnisstruktur entsprechen. Achte darauf, dass labels/train/ und images/train/ im selben übergeordneten Verzeichnis liegen.
KeyError bei der Konvertierung#
Wenn beim Ausführen von convert_coco() ein KeyError: 'bbox'-Fehler oder ein ähnlicher Fehler auftritt, enthält dein labels_dir wahrscheinlich JSON-Dateien, die keine Instanz-Annotationen enthalten (z. B. captions_train2017.json) und eine andere Annotationsstruktur haben.
Lösung: Lege im labels_dir ausschließlich JSON-Dateien mit Instanz-Annotationen ab (z. B. instances_train2017.json).
Leere Label-Dateien nach der Konvertierung#
Wenn die Konvertierung abgeschlossen ist, aber .txt-Dateien leer sind oder fehlen, haben alle Annotationen möglicherweise iscrowd: 1 (häufig bei mit SAM erzeugten Masken), oder Bounding Boxes haben eine Breite oder Höhe von null. Dasselbe Ergebnis erhältst du, wenn du use_keypoints=True für einen Export verwendest, der nur Erkennungsdaten enthält, da Annotationen ohne das Feld keypoints vollständig übersprungen werden.
Lösung: Prüfe deine JSON-Annotationen auf Werte für iscrowd. Wenn du SAM-Masken verwendest, bearbeite die JSON-Datei vorab, um iscrowd: 0 festzulegen. Wenn du use_keypoints=True übergeben hast, stelle sicher, dass deine Annotationen tatsächlich keypoints enthalten.
Rechteckige Polygone aus Masken-Annotationen#
Wenn use_segments=True annotations without a usable polygon protokolliert, enthalten einige Annotationen keinen Wert für segmentation oder keinen Wert, der aus mindestens drei Koordinatenpaaren besteht. Häufige Ursachen sind reine Erkennungsexporte, bei denen das Feld fehlt oder leer ist, sowie die COCO-Lauflängenkodierung ({"counts": ..., "size": ...}), die von Bitmasken-Exportern wie SAM geschrieben wird. Auch eine flache Koordinatenliste ohne umschließende Polygonliste, Umrisse mit nur einem oder zwei Punkten und andere fehlerhafte Werte werden auf dieselbe Weise behandelt. Eine Annotation behält alle gültigen Polygone und greift, wenn keine vorhanden sind, auf eine Segmentzeile in Form ihrer Bounding Box zurück. So bleiben die Labels gültig, enthalten in diesen Zeilen jedoch keine Maskendetails.
Lösung: Exportiere die Annotationen erneut mit Polygonsegmentierungen, dekodiere die RLE-Masken vor dem Ausführen von convert_coco() in Polygone oder korrigiere fehlerhafte Werte von segmentation.
Lücken bei Klassen-IDs in konvertierten Labels#
Wenn Klassen-IDs in den Label-Dateien nicht zusammenhängend sind (z. B. 0, 4, 9 statt 0, 1, 2), verwendet dein Annotationstool nicht zusammenhängende Werte für category_id.
Lösung: Prüfe, ob die Klassen-IDs in deinen .txt-Dateien mit dem Wörterbuch names in dataset.yaml übereinstimmen. Ordne die IDs bei Bedarf zusammenhängenden Werten zu.
Die vollständigen API-Details und Parameterbeschreibungen findest du in der API-Referenz zu convert_coco.
Häufig gestellte Fragen#
Verwende die Funktion
convert_coco()von Ultralytics, um COCO-JSON-Annotationen ins YOLO-Format.txtzu konvertieren. Lege für benutzerdefinierte Datensätzecls91to80=Falsefest:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)Ordne nach der Konvertierung deine Label-Dateien neu an, sodass
labels/der Struktur des Verzeichnissesimages/entspricht, und erstelle anschließend eine Dateidataset.yaml. Den vollständigen Arbeitsablauf 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 im Datensatzverzeichnis unterlabels/train/nebenimages/train/. YOLO erwartet, dass Labels parallel zu den Bildern liegen – beispielsweise benötigtimages/train/img.jpgeinlabels/train/img.txt. Verschiebe deine konvertierten Labels so, dass sie dieser Struktur entsprechen. Eine Anleitung findest du unter Verzeichnisstruktur korrigieren.Der Parameter
cls91to80steuert, wie COCO-Werte fürcategory_idYOLO-Klassen-IDs zugeordnet werden. BeiTrue(Standardwert) wird die Zuordnungstabellecoco91_to_coco80_class()angewendet, die für den standardmäßigen COCO-Datensatz mit 80 Klassen und nicht zusammenhängenden IDs (1–90) vorgesehen ist. Für benutzerdefinierte Datensätze legst du immercls91to80=Falsefest – dadurch wird einfach von jedemcategory_id1 abgezogen, um bei 0 beginnende Klassen-IDs zu erhalten.Nicht ohne benutzerdefinierten Code. Die standardmäßige Trainingspipeline erwartet YOLO-Labels im Format
.txtmit einer Datei pro Bild. Führe daher entwederconvert_coco()aus und befolge diese Schritt-für-Schritt-Anleitung, oder leite den Datensatz ab, um die COCO-JSON-Datei direkt während der Ausführung einzulesen – siehe YOLO mit COCO-JSON ohne Konvertierung trainieren. Weitere Informationen zu unterstützten Formaten findest du unter Datensatzformate.Ja. Verwende beim Aufruf von
convert_coco()use_segments=True, um Polygonsegmentierungsmasken in die konvertierten YOLO-Labels aufzunehmen. Dadurch entstehen Label-Dateien, 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 Pose-Schätzung zu konvertieren:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)Beachte: Wenn sowohl
use_segmentsals auchuse_keypointsaufTruegesetzt sind, werden nur Keypoints in die Label-Dateien geschrieben; Segmente werden ohne Hinweis ignoriert.