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 | Arrays de polígonos ou máscaras RLE 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 teu conjunto de dados deve ser semelhante a esta:
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
from ultralytics.utils 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,
}
YAML.save("my_dataset/dataset.yaml", dataset)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 teu modelo é treinado, mas deteta classes de objetos incorretas, provavelmente estás a usar cls91to80=True (predefinido) num conjunto de dados personalizado. Esta opção mapeia os valores category_id através da tabela de consulta COCO de 91 para 80 classes, que só é correta para o conjunto de dados COCO padrão. Um category_id sem equivalente entre as 80 classes COCO não é mapeado e gera TypeError: must be real number, not NoneType durante a conversão, em vez de produzir etiquetas incorretas.
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, que convert_coco() ignora (o CVAT, por exemplo, exporta anotações de máscara como regiões de multidão), ou caixas delimitadoras podem ter largura ou altura zero. Executar com use_keypoints=True em uma exportação somente de detecção produz o mesmo resultado, porque as anotações sem um campo keypoints são ignoradas por completo.
Solução: Inspecione os valores iscrowd nas anotações JSON. Quando cada máscara marcada como multidão contornar um único objeto, como nas exportações de máscaras do CVAT, defina iscrowd: 0 para que use_segments=True converta a máscara RLE; mantenha sinalizadas as regiões de multidão genuínas que cobrem vários objetos. Se você passou use_keypoints=True, confirme que 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, uma codificação COCO por comprimento de sequência ({"counts": ..., "size": ...}) cujo size não corresponde ao [height, width] da imagem, ou cuja máscara está vazia ou contém apenas regiões pequenas ou estreitas demais para serem contornadas com três pontos, ou um valor que não é RLE nem uma lista com pelo menos três pares de coordenadas. A causa mais comum é uma exportação somente de detecção, que deixa o campo ausente ou vazio; uma lista plana de coordenadas sem uma lista de polígonos que a contenha, contornos com um ou dois pontos e outros valores malformados são tratados da mesma maneira. A anotação mantém os polígonos restantes e, se não houver nenhum, recorre a uma linha de segmento com o formato da caixa delimitadora; assim, os rótulos permanecem válidos, mas essas linhas não contêm detalhes da máscara.
Valores RLE cujo counts esteja ausente ou não possa ser decodificado, como uma string truncada ou sequências que não somam size, interrompem a conversão com um erro em vez de acionar um fallback.
Solução: Exporte novamente as anotações com segmentações por polígonos ou RLE, ou corrija quaisquer 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 nos rótulos YOLO convertidos. As segmentações por polígonos são convertidas diretamente, e as máscaras codificadas por comprimento de sequência (RLE), compactadas ou não, são decodificadas comfaster-coco-eval(instalado automaticamente quando um arquivo JSON as contém) para obter os contornos externos de suas regiões. Um objeto dividido em vários polígonos ou regiões de máscara é reunido em uma única linha de polígono e, como os polígonos YOLO não podem conter buracos, os buracos das máscaras são preenchidos. As anotações de multidão (iscrowd: 1) são ignoradas. Isso produz arquivos de rótulos 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.
Comentários
Faz uma pergunta, partilha os teus resultados ou ajuda alguém.