YOLO Vision 2026:

Come convertire le annotazioni COCO nel formato YOLO#

L'addestramento dei modelli Ultralytics YOLO richiede annotazioni nel formato YOLO, ma molti strumenti di annotazione diffusi esportano invece nel formato COCO JSON. Questa guida mostra come convertire le annotazioni COCO nel formato YOLO e iniziare ad addestrare modelli di rilevamento degli oggetti, segmentazione delle istanze e stima della posa.

Preferisci saltare la conversione?

Per addestrare direttamente su COCO JSON senza generare file .txt, consulta Addestrare YOLO su COCO JSON senza conversione.

Perché convertire da COCO a YOLO?#

Il formato COCO JSON memorizza tutte le annotazioni in un unico 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 singolo file JSON per tutte le immagini.
  • Gli ID delle classi sono diversi — COCO utilizza valori category_id arbitrari, mentre YOLO richiede ID delle classi indicizzati a partire da zero.
CaratteristicaCOCO JSONYOLO TXT
StrutturaUn singolo 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 delle classicategory_id (può iniziare da qualsiasi numero)Indicizzato a partire da zero (inizia da 0)
SegmentazioneArray di poligoni nel campo segmentationCoordinate dei poligoni dopo l'ID della classe
Keypoint[x, y, visibility, ...] in pixel[x, y, visibility, ...] normalizzati

Avvio rapido#

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

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)
)

Dopo la conversione, organizza la struttura delle directory, crea un dataset.yaml e avvia l'addestramento. Consulta la guida completa passo passo 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; in caso contrario, gli ID delle classi verranno mappati in modo errato senza alcun avviso e il modello apprenderà classi sbagliate.

Guida alla conversione passo passo#

1. Prepara il dataset COCO#

Un dataset tipico in formato COCO esportato dagli strumenti di annotazione presenta 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 annotazioni COCO JSON nel formato .txt di YOLO:

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

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

convert_coco() scrive un file .txt per ogni immagine annotata in una sottodirectory labels/ denominata come ciascun file JSON, rimuovendo il prefisso instances_ (quindi instances_train.json produce labels/train/). Le immagini senza annotazioni vengono ignorate e non ricevono alcun file di etichette, quindi la struttura labels/ potrebbe non rispecchiare tutte le immagini:

my_dataset/converted/
├── images/      # created but left empty
└── labels/
    ├── train/   # from instances_train.json
    │   ├── img_001.txt
    │   └── ...
    └── val/     # from instances_val.json
        └── ...
La nuova esecuzione crea una nuova cartella di output

convert_coco() non sovrascrive mai un save_dir esistente: se my_dataset/converted/ esiste già, una nuova esecuzione scrive invece in my_dataset/converted-2/. Elimina l'output precedente (o modifica save_dir) prima di eseguire nuovamente la procedura, altrimenti i passaggi successivi leggeranno etichette obsolete.

3. Organizza la struttura delle directory#

Dopo la conversione, i file delle etichette devono essere posizionati accanto alle immagini. YOLO si aspetta una directory labels/ che rispecchi la directory 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))

La struttura finale del dataset dovrebbe essere simile a questa:

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 associ le categorie COCO ai nomi delle classi YOLO. Questo file indica a YOLO dove si trovano i 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 ulteriori dettagli sul formato YAML del dataset, consulta la guida alla configurazione del dataset.

5. Addestra il modello YOLO#

Con il dataset convertito pronto, addestra un modello YOLO:

Addestra sui 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 e best practice sull'addestramento, consulta la guida all'addestramento dei modelli.

6. Verifica la conversione#

Prima dell'addestramento, controlla alcuni file di etichette per verificare che gli ID delle classi 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 visualizzi ID di classe negativi, probabilmente il tuo COCO JSON utilizza category_id a partire da 0. Aggiungi 1 a tutti i valori category_id nel JSON prima di eseguire convert_coco(), poiché quest'ultimo mappa gli ID delle classi come category_id - 1.

Risoluzione dei problemi comuni#

ID delle classi errati dopo la conversione#

Se il modello si addestra ma rileva classi di oggetti errate, probabilmente stai usando cls91to80=True (predefinito) su un dataset personalizzato. Questo valore mappa i valori category_id tramite la tabella di corrispondenza da 91 a 80 di COCO, corretta solo per il dataset COCO standard. Un category_id senza un elemento corrispondente in COCO-80 non viene mappato e genera TypeError: must be real number, not NoneType durante la conversione, invece di produrre etichette errate.

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

Nessuna etichetta trovata durante l'addestramento#

Se la scansione delle etichette segnala 0 images, N backgrounds e l'addestramento si interrompe con ValueError: train: No labels found in .../labels/train.cache, i file delle etichette non si trovano nella directory prevista. convert_coco() salva le etichette in una directory di output separata (ad esempio save_dir/labels/train/), ma YOLO si aspetta labels/ allo stesso livello di images/ all'interno della directory del dataset.

Soluzione: sposta i file delle etichette in modo da rispettare la struttura delle directory prevista. Assicurati che labels/train/ sia una directory parallela a images/train/.

KeyError durante la conversione#

Se ricevi KeyError: 'bbox' o errori simili eseguendo convert_coco(), probabilmente labels_dir contiene file JSON non relativi alle istanze (ad esempio captions_train2017.json) con una struttura delle annotazioni diversa.

Soluzione: inserisci nella directory labels_dir solo file JSON di annotazione delle istanze (ad esempio instances_train2017.json).

File delle etichette vuoti dopo la conversione#

Se la conversione termina ma i file .txt sono vuoti o mancanti, tutte le annotazioni potrebbero avere iscrowd: 1 (situazione comune con le maschere generate da SAM), oppure le bounding box potrebbero avere larghezza o altezza pari a zero. L'esecuzione con use_keypoints=True su un'esportazione contenente solo dati di rilevamento produce lo stesso risultato, perché le annotazioni senza un campo keypoints vengono ignorate completamente.

Soluzione: esamina le annotazioni JSON alla ricerca di valori iscrowd. Se usi maschere SAM, preelabora il JSON per impostare iscrowd: 0. Se hai passato use_keypoints=True, verifica che le annotazioni contengano effettivamente keypoints.

Poligoni a forma di riquadro dalle annotazioni delle maschere#

Se use_segments=True registra annotations without a usable polygon, alcune annotazioni non contengono alcun valore segmentation, oppure ne contengono uno che non è una lista di almeno tre coppie di coordinate. Le cause più comuni sono le esportazioni contenenti solo dati di rilevamento, che lasciano il campo mancante o vuoto, e la codifica run-length di COCO ({"counts": ..., "size": ...}), scritta dagli esportatori di bitmask come SAM; anche una lista piatta di coordinate senza una lista di poligoni contenitore, contorni costituiti da uno o due punti e altri valori malformati vengono gestiti allo stesso modo. Un'annotazione conserva i poligoni rimasti e, se non ne rimane alcuno, ricorre a una riga di segmento con la forma della relativa bounding box, così le etichette restano valide ma tali righe non contengono dettagli della maschera.

Soluzione: riesporta le annotazioni con segmentazioni poligonali, decodifica le maschere RLE in poligoni prima di eseguire convert_coco() oppure correggi i valori segmentation malformati.

Intervalli negli ID delle classi nelle etichette convertite#

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

Soluzione: verifica che gli ID delle classi nei file .txt corrispondano al dizionario names in dataset.yaml. Se necessario, rimappa gli ID su valori contigui.

Per i dettagli completi sull'API e la descrizione dei parametri, consulta il riferimento API di convert_coco.

FAQ#

  • 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 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.

  • Questo accade perché convert_coco() salva le etichette in una sottodirectory dentro save_dir/labels/ (ad esempio save_dir/labels/train/) anziché direttamente in labels/train/ del dataset, accanto a images/train/. YOLO si aspetta che le etichette siano parallele alle immagini: ad esempio, images/train/img.jpg deve contenere labels/train/img.txt. Sposta le etichette convertite per rispettare questa struttura. Consulta Correggere la struttura delle directory.

  • Il parametro cls91to80 controlla il modo in cui i valori COCO category_id vengono mappati negli ID delle classi YOLO. Quando True (predefinito), applica la tabella di corrispondenza coco91_to_coco80_class() 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 delle classi indicizzati a partire da zero.

  • Non senza codice personalizzato. La pipeline di addestramento predefinita si aspetta etichette YOLO .txt con un file per immagine; quindi puoi eseguire convert_coco() e seguire questa guida passo passo, oppure creare una sottoclasse del dataset per analizzare COCO JSON al volo — consulta Addestrare YOLO su COCO JSON senza conversione. Per ulteriori informazioni sui formati supportati, consulta i formati dei dataset.

  • Sì, usa use_segments=True quando chiami convert_coco() per includere le maschere di segmentazione poligonali nelle etichette YOLO convertite. In questo modo vengono prodotti file di etichette compatibili con i modelli YOLO di segmentazione:

    from ultralytics.data.converter import convert_coco
    
    convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)
  • Usa use_keypoints=True per convertire le annotazioni dei keypoint COCO per l'addestramento alla stima della posa:

    from ultralytics.data.converter import convert_coco
    
    convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)

    Tieni presente che, se sia use_segments sia use_keypoints sono impostati su True, nei file delle etichette verranno scritti solo i keypoint; i segmenti verranno ignorati senza alcun avviso.

Commenti