Meet YOLO26: next-gen vision AI.

Link to this sectionCómo convertir anotaciones COCO al formato YOLO#

Entrenar modelos de Ultralytics YOLO requiere anotaciones en formato YOLO, pero muchas herramientas de anotación populares exportan en su lugar en formato COCO JSON. Esta guía te muestra cómo convertir tus anotaciones COCO al formato YOLO y comenzar a entrenar modelos de detección de objetos, segmentación de instancias y estimación de poses.

¿Prefieres saltarte la conversión?

Para entrenar directamente con COCO JSON sin generar archivos .txt, consulta Entrenar YOLO con COCO JSON sin conversión.

Link to this section¿Por qué convertir de COCO a YOLO?#

El formato COCO JSON almacena todas las anotaciones en un único archivo, mientras que YOLO utiliza un archivo de texto por imagen con coordenadas normalizadas. La conversión es necesaria porque:

  • Los modelos YOLO requieren archivos de etiquetas .txt con un archivo por imagen, que contengan class x_center y_center width height en coordenadas normalizadas.
  • COCO JSON utiliza coordenadas de píxeles en formato [x_min, y_min, width, height] con un único archivo JSON para todas las imágenes.
  • Los ID de clase difieren: COCO utiliza valores de category_id arbitrarios, mientras que YOLO requiere ID de clase indexados desde cero.
CaracterísticaCOCO JSONYOLO TXT
EstructuraUn único archivo JSON para todas las imágenesUn archivo .txt por imagen
Formato Bbox[x_min, y_min, width, height] en píxelesclass x_center y_center width height normalizado (0-1)
ID de clasecategory_id (puede empezar desde cualquier número)Indexado desde cero (empieza en 0)
SegmentaciónArrays de polígonos en el campo segmentationCoordenadas de polígono después del ID de clase
Puntos clave (Keypoints)[x, y, visibility, ...] en píxeles[x, y, visibility, ...] normalizado

Link to this sectionInicio rápido#

La forma más rápida de convertir anotaciones COCO y empezar a entrenar:

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

Después de la conversión, organiza la estructura de tu directorio, crea un dataset.yaml y empieza a entrenar. Consulta la guía paso a paso completa a continuación.

Datasets personalizados: utiliza siempre `cls91to80=False`

El valor predeterminado cls91to80=True está diseñado solo para el dataset COCO estándar con 80 clases de objetos, el cual mapea 91 ID de categorías no contiguas a 80 ID de clase contiguas. Para cualquier dataset personalizado, debes configurar cls91to80=False; de lo contrario, tus ID de clase se mapearán incorrectamente de forma silenciosa y tu modelo aprenderá clases erróneas.

Link to this sectionGuía de conversión paso a paso#

Link to this section1. Prepara tu dataset COCO#

Un dataset típico en formato COCO exportado desde herramientas de anotación tiene la siguiente estructura:

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

Cada archivo JSON sigue la especificación del formato de datos COCO con tres campos obligatorios: images, annotations y 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. Convierte las anotaciones#

Utiliza la función convert_coco() para convertir tus anotaciones COCO JSON al formato .txt de YOLO:

Convertir COCO al 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() escribe un archivo .txt por cada imagen anotada dentro de un subdirectorio labels/ nombrado según cada archivo JSON, eliminando el prefijo instances_ (por lo que instances_train.json genera labels/train/). Las imágenes sin anotaciones se omiten y no obtienen archivo de etiquetas, por lo que el árbol labels/ puede no reflejar todas las imágenes:

my_dataset/converted/
└── labels/
    ├── train/   # from instances_train.json
    │   ├── img_001.txt
    │   └── ...
    └── val/     # from instances_val.json
        └── ...
Volver a ejecutar crea una nueva carpeta de salida

convert_coco() nunca sobrescribe un save_dir existente: si my_dataset/converted/ ya existe, una nueva ejecución escribe en my_dataset/converted-2/ en su lugar. Elimina la salida anterior (o cambia save_dir) antes de volver a ejecutar, o los siguientes pasos leerán etiquetas obsoletas.

Link to this section3. Organiza la estructura del directorio#

Tras la conversión, los archivos de etiquetas deben colocarse junto a tus imágenes. YOLO espera un directorio labels/ que refleje al directorio 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))

Tu estructura de dataset final debería verse así:

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

Link to this section4. Crea dataset.yaml#

Crea un archivo de configuración dataset.yaml que mapee tus categorías COCO a nombres de clase de YOLO. Este archivo le indica a YOLO dónde están tus datos y qué clases detectar:

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)

El archivo YAML resultante:

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

Para obtener más detalles sobre el formato YAML del dataset, consulta la guía de configuración de datasets.

Link to this section5. Entrena tu modelo YOLO#

Con tu dataset convertido listo, entrena un modelo YOLO:

Entrenar con datos COCO convertidos
from ultralytics import YOLO

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

Para consejos de entrenamiento y mejores prácticas, consulta la guía de entrenamiento de modelos.

Link to this section6. Verifica tu conversión#

Antes de entrenar, verifica manualmente algunos archivos de etiquetas para confirmar que los ID de clase y las coordenadas sean correctos:

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

Si ves ID de clase negativos, es probable que tu COCO JSON utilice category_id empezando desde 0. Suma 1 a todos los valores de category_id en tu JSON antes de ejecutar convert_coco(), ya que esta mapea los ID de clase como category_id - 1.

Link to this sectionSolución de problemas comunes#

Link to this sectionID de clase incorrectos tras la conversión#

Si tu modelo entrena pero detecta clases de objetos incorrectas, es probable que estés usando cls91to80=True (predeterminado) en un dataset personalizado. Esto mapea tus valores de category_id a través de la tabla de consulta 91 a 80 de COCO, lo cual solo es correcto para el dataset COCO estándar.

Solución: Utiliza siempre cls91to80=False para datasets personalizados.

Link to this sectionNo se encontraron etiquetas durante el entrenamiento#

Si el entrenamiento muestra WARNING: No labels found o 0 images, N backgrounds, tus archivos de etiquetas no están en el directorio esperado. convert_coco() guarda las etiquetas en un directorio de salida independiente (p. ej., save_dir/labels/train/), pero YOLO espera labels/ en paralelo a images/ dentro de tu directorio de dataset.

Solución: Mueve los archivos de etiquetas para que coincidan con la estructura de directorios esperada. Asegúrate de que labels/train/ sea un hermano de images/train/.

Link to this sectionKeyError durante la conversión#

Si obtienes un KeyError: 'bbox' o errores similares al ejecutar convert_coco(), es probable que tu labels_dir contenga archivos JSON que no son de instancias (p. ej., captions_train2017.json), los cuales tienen una estructura de anotación diferente.

Solución: Coloca únicamente archivos JSON de anotaciones de instancias (p. ej., instances_train2017.json) en el labels_dir.

Link to this sectionArchivos de etiquetas vacíos tras la conversión#

Si la conversión finaliza pero los archivos .txt están vacíos o faltan, puede que todas las anotaciones tengan iscrowd: 1 (común con máscaras generadas por SAM), o que las cajas delimitadoras (bounding boxes) tengan cero de ancho o alto.

Solución: Inspecciona tus anotaciones JSON en busca de valores iscrowd. Si usas máscaras SAM, preprocesa el JSON para establecer iscrowd: 0.

Link to this sectionVacíos en los ID de clase en las etiquetas convertidas#

Si los ID de clase en los archivos de etiquetas no son contiguos (p. ej., 0, 4, 9 en lugar de 0, 1, 2), tu herramienta de anotación utiliza valores de category_id no contiguos.

Solución: Verifica que los ID de clase en tus archivos .txt coincidan con el diccionario names en dataset.yaml. Remapea los ID a valores contiguos si es necesario.

Para obtener detalles completos de la API y descripciones de parámetros, consulta la referencia de la API de convert_coco.

Link to this sectionFAQ#

Link to this section¿Cómo convierto las anotaciones COCO JSON al formato YOLO?#

Utiliza la función convert_coco() de Ultralytics para convertir las anotaciones COCO JSON al formato .txt de YOLO. Configura cls91to80=False para datasets personalizados:

from ultralytics.data.converter import convert_coco

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

Tras la conversión, reorganiza tus archivos de etiquetas para que labels/ refleje al directorio images/, y luego crea un archivo dataset.yaml. Consulta la guía paso a paso para ver el flujo de trabajo completo.

Link to this section¿Por qué el entrenamiento YOLO muestra "No labels found" tras la conversión COCO?#

Esto sucede porque convert_coco() guarda las etiquetas en un subdirectorio dentro de save_dir/labels/ (p. ej., save_dir/labels/train/) en lugar de hacerlo directamente en el labels/train/ de tu dataset junto a images/train/. YOLO espera que las etiquetas estén paralelas a las imágenes; por ejemplo, images/train/img.jpg necesita labels/train/img.txt. Mueve tus etiquetas convertidas para que coincidan con esta estructura. Consulta cómo corregir la estructura de directorios.

Link to this section¿Qué hace cls91to80 en convert_coco()?#

El parámetro cls91to80 controla cómo se mapean los valores category_id de COCO a IDs de clase de YOLO. Cuando es True (predeterminado), aplica la tabla de búsqueda coco91_to_coco80_class() diseñada para el dataset COCO estándar, que tiene 80 clases con IDs no contiguos (1-90). Para datasets personalizados, establece siempre cls91to80=False; esto simplemente resta 1 a cada category_id para crear IDs de clase indexados en cero.

Link to this section¿Puedo entrenar YOLO directamente con COCO JSON sin convertir?#

No con el pipeline de entrenamiento de YOLO actual; las anotaciones deben estar en formato .txt de YOLO con un archivo por imagen. Utiliza convert_coco() para convertir primero tu COCO JSON y luego sigue esta guía para organizar y entrenar. Para obtener más información sobre formatos admitidos, consulta formatos de dataset.

Link to this section¿Puedo convertir anotaciones de segmentación COCO al formato YOLO?#

Sí, utiliza use_segments=True al llamar a convert_coco() para incluir máscaras de segmentación de polígonos en las etiquetas YOLO convertidas. Esto genera archivos de etiquetas compatibles con modelos de segmentación YOLO:

from ultralytics.data.converter import convert_coco

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

Link to this section¿Cómo convierto las anotaciones de puntos clave (keypoints) COCO al formato YOLO?#

Utiliza use_keypoints=True para convertir las anotaciones de puntos clave COCO para el entrenamiento de estimación de poses:

from ultralytics.data.converter import convert_coco

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

Ten en cuenta que si tanto use_segments como use_keypoints están configurados en True, solo se escribirán los puntos clave en los archivos de etiquetas; los segmentos serán ignorados silenciosamente.

Comentarios