Como converter anotações COCO para o formato YOLO#
O treino de modelos Ultralytics YOLO requer anotações no formato YOLO, mas muitas ferramentas populares de anotação exportam no formato COCO JSON. Este guia mostra como converter as tuas anotações COCO para o formato YOLO e começar a treinar modelos de deteção de objetos, segmentação de instâncias e estimativa de pose.
Para treinar diretamente com COCO JSON sem gerar ficheiros .txt, consulta Treinar YOLO com COCO JSON sem conversão.
Porquê converter de COCO para YOLO?#
O formato COCO JSON guarda todas as anotações num único ficheiro, enquanto YOLO usa um ficheiro de texto por imagem com coordenadas normalizadas. A conversão é necessária porque:
- Os modelos YOLO requerem ficheiros de rótulos
.txt, um ficheiro por imagem, que contêmclass x_center y_center width heightcom coordenadas normalizadas. - O COCO JSON usa coordenadas em píxeis no formato
[x_min, y_min, width, height], com um único ficheiro JSON para todas as imagens. - Os IDs de classe são diferentes — o COCO usa valores arbitrários de
category_id, enquanto o YOLO requer IDs de classe indexados a partir de zero.
| Funcionalidade | COCO JSON | YOLO TXT |
|---|---|---|
| Estrutura | Um único ficheiro JSON para todas as imagens | Um arquivo .txt por imagem |
| Formato BBox | [x_min, y_min, width, height] em píxeis | class x_center y_center width height normalizado (0-1) |
| IDs de classe | category_id (pode começar com qualquer número) | Indexado a partir de zero (começa em 0) |
| Segmentação | Matrizes de polígonos no campo segmentation | Coordenadas dos polígonos após o ID da classe |
| Pontos-chave | [x, y, visibility, ...] em píxeis | [x, y, visibility, ...] normalizado |
Início rápido#
A maneira mais rápida de converter anotações COCO e começar o treinamento:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/", # diretório que contém seus arquivos JSON
save_dir="my_dataset/converted/", # onde salvar os rótulos convertidos
cls91to80=False, # defina como False para conjuntos de dados personalizados (consulte o aviso abaixo)
)Após a conversão, organize a estrutura do diretório, crie um dataset.yaml e comece o treinamento. Veja abaixo o guia passo a passo completo.
O valor padrão de cls91to80=True foi projetado somente para o conjunto de dados COCO padrão, com 80 classes de objetos, que mapeia 91 IDs de categoria não contíguos para 80 IDs de classe contíguos. Para qualquer conjunto de dados personalizado, você deve definir cls91to80=False — caso contrário, seus IDs de classe serão mapeados incorretamente sem aviso, e seu modelo aprenderá classes erradas.
Guia de conversão passo a passo#
1. Prepare seu conjunto de dados COCO#
Um conjunto de dados típico no formato COCO, exportado de ferramentas de anotação, tem a seguinte estrutura:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ ├── img_002.jpg
│ │ └── ...
│ └── val/
│ ├── img_100.jpg
│ └── ...
└── annotations/
├── instances_train.json
└── instances_val.jsonCada arquivo JSON segue a especificação do formato de dados COCO, com três campos obrigatórios — 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. Converta as anotações#
Use a função convert_coco() para converter suas anotações COCO JSON para o formato YOLO .txt:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
cls91to80=False,
)convert_coco() grava um arquivo .txt para cada imagem anotada em um subdiretório labels/ com o nome de cada arquivo JSON e o prefixo instances_ removido (assim, instances_train.json gera labels/train/). Imagens sem anotações são ignoradas e não recebem um arquivo de rótulo, então a árvore labels/ pode não espelhar todas as imagens:
my_dataset/converted/
├── images/ # created but left empty
└── labels/
├── train/ # from instances_train.json
│ ├── img_001.txt
│ └── ...
└── val/ # from instances_val.json
└── ...convert_coco() nunca substitui um save_dir existente: se my_dataset/converted/ já existir, uma nova execução gravará em my_dataset/converted-2/. Exclua a saída anterior (ou altere save_dir) antes de executar novamente; caso contrário, as próximas etapas lerão rótulos desatualizados.
3. Organize a estrutura do diretório#
Após a conversão, os arquivos de rótulo precisam ficar junto às imagens. O YOLO espera um diretório labels/ que espelhe o diretório images/:
import shutil
from pathlib import Path
converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")
# convert_coco nomeia cada subdiretório com base no respectivo arquivo JSON (sem o prefixo "instances_"),
# então percorra os subdiretórios existentes em vez de presumir "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))A estrutura final do conjunto de dados deve ter esta aparência:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ └── ...
│ └── val/
│ └── ...
├── labels/
│ ├── train/
│ │ ├── img_001.txt
│ │ └── ...
│ └── val/
│ └── ...
└── dataset.yaml4. Crie dataset.yaml#
Crie um arquivo de configuração dataset.yaml que mapeie suas categorias COCO para nomes de classes YOLO. Esse arquivo informa ao YOLO onde estão seus dados e quais classes detectar:
import json
from pathlib import Path
import yaml
# Leia as categorias do seu JSON COCO
with open("my_dataset/annotations/instances_train.json") as f:
coco = json.load(f)
# Crie nomes de classes que correspondam à saída de convert_coco (category_id - 1)
categories = sorted(coco["categories"], key=lambda x: x["id"])
names = {cat["id"] - 1: cat["name"] for cat in categories}
# OBSERVAÇÃO: convert_coco mapeia os IDs das classes como category_id - 1, então category_id deve
# começar em 1. Se suas categorias começarem em 0, some 1 primeiro a cada ID.
# Crie 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)O arquivo YAML resultante:
path: /absolute/path/to/my_dataset
train: images/train
val: images/val
names:
0: helmet
1: vestPara saber mais sobre o formato YAML do conjunto de dados, consulte o guia de configuração de conjuntos de dados.
5. Treine seu modelo YOLO#
Com o conjunto de dados convertido pronto, treine um modelo YOLO:
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # carrega um modelo pré-treinado
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)Para ver dicas de treinamento e práticas recomendadas, consulte o guia de treinamento de modelos.
6. Verifique sua conversão#
Antes do treinamento, confira alguns arquivos de rótulo para confirmar se os IDs de classe e as coordenadas estão corretos:
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}"Se encontrar IDs de classe negativos, seu JSON COCO provavelmente usa category_id começando em 0. Some 1 a todos os valores category_id no JSON antes de executar convert_coco(), pois ele mapeia os IDs de classe como category_id - 1.
Solução de problemas comuns#
IDs de classe incorretos após a conversão#
Se o treinamento do seu modelo for concluído, mas ele detectar classes de objetos erradas, provavelmente você está usando cls91to80=True (padrão) em um conjunto de dados personalizado. Isso mapeia seus valores category_id usando a tabela de consulta COCO 91 para 80, que só é correta para o conjunto de dados COCO padrão. Um category_id sem correspondente no COCO-80 não é mapeado e gera TypeError: must be real number, not NoneType durante a conversão, em vez de produzir rótulos incorretos.
Solução: use sempre cls91to80=False para conjuntos de dados personalizados.
Nenhum rótulo encontrado durante o treinamento#
Se a verificação dos rótulos informar 0 images, N backgrounds e o treinamento for interrompido com ValueError: train: No labels found in .../labels/train.cache, seus arquivos de rótulo não estão no diretório esperado. convert_coco() salva os rótulos em um diretório de saída separado (por exemplo, save_dir/labels/train/), mas o YOLO espera labels/ em paralelo a images/ dentro do diretório do conjunto de dados.
Solução: mova os arquivos de rótulo para corresponder à estrutura de diretório esperada. Verifique se labels/train/ está no mesmo nível que images/train/.
KeyError durante a conversão#
Se você receber KeyError: 'bbox' ou erros semelhantes ao executar convert_coco(), seu labels_dir provavelmente contém arquivos JSON que não são de instâncias (por exemplo, captions_train2017.json) e têm uma estrutura de anotação diferente.
Solução: coloque apenas arquivos JSON de anotação de instâncias (por exemplo, instances_train2017.json) em labels_dir.
Arquivos de rótulo vazios após a conversão#
Se a conversão for concluída, mas os arquivos .txt estiverem vazios ou ausentes, todas as anotações podem ter iscrowd: 1 (algo comum em máscaras geradas pelo SAM) ou as caixas delimitadoras podem ter largura ou altura zero. Executar com use_keypoints=True em uma exportação apenas de detecção produz o mesmo resultado, pois as anotações sem o campo keypoints são totalmente ignoradas.
Solução: inspecione os valores iscrowd nas anotações JSON. Se estiver usando máscaras SAM, pré-processe o JSON para definir iscrowd: 0. Se você passou use_keypoints=True, confirme se suas anotações realmente contêm keypoints.
Polígonos em forma de caixa provenientes de anotações de máscaras#
Se use_segments=True registrar annotations without a usable polygon, algumas anotações não têm um valor segmentation ou têm um valor que não é uma lista com pelo menos três pares de coordenadas. As causas mais comuns são exportações apenas de detecção, nas quais o campo está ausente ou vazio, e a codificação de comprimento variável COCO ({"counts": ..., "size": ...}), usada por exportadores de mapas de bits como o SAM; listas simples de coordenadas sem uma lista de polígonos que as envolva, contornos com um ou dois pontos e outros valores malformados são tratados da mesma maneira. Uma anotação mantém os polígonos restantes e, quando não há nenhum, recorre a uma linha de segmento com o formato da caixa delimitadora. Assim, os rótulos continuam válidos, mas essas linhas não contêm detalhes da máscara.
Solução: exporte novamente as anotações com segmentações poligonais, decodifique as máscaras RLE em polígonos antes de executar convert_coco() ou corrija os valores segmentation malformados.
Lacunas nos IDs de classe dos rótulos convertidos#
Se os IDs de classe nos arquivos de rótulo não forem contíguos (por exemplo, 0, 4, 9 em vez de 0, 1, 2), sua ferramenta de anotação usa valores category_id não contíguos.
Solução: verifique se os IDs de classe nos arquivos .txt correspondem ao dicionário names em dataset.yaml. Se necessário, remapeie os IDs para valores contíguos.
Para ver todos os detalhes da API e as descrições dos parâmetros, consulte a referência da API de convert_coco.
Perguntas frequentes#
Use a função
convert_coco()da Ultralytics para converter anotações COCO JSON para o formato YOLO.txt. Definacls91to80=Falsepara conjuntos de dados personalizados:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)Após a conversão, reorganize seus arquivos de rótulo para que
labels/espelhe o diretórioimages/e, em seguida, crie um arquivodataset.yaml. Consulte o guia passo a passo para ver o fluxo de trabalho completo.Isso acontece porque
convert_coco()salva os rótulos em um subdiretório desave_dir/labels/(por exemplo,save_dir/labels/train/), em vez de diretamente emlabels/train/do conjunto de dados, junto aimages/train/. O YOLO espera que os rótulos fiquem em paralelo às imagens — por exemplo,images/train/img.jpgprecisa delabels/train/img.txt. Mova os rótulos convertidos para corresponder a essa estrutura. Consulte como corrigir a estrutura de diretórios.O parâmetro
cls91to80controla como os valores COCOcategory_idsão mapeados para IDs de classe YOLO. QuandoTrue(padrão), ele aplica a tabela de consultacoco91_to_coco80_class(), projetada para o conjunto de dados COCO padrão, que tem 80 classes com IDs não contíguos (1-90). Para conjuntos de dados personalizados, defina semprecls91to80=False— isso simplesmente subtrai 1 de cadacategory_idpara criar IDs de classe indexados a partir de zero.Não sem código personalizado. O pipeline de treinamento padrão espera rótulos YOLO
.txt, com um arquivo por imagem. Portanto, executeconvert_coco()e siga este guia passo a passo, ou crie uma subclasse do conjunto de dados para analisar o COCO JSON em tempo real — consulte Treinar YOLO com COCO JSON sem conversão. Para saber mais sobre os formatos compatíveis, consulte formatos de conjuntos de dados.Sim, use
use_segments=Trueao chamarconvert_coco()para incluir máscaras de segmentação poligonais nos rótulos YOLO convertidos. Isso gera arquivos de rótulo compatíveis com modelos YOLO de segmentação:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)Use
use_keypoints=Truepara converter anotações de pontos-chave COCO para o treinamento de estimativa de pose:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)Observe que, se
use_segmentseuse_keypointsforem definidos comoTrue, somente os pontos-chave serão gravados nos arquivos de rótulo — os segmentos serão ignorados sem aviso.