Cómo convertir anotaciones COCO al formato YOLO
Entrenar modelos Ultralytics YOLO requiere anotaciones en formato YOLO, pero muchas herramientas de anotación populares exportan en formato COCO JSON en su lugar. Esta guía te muestra cómo convertir tus anotaciones COCO al formato YOLO y empezar a entrenar object detection, segmentación de instancias, y pose estimation bien entrenados.
¿Por qué convertir de COCO a YOLO?
El formato COCO JSON guarda todas las anotaciones en un único archivo, mientras que YOLO usa un archivo de texto por imagen con coordenadas normalizadas. La conversión es necesaria porque:
- Los modelos YOLO requieren
.txtarchivos de etiquetas con un archivo por imagen, que contengaclass x_center y_center width heighten coordenadas normalizadas. - COCO JSON usa formato de coordenadas de píxeles en
[x_min, y_min, width, height]con un único archivo JSON para todas las imágenes. - Los ID de clase difieren — COCO usa valores
category_idarbitrarios, mientras que YOLO requiere ID de clase indexados desde cero.
| Funcionalidad | COCO JSON | YOLO TXT |
|---|---|---|
| Estructura | Archivo JSON único para todas las imágenes | Un archivo .txt por imagen |
| Formato Bbox | [x_min, y_min, width, height] en píxeles | class x_center y_center width height normalizado (0-1) |
| ID de clase | category_id (pueden empezar en cualquier número) | Indexados desde cero (empiezan en 0) |
| Segmentation | Arrays de polígonos en el campo segmentation | Coordenadas de polígonos después del ID de clase |
| Keypoints | [x, y, visibility, ...] en píxeles | [x, y, visibility, ...] normalizadas |
Inicio 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="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
)Tras la conversión, organiza la estructura de tu directorio, crea un archivo dataset.yaml, y inicia el entrenamiento. Consulta la guía paso a paso completa a continuación.
El método cls91to80=True El valor predeterminado está diseñado solo para el estándar COCO dataset con 80 clases de objetos, que mapea 91 ID de categorías no contiguas a 80 ID de clase contiguos. Para cualquier dataset personalizado, debes configurar Debes cls91to80=False — de lo contrario, tus ID de clase se mapearán incorrectamente de forma silenciosa y tu modelo aprenderá clases erróneas.
Guía de conversión paso a paso
1. 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.jsonCada archivo JSON sigue la especificación de 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" }
]
}2. Convierte las anotaciones
Usa el comando convert_coco() función para convertir tus anotaciones COCO JSON al formato .txt YOLO:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
cls91to80=False,
)3. 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 el directorio 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))Tu estructura del conjunto de datos final debería verse así:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ └── ...
│ └── val/
│ └── ...
├── labels/
│ ├── train/
│ │ ├── img_001.txt
│ │ └── ...
│ └── val/
│ └── ...
└── dataset.yaml4. Crea dataset.yaml
Crea un archivo dataset.yaml archivo de configuración que mapea tus categorías COCO a nombres de clase YOLO. Este archivo le dice 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: vestPara más detalles sobre el formato YAML del dataset, consulta la guía de configuración del dataset.
5. Entrena tu modelo YOLO
Con tu dataset convertido listo, entrena un modelo 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)Para consejos de entrenamiento y mejores prácticas, consulta la guía de entrenamiento de modelos.
6. Verifica tu conversión
Antes de entrenar, revisa 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}"Si ves ID de clase negativos, es probable que tu COCO JSON utilice category_id empezando desde 0. Suma 1 a todos los valores category_id en tu JSON antes de ejecutar convert_coco(), ya que mapea los ID de clase como category_id - 1.
Solución de problemas comunes
ID de clase incorrectos tras la conversión
Si tu modelo entrena pero detecta clases de objeto erróneas, probablemente estés usando cls91to80=True (predeterminado) en un dataset personalizado. Esto mapea tus valores category_id a través de la tabla de búsqueda 91-a-80 de COCO, que solo es correcta para el estándar COCO dataset.
Solución: utiliza siempre cls91to80=False para datasets personalizados.
No 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 separado (p. ej., save_dir/labels/train/), pero YOLO espera un labels/ paralelo a images/ dentro del directorio de tu dataset.
Solución: Mueve los archivos de etiquetas para que coincidan con la estructura de directorio esperada. Asegúrate de que labels/train/ es un hermano de images/train/.
KeyError durante la conversión
Si obtienes KeyError: 'bbox' o errores similares al ejecutar convert_coco(), es probable que tu labels_dir contenga archivos JSON que no sean de instancias (p. ej., captions_train2017.json) que tengan una estructura de anotación diferente.
Solución: Solo coloca archivos JSON de anotación de instancias (p. ej., instances_train2017.json) en la labels_dir.
Archivos de etiquetas vacíos tras la conversión
Si la conversión se completa pero los archivos .txt están vacíos o faltan, es posible que todas las anotaciones tengan iscrowd: 1 (común con máscaras generadas por SAM), o bounding boxes tengan ancho o alto cero.
Solución: Inspecciona tus anotaciones JSON para ver valores de iscrowd. Si usas máscaras de SAM, preprocesa el JSON para establecer iscrowd: 0.
Brechas en los ID de clase en 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 usa 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. Reasigna los ID a valores contiguos si es necesario.
Para obtener todos los detalles de la API y descripciones de parámetros, consulta la referencia de la API de convert_coco API reference.
Preguntas frecuentes
¿Cómo convierto anotaciones JSON de COCO al formato YOLO?
Usa el comando convert_coco() la función de Ultralytics para convertir anotaciones JSON de COCO al formato .txt YOLO. Establece cls91to80=False para conjuntos de datos personalizados:
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)Después de la conversión, reorganiza tus archivos de etiquetas para que el labels/ refleje el directorio images/, luego crea un archivo dataset.yaml. Consulta la guía paso a paso para ver el flujo de trabajo completo.
¿Por qué el entrenamiento de YOLO muestra "No labels found" después de la conversión de 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 directamente en el labels/train/ junto a los directorios images/train/ de tu conjunto de datos. 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 fixing the directory structure.
¿Qué hace cls91to80 en convert_coco()?
El método cls91to80 El parámetro controla cómo se asignan los valores de category_id de COCO a los ID de clase de YOLO. Cuando es True (predeterminado), utiliza una tabla de búsqueda diseñada para el estándar COCO dataset, que tiene 80 clases con ID no contiguos (1-90). Para datasets personalizados, establece siempre cls91to80=False — esto simplemente resta 1 a cada category_id para crear ID de clase basados en cero.
¿Puedo entrenar YOLO directamente con JSON de COCO sin convertirlo?
No con el pipeline de entrenamiento actual de YOLO; las anotaciones deben estar en formato .txt YOLO con un archivo por imagen. Usa convert_coco() para convertir primero tu JSON de COCO, luego sigue esta guía para organizar y entrenar. Para más información sobre los formatos soportados, consulta dataset formats.
¿Puedo convertir anotaciones de segmentación de COCO al formato YOLO?
Sí, usa use_segments=True al llamar a convert_coco() para incluir máscaras de segmentación poligonal en las etiquetas YOLO convertidas. Esto genera archivos de etiquetas compatibles con YOLO segmentation models:
from ultralytics.data.converter import convert_coco
convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)¿Cómo convierto anotaciones de puntos clave de COCO al formato YOLO?
Utiliza use_keypoints=True para convertir anotaciones de puntos clave de COCO para el entrenamiento de pose estimation:
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 ambos use_segments y use_keypoints se establecen en True, solo se escribirán los puntos clave en los archivos de etiquetas; los segmentos se ignoran silenciosamente.