Meet YOLO26: next-gen vision AI.

COCO 어노테이션을 YOLO 형식으로 변환하는 방법

Ultralytics YOLO 모델을 학습하려면 YOLO 형식의 어노테이션이 필요하지만, 많은 인기 어노테이션 도구는 대신 COCO JSON 형식으로 내보냅니다. 이 가이드에서는 COCO 어노테이션을 YOLO 형식으로 변환하고 객체 탐지, 인스턴스 세그멘테이션포즈 추정 모델 학습을 시작하는 방법을 보여줍니다.

왜 COCO에서 YOLO로 변환해야 하나요?

COCO JSON 형식은 모든 어노테이션을 단일 파일에 저장하는 반면, YOLO는 이미지당 하나의 텍스트 파일을 정규화된 좌표와 함께 사용합니다. 변환이 필요한 이유는 다음과 같습니다:

  • YOLO 모델은 .txt 레이블 파일이 필요하며, 각 이미지당 하나의 파일이 있어야 하고 class x_center y_center width height를 정규화된 좌표로 포함해야 합니다.
  • COCO JSON은 픽셀 좌표를 [x_min, y_min, width, height] 형식으로 사용하며 모든 이미지에 대해 단일 JSON 파일을 사용합니다.
  • 클래스 ID가 다릅니다. COCO는 임의의 category_id 값을 사용하지만, YOLO는 0부터 시작하는 인덱스 클래스 ID를 필요로 합니다.
기능COCO JSONYOLO TXT
구조모든 이미지를 위한 단일 JSON 파일이미지당 하나의 .txt 파일
Bbox 형식[x_min, y_min, width, height] (픽셀 단위)class x_center y_center width height (정규화된 0-1)
클래스 IDcategory_id (어떤 숫자에서든 시작 가능)0부터 시작하는 인덱스 (0부터 시작)
세그멘테이션segmentation 필드의 다각형 배열클래스 ID 뒤에 오는 다각형 좌표
키포인트[x, y, visibility, ...] (픽셀 단위)[x, y, visibility, ...] (정규화됨)

빠른 시작

COCO 어노테이션을 변환하고 학습을 시작하는 가장 빠른 방법:

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
)

변환 후, 디렉터리 구조를 정리하고, dataset.yaml을 생성한 다음, 학습을 시작합니다. 아래 전체 단계별 가이드를 참조하세요.

커스텀 데이터셋: 항상 `cls91to80=False`를 사용하세요

cls91to80=True 기본값은 80개의 객체 클래스가 있는 표준 COCO 데이터셋 전용으로 설계되었으며, 이는 91개의 비연속적인 카테고리 ID를 80개의 연속적인 클래스 ID로 매핑합니다. 모든 커스텀 데이터셋의 경우, 반드시 cls91to80=False를 설정해야 합니다. 그렇지 않으면 클래스 ID가 잘못 매핑되어 모델이 잘못된 클래스를 학습하게 됩니다.

단계별 변환 가이드

COCO 데이터셋 준비

어노테이션 도구에서 내보낸 일반적인 COCO 형식 데이터셋은 다음과 같은 구조를 가집니다:

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

Each JSON file follows the COCO data format specification with three required fields — images, annotations, and 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" }
    ]
}

어노테이션 변환

convert_coco() 함수를 사용하여 COCO JSON 어노테이션을 YOLO .txt 형식으로 변환합니다:

COCO를 YOLO 형식으로 변환
from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="my_dataset/annotations/",
    save_dir="my_dataset/converted/",
    cls91to80=False,
)

디렉터리 구조 정리

After conversion, label files need to be placed alongside your images. YOLO expects a labels/ directory that mirrors the images/ directory:

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

최종 데이터셋 구조는 다음과 같아야 합니다:

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

dataset.yaml 생성

COCO 카테고리를 YOLO 클래스 이름으로 매핑하는 dataset.yaml 구성 파일을 생성합니다. 이 파일은 YOLO에게 데이터 위치와 탐지할 클래스를 알려줍니다:

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)

결과물인 YAML 파일:

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

데이터셋 YAML 형식에 대한 자세한 내용은 데이터셋 구성 가이드를 참조하세요.

YOLO 모델 학습

변환된 데이터셋이 준비되면 YOLO 모델을 학습합니다:

변환된 COCO 데이터로 학습
from ultralytics import YOLO

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

학습 팁과 모범 사례는 모델 학습 가이드를 참조하세요.

변환 확인

학습 전에 몇 개의 레이블 파일을 확인하여 클래스 ID와 좌표가 정확한지 검토하세요:

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

If you see negative class IDs, your COCO JSON likely uses category_id starting from 0. Add 1 to all category_id values in your JSON before running convert_coco(), since it maps class IDs as category_id - 1.

일반적인 문제 해결

변환 후 잘못된 클래스 ID

모델은 학습되지만 잘못된 객체 클래스를 탐지한다면, 커스텀 데이터셋에 cls91to80=True(기본값)를 사용하고 있을 가능성이 높습니다. 이는 category_id 값을 표준 COCO 데이터셋 전용인 COCO 91-to-80 조회 테이블을 통해 매핑합니다.

해결책: 커스텀 데이터셋에는 항상 cls91to80=False를 사용하세요.

학습 중 레이블을 찾을 수 없음

If training shows WARNING: No labels found or 0 images, N backgrounds, your label files are not in the expected directory. convert_coco() saves labels to a separate output directory (e.g., save_dir/labels/train/), but YOLO expects labels/ parallel to images/ inside your dataset directory.

해결책: 레이블 파일을 이동하여 예상되는 디렉터리 구조에 맞추세요. labels/train/images/train/과 형제 디렉터리인지 확인하세요.

변환 중 KeyError 발생

If you get KeyError: 'bbox' or similar errors when running convert_coco(), your labels_dir likely contains non-instance JSON files (e.g., captions_train2017.json) that have a different annotation structure.

해결책: 인스턴스 어노테이션 JSON 파일(예: instances_train2017.json)만 labels_dir에 두세요.

변환 후 빈 레이블 파일

변환은 완료되었는데 .txt 파일이 비어 있거나 없으면, 모든 어노테이션에 iscrowd: 1이 설정되어 있거나(SAM으로 생성된 마스크에서 흔함), 바운딩 박스의 너비나 높이가 0일 수 있습니다.

해결책: JSON 어노테이션에서 iscrowd 값을 검사하세요. SAM 마스크를 사용하는 경우, JSON을 전처리하여 iscrowd: 0으로 설정하세요.

변환된 레이블의 클래스 ID 공백

레이블 파일의 클래스 ID가 비연속적(예: 0, 1, 2 대신 0, 4, 9)이라면, 어노테이션 도구가 비연속적인 category_id 값을 사용하는 것입니다.

Solution: Verify the class IDs in your .txt files match the names dictionary in dataset.yaml. Remap IDs to contiguous values if needed.

전체 API 세부 정보 및 매개변수 설명은 convert_coco API 참조를 확인하세요.

FAQ

COCO JSON 어노테이션을 YOLO 형식으로 어떻게 변환하나요?

Ultralytics의 convert_coco() 함수를 사용하여 COCO JSON 어노테이션을 YOLO .txt 형식으로 변환하세요. 커스텀 데이터셋의 경우 cls91to80=False로 설정하세요:

from ultralytics.data.converter import convert_coco

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

변환 후 레이블 파일을 재정리하여 labels/images/ 디렉터리를 미러링하도록 한 다음 dataset.yaml 파일을 만드세요. 전체 워크플로우는 단계별 가이드를 참조하세요.

COCO 변환 후 YOLO 학습에서 "No labels found" 오류가 발생하는 이유는 무엇인가요?

This happens because convert_coco() saves labels to a subdirectory inside save_dir/labels/ (e.g., save_dir/labels/train/) rather than directly into your dataset's labels/train/ alongside images/train/. YOLO expects labels to sit parallel to images — for example, images/train/img.jpg needs labels/train/img.txt. Move your converted labels to match this structure. See fixing the directory structure.

What does cls91to80 do in convert_coco()?

cls91to80 매개변수는 COCO category_id 값이 YOLO 클래스 ID로 매핑되는 방식을 제어합니다. True(기본값)로 설정하면 비연속적인 ID(1-90)를 가진 80개 클래스의 표준 COCO 데이터셋 전용 조회 테이블을 사용합니다. 커스텀 데이터셋의 경우 항상 cls91to80=False로 설정하세요. 이는 각 category_id에서 1을 빼서 0부터 시작하는 인덱스 클래스 ID를 만드는 작업입니다.

변환 없이 COCO JSON으로 YOLO를 직접 학습할 수 있나요?

현재 YOLO 학습 파이프라인으로는 불가능합니다. 어노테이션은 이미지당 하나의 파일이 있는 YOLO .txt 형식이어야 합니다. 먼저 convert_coco()를 사용하여 COCO JSON을 변환한 다음, 이 가이드에 따라 정리하고 학습하세요. 지원되는 형식에 대한 자세한 내용은 데이터셋 형식을 참조하세요.

COCO 세그멘테이션 어노테이션을 YOLO 형식으로 변환할 수 있나요?

Yes, use use_segments=True when calling convert_coco() to include polygon segmentation masks in the converted YOLO labels. This produces label files compatible with YOLO segmentation models:

from ultralytics.data.converter import convert_coco

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

COCO 키포인트 어노테이션을 YOLO 형식으로 변환하려면 어떻게 하나요?

Use use_keypoints=True to convert COCO keypoint annotations for pose estimation training:

from ultralytics.data.converter import convert_coco

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

use_segmentsuse_keypoints를 모두 True로 설정하면 키포인트만 레이블 파일에 기록되며 세그먼트는 무시되니 주의하세요.

댓글