Skip to main content

Come convertire le annotazioni COCO in formato YOLO

Addestrare 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 in formato YOLO e iniziare ad addestrare object detection, instance segmentation, e pose estimation ben addestrati.

Perché convertire da COCO a YOLO?

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

  • I modelli YOLO richiedono .txt file di etichetta con un file per immagine, contenente class x_center y_center width height in coordinate normalizzate.
  • COCO JSON usa coordinate in pixel in [x_min, y_min, width, height] con un singolo file JSON per tutte le immagini.
  • Gli ID delle classi differiscono — COCO usa valori category_id arbitrari, mentre YOLO richiede ID di classe indicizzati a zero.
CaratteristicaCOCO JSONYOLO TXT
StrutturaSingolo file JSON per tutte le immaginiUn .txt file per immagine
Formato Bbox[x_min, y_min, width, height] in pixelclass x_center y_center width height normalizzato (0-1)
ID Classecategory_id (può iniziare da qualsiasi numero)Indicizzato a zero (inizia da 0)
segmentazioneArray di poligoni nel campo segmentationCoordinate del poligono dopo l'ID 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 della tua directory, crea un file dataset.yaml, e inizia l'addestramento. Vedi la guida passo dopo passo completa qui sotto.

Dataset personalizzati: usa sempre `cls91to80=False`

Il metodo cls91to80=True il valore predefinito è progettato solo per lo standard dataset COCO con 80 classi di oggetti, che mappa 91 ID di categoria non contigui in 80 ID di classe contigui. Per qualsiasi dataset personalizzato, devi Devi impostare cls91to80=False — altrimenti gli ID delle tue classi verranno mappati in modo errato senza avvisi e il tuo modello imparerà classi sbagliate.

Guida alla conversione passo dopo passo

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 il comando convert_coco() funzione per convertire le tue annotazioni COCO JSON nel formato YOLO .txt :

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 della directory

Dopo la conversione, i file di etichetta 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))

Il tuo struttura del dataset finale 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 dataset.yaml file di configurazione che mappa le tue categorie COCO ai nomi delle classi YOLO. Questo file dice 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, vedi 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, vedi la guida all'addestramento del modello.

6. Verifica la tua conversione

Prima dell'addestramento, controlla a campione alcuni file di etichetta per confermare 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 vedi ID di classe negativi, probabilmente il tuo COCO JSON usa category_id partendo da 0. Aggiungi 1 a tutti i valori category_id nel tuo JSON prima di eseguire convert_coco(), poiché mappa gli ID di classe come category_id - 1.

Risoluzione dei problemi comuni

ID di classe errati dopo la conversione

Se il tuo modello si addestra ma rileva classi di oggetti errate, probabilmente stai usando cls91to80=True (predefinito) su un dataset personalizzato. Questo mappa i tuoi valori category_id attraverso la tabella di ricerca COCO 91-to-80, che è corretta solo per lo standard dataset COCO.

Soluzione: Usa sempre cls91to80=False per 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 etichetta non sono nella directory prevista. convert_coco() salva le etichette in una directory di output separata (es. save_dir/labels/train/), ma YOLO si aspetta labels/ parallela a images/ all'interno della directory del tuo dataset.

Soluzione: Sposta i file di etichetta per farli corrispondere alla struttura della directory prevista. Assicurati che labels/train/ è un elemento fratello di images/train/.

KeyError durante la conversione

Se ricevi KeyError: 'bbox' o errori simili durante l'esecuzione di convert_coco(), il tuo labels_dir probabilmente contiene file JSON che non sono istanze (ad esempio, captions_train2017.json) che hanno una struttura di annotazione diversa.

Soluzione: Inserisci solo file JSON di annotazione di istanze (ad esempio, instances_train2017.json) nella 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 le maschere generate da SAM), oppure i bounding boxes hanno larghezza o altezza pari a zero.

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

Lacune negli ID classe nelle etichette convertite

Se gli ID classe nei file di 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 classe nei tuoi file .txt corrispondano al dizionario names in dataset.yaml. Riassegna gli ID a valori contigui se necessario.

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

FAQ

Come converto le annotazioni COCO JSON nel formato YOLO?

Usa il comando convert_coco() funzione di Ultralytics per convertire le annotazioni COCO JSON nel formato YOLO .txt. Imposta cls91to80=False per 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 di etichette in modo che labels/ rispecchi la directory images/, quindi crea un file dataset.yaml. Consulta il guida passo dopo 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/) invece che direttamente nella labels/train/ insieme alle directory images/train/ del tuo dataset. YOLO si aspetta che le etichette siano parallele alle immagini — ad esempio, images/train/img.jpg richiede labels/train/img.txt. Sposta le etichette convertite per far corrispondere questa struttura. Consulta correggere la struttura della directory.

Cosa fa cls91to80 in convert_coco()?

Il metodo cls91to80 Il parametro controlla come i valori COCO category_id vengono mappati agli ID classe YOLO. Quando è True (impostazione predefinita), utilizza una tabella di ricerca progettata per lo standard dataset COCO, che ha 80 classi con ID non contigui (1-90). Per custom datasets, imposta sempre cls91to80=False — questo sottrae semplicemente 1 da ogni category_id per creare ID classe a indice zero.

Posso addestrare YOLO direttamente su COCO JSON senza convertire?

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

Posso convertire le annotazioni di segmentazione COCO nel formato YOLO?

Sì, usa use_segments=True quando chiami convert_coco() per includere maschere di segmentazione poligonale nelle etichette YOLO convertite. Questo produce file di etichette compatibili con 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 punti chiave COCO nel formato YOLO?

Usa use_keypoints=True per convertire le annotazioni dei punti chiave COCO per l'addestramento di 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 entrambi use_segments e use_keypoints sono impostati su True, solo i punti chiave verranno scritti nei file di etichette — i segmenti vengono ignorati silenziosamente.

Commenti