Link to this sectionComment convertir des annotations COCO au format YOLO#
L'entraînement de modèles Ultralytics YOLO nécessite des annotations au format YOLO, mais de nombreux outils d'annotation populaires exportent plutôt au format COCO JSON. Ce guide te montre comment convertir tes annotations COCO au format YOLO et commencer à entraîner des modèles de détection d'objets, de segmentation d'instances et d'estimation de pose.
Pour entraîner directement sur COCO JSON sans générer de fichiers .txt, consulte Train YOLO on COCO JSON Without Conversion.
Link to this sectionPourquoi convertir de COCO vers YOLO ?#
Le format COCO JSON stocke toutes les annotations dans un seul fichier, tandis que YOLO utilise un fichier texte par image avec des coordonnées normalisées. La conversion est nécessaire car :
- Les modèles YOLO nécessitent des fichiers d'étiquettes
.txtavec un fichier par image, contenantclass x_center y_center width heighten coordonnées normalisées. - Le COCO JSON utilise des coordonnées en pixels au format
[x_min, y_min, width, height]avec un seul fichier JSON pour toutes les images. - Les ID de classe diffèrent — COCO utilise des valeurs
category_idarbitraires, tandis que YOLO nécessite des ID de classe indexés à zéro.
| Fonctionnalité | COCO JSON | YOLO TXT |
|---|---|---|
| Structure | Fichier JSON unique pour toutes les images | Un fichier .txt par image |
| Format de bbox | [x_min, y_min, width, height] en pixels | class x_center y_center width height normalisés (0-1) |
| ID de classe | category_id (peut commencer à n'importe quel nombre) | Indexés à zéro (commencent à 0) |
| Segmentation | Tableaux de polygones dans le champ segmentation | Coordonnées du polygone après l'ID de classe |
| Keypoints | [x, y, visibility, ...] en pixels | [x, y, visibility, ...] normalisés |
Link to this sectionDémarrage rapide#
La méthode la plus rapide pour convertir des annotations COCO et commencer l'entraînement :
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)
)Après la conversion, organise ta structure de répertoire, crée un dataset.yaml et lance l'entraînement. Consulte le guide étape par étape complet ci-dessous.
La valeur par défaut cls91to80=True est conçue uniquement pour le jeu de données COCO standard avec 80 classes d'objets, qui mappe 91 ID de catégorie non contigus vers 80 ID de classe contigus. Pour tout jeu de données personnalisé, tu dois définir cls91to80=False — sinon, tes ID de classe seront mappés incorrectement de manière silencieuse et ton modèle apprendra de mauvaises classes.
Link to this sectionGuide de conversion étape par étape#
Link to this section1. Prépare ton jeu de données COCO#
Un jeu de données typique au format COCO exporté depuis des outils d'annotation a la structure suivante :
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ ├── img_002.jpg
│ │ └── ...
│ └── val/
│ ├── img_100.jpg
│ └── ...
└── annotations/
├── instances_train.json
└── instances_val.jsonChaque fichier JSON suit la spécification du format de données COCO avec trois champs requis — images, annotations et 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" }
]
}Link to this section2. Convertis les annotations#
Utilise la fonction convert_coco() pour convertir tes annotations COCO JSON au format .txt YOLO :
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
cls91to80=False,
)convert_coco() écrit un fichier .txt par image annotée dans un sous-répertoire labels/ nommé d'après chaque fichier JSON, avec le préfixe instances_ supprimé (donc instances_train.json produit labels/train/). Les images sans annotation sont ignorées et ne reçoivent pas de fichier d'étiquette, donc l'arborescence labels/ peut ne pas refléter chaque image :
my_dataset/converted/
└── labels/
├── train/ # from instances_train.json
│ ├── img_001.txt
│ └── ...
└── val/ # from instances_val.json
└── ...convert_coco() ne remplace jamais un save_dir existant : si my_dataset/converted/ existe déjà, une réexécution écrit dans my_dataset/converted-2/ à la place. Supprime la sortie précédente (ou change le save_dir) avant de réexécuter, sinon les prochaines étapes liront des étiquettes obsolètes.
Link to this section3. Organise la structure de répertoire#
Après la conversion, les fichiers d'étiquettes doivent être placés à côté de tes images. YOLO s'attend à ce qu'un répertoire labels/ reflète le répertoire images/ :
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))Ta structure de jeu de données finale devrait ressembler à :
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ └── ...
│ └── val/
│ └── ...
├── labels/
│ ├── train/
│ │ ├── img_001.txt
│ │ └── ...
│ └── val/
│ └── ...
└── dataset.yamlLink to this section4. Crée dataset.yaml#
Crée un fichier de configuration dataset.yaml qui mappe tes catégories COCO aux noms de classe YOLO. Ce fichier indique à YOLO où se trouvent tes données et quelles classes détecter :
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)Le fichier YAML résultant :
path: /absolute/path/to/my_dataset
train: images/train
val: images/val
names:
0: helmet
1: vestPour plus de détails sur le format YAML du jeu de données, consulte le guide de configuration des jeux de données.
Link to this section5. Entraîne ton modèle YOLO#
Avec ton jeu de données converti prêt, entraîne un modèle 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)Pour des conseils d'entraînement et les meilleures pratiques, consulte le guide d'entraînement des modèles.
Link to this section6. Vérifie ta conversion#
Avant l'entraînement, vérifie quelques fichiers d'étiquettes pour confirmer que les ID de classe et les coordonnées sont corrects :
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}"Si tu vois des ID de classe négatifs, ton COCO JSON utilise probablement un category_id commençant à 0. Ajoute 1 à toutes les valeurs category_id dans ton JSON avant d'exécuter convert_coco(), car il mappe les ID de classe comme category_id - 1.
Link to this sectionDépannage des problèmes courants#
Link to this sectionMauvais ID de classe après conversion#
Si ton modèle s'entraîne mais détecte les mauvaises classes d'objets, tu utilises probablement cls91to80=True (par défaut) sur un jeu de données personnalisé. Cela mappe tes valeurs category_id via la table de recherche COCO 91-vers-80, ce qui n'est correct que pour le jeu de données COCO standard.
Solution : Utilise toujours cls91to80=False pour les jeux de données personnalisés.
Link to this sectionAucune étiquette trouvée pendant l'entraînement#
Si l'entraînement affiche WARNING: No labels found ou 0 images, N backgrounds, tes fichiers d'étiquettes ne sont pas dans le répertoire attendu. convert_coco() enregistre les étiquettes dans un répertoire de sortie séparé (par exemple, save_dir/labels/train/), mais YOLO attend un dossier labels/ parallèle à images/ dans ton répertoire de jeu de données.
Solution : Déplace les fichiers d'étiquettes pour qu'ils correspondent à la structure de répertoire attendue. Assure-toi que labels/train/ est un répertoire frère de images/train/.
Link to this sectionKeyError pendant la conversion#
Si tu obtiens KeyError: 'bbox' ou des erreurs similaires lors de l'exécution de convert_coco(), ton labels_dir contient probablement des fichiers JSON qui ne sont pas des instances (par exemple, captions_train2017.json) et qui ont une structure d'annotation différente.
Solution : Place uniquement les fichiers JSON d'annotation d'instances (par exemple, instances_train2017.json) dans le labels_dir.
Link to this sectionFichiers d'étiquettes vides après conversion#
Si la conversion se termine mais que les fichiers .txt sont vides ou manquants, toutes les annotations peuvent avoir iscrowd: 1 (courant avec les masques générés par SAM), ou les boîtes englobantes ont une largeur ou une hauteur nulle.
Solution : Inspecte tes annotations JSON pour les valeurs iscrowd. Si tu utilises des masques SAM, prétraite le JSON pour définir iscrowd: 0.
Link to this sectionLacunes dans les ID de classe dans les étiquettes converties#
Si les ID de classe dans les fichiers d'étiquettes ne sont pas contigus (par exemple, 0, 4, 9 au lieu de 0, 1, 2), ton outil d'annotation utilise des valeurs category_id non contiguës.
Solution : Vérifie que les ID de classe dans tes fichiers .txt correspondent au dictionnaire names dans dataset.yaml. Remappe les ID vers des valeurs contiguës si nécessaire.
Pour tous les détails sur l'API et les descriptions des paramètres, consulte la référence de l'API convert_coco.
Link to this sectionFAQ#
Link to this sectionComment puis-je convertir des annotations COCO JSON au format YOLO ?#
Utilise la fonction convert_coco() d'Ultralytics pour convertir les annotations COCO JSON au format .txt YOLO. Définis cls91to80=False pour les jeux de données personnalisés :
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)Après la conversion, réorganise tes fichiers d'étiquettes afin que labels/ reflète le répertoire images/, puis crée un fichier dataset.yaml. Consulte le guide étape par étape pour le flux de travail complet.
Link to this sectionPourquoi l'entraînement YOLO affiche-t-il "No labels found" après la conversion COCO ?#
Cela se produit car convert_coco() enregistre les étiquettes dans un sous-répertoire de save_dir/labels/ (par exemple, save_dir/labels/train/) au lieu de le faire directement dans le labels/train/ de ton jeu de données, à côté de images/train/. YOLO s'attend à ce que les étiquettes soient parallèles aux images — par exemple, images/train/img.jpg nécessite labels/train/img.txt. Déplace tes étiquettes converties pour qu'elles correspondent à cette structure. Consulte corriger la structure de répertoire.
Link to this sectionQue fait cls91to80 dans convert_coco() ?#
Le paramètre cls91to80 contrôle comment les valeurs category_id de COCO sont mappées vers les IDs de classe YOLO. Quand il est sur True (par défaut), il applique la table de correspondance coco91_to_coco80_class() conçue pour le COCO dataset standard, qui possède 80 classes avec des IDs non contigus (1-90). Pour les datasets personnalisés, définis toujours cls91to80=False — cela soustrait simplement 1 à chaque category_id pour créer des IDs de classe indexés à zéro.
Link to this sectionPuis-je entraîner YOLO directement sur du COCO JSON sans convertir ?#
Pas avec le pipeline d'entraînement YOLO actuel — les annotations doivent être au format .txt YOLO avec un fichier par image. Utilise d'abord convert_coco() pour convertir ton COCO JSON, puis suis ce guide pour organiser et entraîner. Pour en savoir plus sur les formats pris en charge, consulte formats de jeu de données.
Link to this sectionPuis-je convertir des annotations de segmentation COCO au format YOLO ?#
Oui, utilise use_segments=True lors de l'appel de convert_coco() pour inclure les masques de segmentation polygonale dans les étiquettes YOLO converties. Cela produit des fichiers d'étiquettes compatibles avec les modèles de segmentation YOLO :
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)Link to this sectionComment puis-je convertir des annotations de keypoints COCO au format YOLO ?#
Utilise use_keypoints=True pour convertir les annotations de keypoints COCO pour l'entraînement à l'estimation de pose :
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)Note que si use_segments et use_keypoints sont tous deux définis sur True, seuls les keypoints seront écrits dans les fichiers d'étiquettes — les segments sont ignorés silencieusement.