Meet YOLO26: next-gen vision AI.

Come convertire le annotazioni COCO nel formato YOLO

L'addestramento dei modelli Ultralytics YOLO richiede annotazioni in formato YOLO, ma molti strumenti di annotazione popolari esportano invece in formato COCO JSON. Questa guida ti mostra come convertire le tue annotazioni COCO nel formato YOLO e iniziare ad addestrare modelli di object detection, instance segmentation e pose estimation.

Perché convertire da COCO a YOLO?

Il formato COCO JSON archivia tutte le annotazioni in un singolo file, mentre YOLO utilizza un file di testo per immagine con coordinate normalizzate. La conversione è necessaria perché:

  • I modelli YOLO richiedono file di etichette .txt con un file per immagine, contenente class x_center y_center width height in coordinate normalizzate.
  • COCO JSON utilizza coordinate in pixel nel formato [x_min, y_min, width, height] con un unico file JSON per tutte le immagini.
  • Gli ID di classe differiscono — COCO usa valori di category_id arbitrari, mentre YOLO richiede ID di classe indicizzati da zero.
CaratteristicaCOCO JSONYOLO TXT
StrutturaSingolo file JSON per tutte le immaginiUn file .txt per immagine
Formato Bbox[x_min, y_min, width, height] in pixelclass x_center y_center width height normalizzato (0-1)
ID di classecategory_id (può iniziare da qualsiasi numero)Indicizzato da zero (inizia da 0)
SegmentazioneArray di poligoni nel campo segmentationCoordinate del poligono dopo l'ID di classe
Keypoints[x, y, visibility, ...] in pixel[x, y, visibility, ...] normalizzato

Avvio rapido

Il modo più veloce per convertire le annotazioni COCO e iniziare l'addestramento:

from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="path/to/annotations/",  # directory containing your JSON files
    save_dir="path/to/output/",  # where to save converted labels
    cls91to80=False,  # IMPORTANT: set False for custom datasets
)

Dopo la conversione, organizza la struttura delle tue directory, crea un file dataset.yaml e avvia l'addestramento. Consulta la guida passo-passo completa qui sotto.

Dataset personalizzati: usa sempre `cls91to80=False`

Il valore predefinito cls91to80=True è progettato solo per il dataset COCO standard con 80 classi di oggetti, che mappa 91 ID di categoria non contigui in 80 ID di classe contigui. Per qualsiasi dataset personalizzato, devi impostare cls91to80=False — altrimenti i tuoi ID di classe verranno mappati erroneamente in modo silenzioso e il tuo modello imparerà classi errate.

Guida passo-passo alla conversione

1. Prepara il tuo dataset COCO

Un tipico dataset in formato COCO esportato da strumenti di annotazione ha la seguente struttura:

my_dataset/
├── images/
│   ├── train/
│   │   ├── img_001.jpg
│   │   ├── img_002.jpg
│   │   └── ...
│   └── val/
│       ├── img_100.jpg
│       └── ...
└── annotations/
    ├── instances_train.json
    └── instances_val.json

Ogni file JSON segue la specifica del formato dati COCO con tre campi obbligatori: images, annotations e 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. Converti le annotazioni

Usa la funzione convert_coco() per convertire le tue annotazioni COCO JSON nel formato .txt di YOLO:

Converti COCO in formato YOLO
from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="my_dataset/annotations/",
    save_dir="my_dataset/converted/",
    cls91to80=False,
)

3. Organizza la struttura delle directory

Dopo la conversione, i file delle etichette devono essere posizionati insieme alle tue immagini. YOLO si aspetta una directory labels/ che rispecchi la directory images/:

import shutil
from pathlib import Path

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

# Move labels next to images for each split
for split in ["train", "val"]:
    src = converted_dir / split  # convert_coco strips "instances_" prefix from JSON filename
    dst = dataset_dir / "labels" / split
    dst.mkdir(parents=True, exist_ok=True)
    for f in src.glob("*.txt"):
        shutil.move(str(f), str(dst / f.name))

La struttura finale del dataset dovrebbe apparire così:

my_dataset/
├── images/
│   ├── train/
│   │   ├── img_001.jpg
│   │   └── ...
│   └── val/
│       └── ...
├── labels/
│   ├── train/
│   │   ├── img_001.txt
│   │   └── ...
│   └── val/
│       └── ...
└── dataset.yaml

4. Crea dataset.yaml

Crea un file di configurazione dataset.yaml che mappi le tue categorie COCO ai nomi delle classi YOLO. Questo file comunica a YOLO dove si trovano i tuoi dati e quali classi rilevare:

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)

Il file YAML risultante:

path: /absolute/path/to/my_dataset
train: images/train
val: images/val
names:
    0: helmet
    1: vest

Per maggiori dettagli sul formato YAML del dataset, consulta la guida alla configurazione del dataset.

5. Addestra il tuo modello YOLO

Con il tuo dataset convertito pronto, addestra un modello YOLO:

Addestra su dati COCO convertiti
from ultralytics import YOLO

model = YOLO("yolo26n.pt")  # load a pretrained model
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)

Per suggerimenti sull'addestramento e best practice, consulta la guida all'addestramento dei modelli.

6. Verifica la tua conversione

Prima dell'addestramento, controlla a campione alcuni file di etichette per confermare che gli ID di classe e le coordinate siano corretti:

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}"
Suggerimento

Se vedi ID di classe negativi, probabilmente il tuo COCO JSON utilizza category_id che parte da 0. Aggiungi 1 a tutti i valori di category_id nel tuo JSON prima di eseguire convert_coco(), poiché la funzione mappa gli ID di classe come category_id - 1.

Risoluzione dei problemi comuni

ID di classe errati dopo la conversione

Se il tuo modello viene addestrato ma rileva classi di oggetti errate, probabilmente stai usando cls91to80=True (impostazione predefinita) su un dataset personalizzato. Questo mappa i tuoi valori di category_id attraverso la tabella di lookup di COCO 91-a-80, che è corretta solo per il dataset COCO standard.

Soluzione: usa sempre cls91to80=False per i dataset personalizzati.

Nessuna etichetta trovata durante l'addestramento

Se l'addestramento mostra WARNING: No labels found o 0 images, N backgrounds, i tuoi file di etichette non si trovano nella directory prevista. convert_coco() salva le etichette in una directory di output separata (es. save_dir/labels/train/), ma YOLO si aspetta labels/ parallelamente a images/ all'interno della directory del tuo dataset.

Soluzione: sposta i file delle etichette per corrispondere alla struttura di directory prevista. Assicurati che labels/train/ sia adiacente a images/train/.

KeyError durante la conversione

Se ricevi KeyError: 'bbox' o errori simili durante l'esecuzione di convert_coco(), probabilmente la tua labels_dir contiene file JSON non di istanza (es. captions_train2017.json) che hanno una struttura di annotazione diversa.

Solution: Only place instance annotation JSON files (e.g., instances_train2017.json) in the labels_dir.

File di etichette vuoti dopo la conversione

Se la conversione viene completata ma i file .txt sono vuoti o mancanti, tutte le annotazioni potrebbero avere iscrowd: 1 (comune con maschere generate da SAM), oppure le bounding box hanno larghezza o altezza pari a zero.

Soluzione: controlla le tue annotazioni JSON per i valori iscrowd. Se utilizzi maschere SAM, pre-elabora il JSON per impostare iscrowd: 0.

Salti negli ID di classe nelle etichette convertite

Se gli ID di classe nei file delle etichette non sono contigui (es. 0, 4, 9 invece di 0, 1, 2), il tuo strumento di annotazione utilizza valori di category_id non contigui.

Soluzione: verifica che gli ID di classe nei tuoi file .txt corrispondano al dizionario names in dataset.yaml. Riassegna gli ID a valori contigui se necessario.

Per dettagli completi sull'API e descrizioni dei parametri, consulta il riferimento dell'API convert_coco.

FAQ

Come posso convertire le annotazioni COCO JSON nel formato YOLO?

Usa la funzione convert_coco() di Ultralytics per convertire le annotazioni COCO JSON nel formato .txt di YOLO. Imposta cls91to80=False per i dataset personalizzati:

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)

Dopo la conversione, riorganizza i tuoi file delle etichette in modo che labels/ rispecchi la directory images/, quindi crea un file dataset.yaml. Consulta la guida passo-passo per il flusso di lavoro completo.

Perché l'addestramento YOLO mostra "No labels found" dopo la conversione COCO?

Questo accade perché convert_coco() salva le etichette in una sottodirectory all'interno di save_dir/labels/ (es. save_dir/labels/train/) anziché direttamente nella directory labels/train/ del tuo dataset accanto a images/train/. YOLO si aspetta che le etichette si trovino parallelamente alle immagini — ad esempio, images/train/img.jpg richiede labels/train/img.txt. Sposta le tue etichette convertite per corrispondere a questa struttura. Consulta correggere la struttura delle directory.

Cosa fa cls91to80 in convert_coco()?

Il parametro cls91to80 controlla come i valori di category_id COCO vengono mappati agli ID di classe YOLO. Quando è True (predefinito), utilizza una tabella di lookup progettata per il dataset COCO standard, che ha 80 classi con ID non contigui (1-90). Per i dataset personalizzati, imposta sempre cls91to80=False — questo sottrae semplicemente 1 da ogni category_id per creare ID di classe indicizzati da zero.

Posso addestrare YOLO direttamente su COCO JSON senza convertire?

Non con l'attuale pipeline di addestramento YOLO: le annotazioni devono essere nel formato .txt di YOLO con un file per immagine. Usa convert_coco() per convertire prima il tuo COCO JSON, quindi segui questa guida per organizzare e addestrare. Per saperne di più sui formati supportati, consulta formati dei dataset.

Posso convertire le annotazioni di segmentazione COCO nel formato YOLO?

Sì, usa use_segments=True quando chiami convert_coco() per includere le maschere di segmentazione poligonali nelle etichette YOLO convertite. Questo produce file di etichette compatibili con i modelli di segmentazione YOLO:

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)

Come converto le annotazioni di keypoint COCO nel formato YOLO?

Usa use_keypoints=True per convertire le annotazioni di keypoint COCO per l'addestramento alla pose estimation:

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)

Nota che se sia use_segments che use_keypoints sono impostati su True, verranno scritti nei file delle etichette solo i keypoint — i segmenti verranno ignorati silenziosamente.

Commenti