Meet YOLO26: next-gen vision AI.

Link to this sectionCOCO 어노테이션을 YOLO 형식으로 변환하는 방법#

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

Link to this section왜 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, ...] (정규화됨)

Link to this section빠른 시작#

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가 잘못 매핑되어 모델이 잘못된 클래스를 학습하게 됩니다.

Link to this section단계별 변환 가이드#

Link to this sectionCOCO 데이터셋 준비#

어노테이션 도구에서 내보낸 일반적인 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" }
    ]
}

Link to this section어노테이션 변환#

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

Link to this section디렉터리 구조 정리#

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

Link to this sectiondataset.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 형식에 대한 자세한 내용은 데이터셋 구성 가이드를 참조하세요.

Link to this sectionYOLO 모델 학습#

변환된 데이터셋이 준비되면 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)

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

Link to this section변환 확인#

학습 전에 몇 개의 레이블 파일을 확인하여 클래스 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.

Link to this section일반적인 문제 해결#

Link to this section변환 후 잘못된 클래스 ID#

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

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

Link to this section학습 중 레이블을 찾을 수 없음#

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/과 형제 디렉터리인지 확인하세요.

Link to this section변환 중 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에 두세요.

Link to this section변환 후 빈 레이블 파일#

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

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

Link to this section변환된 레이블의 클래스 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 참조를 확인하세요.

Link to this sectionFAQ#

Link to this sectionCOCO 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 파일을 만드세요. 전체 워크플로우는 단계별 가이드를 참조하세요.

Link to this sectionCOCO 변환 후 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.

Link to this sectionWhat 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를 만드는 작업입니다.

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

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

Link to this sectionCOCO 세그멘테이션 어노테이션을 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)

Link to this sectionCOCO 키포인트 어노테이션을 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로 설정하면 키포인트만 레이블 파일에 기록되며 세그먼트는 무시되니 주의하세요.

댓글