Ultralytics YOLO27:
Get Started

간단한 유틸리티#

YOLO model code with 3D perspective visualization

ultralytics 패키지는 워크플로를 지원하고 개선하며 가속하는 다양한 유틸리티를 제공합니다. 사용할 수 있는 유틸리티는 더 많지만, 이 가이드에서는 개발자에게 유용한 몇 가지를 소개하고 Ultralytics 도구를 활용한 프로그래밍의 실용적인 참고 자료를 제공합니다.



시청: Ultralytics 유틸리티 | 자동 주석, Explorer API 및 데이터셋 변환

데이터#

자동 라벨링 / 주석#

데이터셋 주석은 리소스와 시간이 많이 소요되는 작업입니다. 적절한 양의 데이터로 학습한 Ultralytics YOLO 객체 감지 모델이 있다면, 해당 모델을 SAM과 함께 사용해 추가 데이터를 세그멘테이션 형식으로 자동 주석 처리할 수 있습니다.

from ultralytics.data.annotator import auto_annotate

auto_annotate(
    data="path/to/new/data",
    det_model="yolo26n.pt",
    sam_model="mobile_sam.pt",
    device="cuda",
    output_dir="path/to/save_labels",
)

이 함수는 값을 반환하지 않습니다. 자세한 내용은 다음을 참조하세요.

데이터셋 주석 시각화#

이 함수는 학습 전에 이미지의 YOLO 주석을 시각화하여 잘못된 감지 결과를 초래할 수 있는 주석 오류를 식별하고 수정하도록 돕습니다. 바운딩 박스를 그리고, 클래스 이름으로 객체에 레이블을 지정하며, 가독성을 높이기 위해 배경의 휘도에 따라 텍스트 색상을 조정합니다.

from ultralytics.data.utils import visualize_image_annotations

label_map = {  # 주석이 지정된 모든 클래스 레이블을 포함하는 레이블 맵을 정의합니다.
    0: "person",
    1: "car",
}

# Visualize
visualize_image_annotations(
    "path/to/image.jpg",  # 입력 이미지 경로입니다.
    "path/to/annotations.txt",  # 이미지의 주석 파일 경로입니다.
    label_map,
)

세그멘테이션 마스크를 YOLO 형식으로 변환#

세그멘테이션 마스크를 YOLO 형식으로 변환

세그멘테이션 마스크 이미지 데이터셋을 Ultralytics YOLO 세그멘테이션 형식으로 변환할 때 사용합니다. 이 함수는 바이너리 형식의 마스크 이미지가 포함된 디렉터리를 입력받아 YOLO 세그멘테이션 형식으로 변환합니다.

변환된 마스크는 지정된 출력 디렉터리에 저장됩니다.

from ultralytics.data.converter import convert_segment_masks_to_yolo_seg

# `classes`는 데이터셋에 포함된 전체 클래스 수입니다.
# COCO 데이터셋에는 클래스가 80개 있습니다.
convert_segment_masks_to_yolo_seg(masks_dir="path/to/masks_dir", output_dir="path/to/output_dir", classes=80)

COCO를 YOLO 형식으로 변환#

COCO JSON 주석을 YOLO 형식으로 변환할 때 사용합니다. 객체 감지(바운딩 박스) 데이터셋의 경우 use_segments과 use_keypoints를 모두 False으로 설정하세요.

from ultralytics.data.converter import convert_coco

convert_coco(
    "coco/annotations/",
    use_segments=False,
    use_keypoints=False,
    cls91to80=True,
)

convert_coco 함수에 대한 자세한 내용은 참고 페이지를 참조하세요.

바운딩 박스 크기 가져오기#

import cv2

from ultralytics import YOLO
from ultralytics.utils.plotting import Annotator

model = YOLO("yolo26n.pt")  # Load pretrain or fine-tune model

# Process the image
source = cv2.imread("path/to/image.jpg")
results = model(source)

# Extract results
annotator = Annotator(source, example=model.names)

for box in results[0].boxes.xyxy.cpu():
    width, height, area = annotator.get_bbox_dimension(box)
    print(f"Bounding Box Width {width.item()}, Height {height.item()}, Area {area.item()}")

바운딩 박스를 세그먼트로 변환#

기존 x y w h 바운딩 박스 데이터가 있는 경우 yolo_bbox2segment 함수를 사용해 세그먼트로 변환할 수 있습니다. 이미지와 주석 파일을 다음과 같이 구성하세요.

data
|__ images
    ├─ 001.jpg
    ├─ 002.jpg
    ├─ ..
    └─ NNN.jpg
|__ labels
    ├─ 001.txt
    ├─ 002.txt
    ├─ ..
    └─ NNN.txt
from ultralytics.data.converter import yolo_bbox2segment

yolo_bbox2segment(
    im_dir="path/to/images",
    save_dir=None,  # 이미지 디렉터리 옆의 "labels-segment"에 저장됨
    sam_model="sam_b.pt",
)

함수에 대한 자세한 내용은 yolo_bbox2segment 참고 페이지를 참조하세요.

세그먼트를 바운딩 박스로 변환#

세그멘테이션 데이터셋 형식을 사용하는 데이터셋이 있다면 이 함수를 사용해 세그먼트를 수직(또는 수평) 바운딩 박스(x y w h 형식)로 간편하게 변환할 수 있습니다.

import numpy as np

from ultralytics.utils.ops import segments2boxes

segments = np.array(
    [
        [805, 392, 797, 400, 812, 402, 808, 714, 808, 392],
        [115, 398, 113, 400, 150, 410, 150, 400, 149, 298],
        [267, 412, 265, 413, 300, 420, 300, 413, 299, 412],
    ],
    dtype=np.float32,
)

segments2boxes([s.reshape(-1, 2) for s in segments])
# >>> array([[804.5, 553. ,  15. , 322. ],
#           [131.5, 354. ,  37. , 112. ],
#           [282.5, 416. ,  35. ,   8. ]],
# dtype=float32) # xywh 바운딩 박스

이 함수의 작동 방식을 알아보려면 참고 페이지를 참조하세요.

유틸리티#

이미지 압축#

가로 세로 비율과 품질을 유지하면서 단일 이미지 파일의 크기를 줄입니다. 입력 이미지가 최대 크기보다 작으면 크기를 조정하지 않습니다.

from pathlib import Path

from ultralytics.data.utils import compress_one_image

for f in Path("path/to/dataset").rglob("*.jpg"):
    compress_one_image(f)

데이터셋 자동 분할#

데이터셋을 train/val/test 분할 세트로 자동 분할하고, 결과 분할 정보를 autosplit_*.txt 파일에 저장합니다. 이 유틸리티는 영구적인 분할 파일을 생성합니다. 반면 fraction 학습 인수는 실행마다 재현 가능한 하위 집합을 선택합니다.

from ultralytics.data.split import autosplit

autosplit(
    path="path/to/images",
    weights=(0.9, 0.1, 0.0),  # (학습, 검증, 테스트) 분할 비율
    annotated_only=False,  # True인 경우 주석 파일이 있는 이미지만 분할
)

이 함수에 대한 자세한 내용은 참고 페이지를 참조하세요.

세그먼트 폴리곤을 바이너리 마스크로 변환#

단일 폴리곤(리스트 형식)을 지정된 이미지 크기의 바이너리 마스크로 변환합니다. 폴리곤은 폴리곤 윤곽을 정의하는 x, y 값이 번갈아 나열된 N 좌표의 1D 평탄 배열이어야 합니다.

경고

N은 항상 짝수여야 합니다.

import numpy as np

from ultralytics.data.utils import polygon2mask

imgsz = (1080, 810)
polygon = np.array([805, 392, 797, 400, ..., 808, 714, 808, 392])  # (N,) 평탄한 x, y 좌표

mask = polygon2mask(
    imgsz,  # tuple
    [polygon],  # 리스트로 입력
    color=255,  # 8비트 바이너리
    downsample_ratio=1,
)

바운딩 박스#

바운딩 박스(수평) 인스턴스#

바운딩 박스 데이터를 관리하기 위해 Bboxes 클래스는 박스 좌표 형식 간 변환, 박스 크기 조정, 면적 계산, 오프셋 적용 등을 지원합니다.

import numpy as np

from ultralytics.utils.instance import Bboxes

boxes = Bboxes(
    bboxes=np.array(
        [
            [22.878, 231.27, 804.98, 756.83],
            [48.552, 398.56, 245.35, 902.71],
            [669.47, 392.19, 809.72, 877.04],
            [221.52, 405.8, 344.98, 857.54],
            [0, 550.53, 63.01, 873.44],
            [0.0584, 254.46, 32.561, 324.87],
        ]
    ),
    format="xyxy",
)

boxes.areas()
# >>> array([ 4.1104e+05,       99216,       68000,       55772,       20347,      2288.5])

boxes.convert("xywh")
print(boxes.bboxes)
# >>> array(
#     [[ 413.93, 494.05,  782.1, 525.56],
#      [ 146.95, 650.63,  196.8, 504.15],
#      [  739.6, 634.62, 140.25, 484.85],
#      [ 283.25, 631.67, 123.46, 451.74],
#      [ 31.505, 711.99,  63.01, 322.91],
#      [  16.31, 289.67, 32.503,  70.41]]
# )

더 많은 속성과 메서드는 Bboxes 참고 섹션을 참조하세요.

팁

다음 함수를 비롯한 여러 함수를 Bboxes 클래스를 통해 사용할 수 있습니다. 함수를 직접 사용하려면 다음 하위 섹션에서 개별적으로 가져오는 방법을 확인하세요.

박스 크기 조정#

이미지 크기를 키우거나 줄일 때 ultralytics.utils.ops.scale_boxes을 사용하면 해당 바운딩 박스 좌표도 이미지에 맞게 적절히 조정할 수 있습니다.

import cv2 as cv
import numpy as np

from ultralytics.utils.ops import scale_boxes

image = cv.imread("ultralytics/assets/bus.jpg")
h, w, c = image.shape
resized = cv.resize(image, None, fx=1.2, fy=1.2)
new_h, new_w, _ = resized.shape

xyxy_boxes = np.array(
    [
        [22.878, 231.27, 804.98, 756.83],
        [48.552, 398.56, 245.35, 902.71],
        [669.47, 392.19, 809.72, 877.04],
        [221.52, 405.8, 344.98, 857.54],
        [0, 550.53, 63.01, 873.44],
        [0.0584, 254.46, 32.561, 324.87],
    ]
)

new_boxes = scale_boxes(
    img1_shape=(h, w),  # 원본 이미지 크기
    boxes=xyxy_boxes,  # 원본 이미지의 박스
    img0_shape=(new_h, new_w),  # 크기를 조정할 이미지 크기
    ratio_pad=None,
    padding=False,
    xywh=False,
)

print(new_boxes)
# >>> array(
#     [[  27.454,  277.52,  965.98,   908.2],
#     [   58.262,  478.27,  294.42,  1083.3],
#     [   803.36,  470.63,  971.66,  1052.4],
#     [   265.82,  486.96,  413.98,    1029],
#     [        0,  660.64,  75.612,  1048.1],
#     [   0.0701,  305.35,  39.073,  389.84]]
# )

바운딩 박스 형식 변환#

XYXY → XYWH#

바운딩 박스 좌표를 (x1, y1, x2, y2) 형식에서 (x, y, 너비, 높이) 형식으로 변환합니다. 여기서 (x1, y1)은 왼쪽 위 모서리이고 (x2, y2)는 오른쪽 아래 모서리입니다.

import numpy as np

from ultralytics.utils.ops import xyxy2xywh

xyxy_boxes = np.array(
    [
        [22.878, 231.27, 804.98, 756.83],
        [48.552, 398.56, 245.35, 902.71],
        [669.47, 392.19, 809.72, 877.04],
        [221.52, 405.8, 344.98, 857.54],
        [0, 550.53, 63.01, 873.44],
        [0.0584, 254.46, 32.561, 324.87],
    ]
)
xywh = xyxy2xywh(xyxy_boxes)

print(xywh)
# >>> array(
#     [[ 413.93,  494.05,   782.1, 525.56],
#     [  146.95,  650.63,   196.8, 504.15],
#     [   739.6,  634.62,  140.25, 484.85],
#     [  283.25,  631.67,  123.46, 451.74],
#     [  31.505,  711.99,   63.01, 322.91],
#     [   16.31,  289.67,  32.503,  70.41]]
# )

모든 바운딩 박스 변환#

from ultralytics.utils.ops import (
    ltwh2xywh,
    ltwh2xyxy,
    xywh2ltwh,  # xywh → 왼쪽 위 모서리, w, h
    xywh2xyxy,
    xywhn2xyxy,  # 정규화 좌표 → 픽셀
    xyxy2ltwh,  # xyxy → 왼쪽 위 모서리, w, h
    xyxy2xywhn,  # 픽셀 → 정규화 좌표
)

for func in (ltwh2xywh, ltwh2xyxy, xywh2ltwh, xywh2xyxy, xywhn2xyxy, xyxy2ltwh, xyxy2xywhn):
    print(help(func))  # 함수 독스트링 출력

자세한 내용은 각 함수의 독스트링을 확인하거나 ultralytics.utils.ops 참고 페이지를 참조하세요.

플로팅#

주석 유틸리티#

Ultralytics에는 다양한 데이터 유형에 주석을 추가할 수 있는 Annotator 클래스가 포함되어 있습니다. 이 클래스는 객체 감지 바운딩 박스, 포즈 키포인트, 방향 바운딩 박스에 사용하는 것이 가장 적합합니다.

박스 주석#

Ultralytics YOLO를 사용하는 Python 예제 🚀
import cv2 as cv
import numpy as np

from ultralytics.utils.plotting import Annotator, colors

names = {
    0: "person",
    5: "bus",
    11: "stop sign",
}

image = cv.imread("ultralytics/assets/bus.jpg")
ann = Annotator(
    image,
    line_width=None,  # default auto-size
    font_size=None,  # default auto-size
    font="Arial.ttf",  # must be ImageFont compatible
    pil=False,  # use PIL, otherwise uses OpenCV
)

xyxy_boxes = np.array(
    [
        [5, 22.878, 231.27, 804.98, 756.83],  # class-idx x1 y1 x2 y2
        [0, 48.552, 398.56, 245.35, 902.71],
        [0, 669.47, 392.19, 809.72, 877.04],
        [0, 221.52, 405.8, 344.98, 857.54],
        [0, 0, 550.53, 63.01, 873.44],
        [11, 0.0584, 254.46, 32.561, 324.87],
    ]
)

for nb, box in enumerate(xyxy_boxes):
    c_idx, *box = box
    label = f"{str(nb).zfill(2)}:{names.get(int(c_idx))}"
    ann.box_label(box, label, color=colors(c_idx, bgr=True))

image_with_bboxes = ann.result()

감지 결과를 처리할 때 model.names의 이름을 사용할 수 있습니다. 자세한 내용은 Annotator 참고 페이지도 참조하세요.

Ultralytics 스윕 주석#

Ultralytics 유틸리티를 사용한 스윕 주석
import sys

import cv2
import numpy as np

from ultralytics import YOLO
from ultralytics.solutions.solutions import SolutionAnnotator
from ultralytics.utils.plotting import colors

# User defined video path and model file
cap = cv2.VideoCapture("path/to/video.mp4")
model = YOLO(model="yolo26s-seg.pt")  # Model file, e.g., yolo26s.pt or yolo26m-seg.pt

if not cap.isOpened():
    print("Error: Could not open video.")
    sys.exit()

# Initialize the video writer object.
w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS))
video_writer = cv2.VideoWriter("ultralytics.avi", cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))

masks = None  # Initialize variable to store masks data
f = 0  # Initialize frame count variable for enabling mouse event.
line_x = w  # Store width of line.
dragging = False  # Initialize bool variable for line dragging.
classes = model.names  # Store model classes names for plotting.
window_name = "Ultralytics Sweep Annotator"

def drag_line(event, x, _, flags, param):
    """Mouse callback function to enable dragging a vertical sweep line across the video frame."""
    global line_x, dragging
    if event == cv2.EVENT_LBUTTONDOWN or (flags & cv2.EVENT_FLAG_LBUTTON):
        line_x = max(0, min(x, w))
        dragging = True

while cap.isOpened():  # Loop over the video capture object.
    ret, im0 = cap.read()
    if not ret:
        break
    f = f + 1  # Increment frame count.
    count = 0  # Re-initialize count variable on every frame for precise counts.
    results = model.track(im0, persist=True)[0]

    if f == 1:
        cv2.namedWindow(window_name)
        cv2.setMouseCallback(window_name, drag_line)

    annotator = SolutionAnnotator(im0)

    if results.boxes.is_track:
        if results.masks is not None:
            masks = [np.array(m, dtype=np.int32) for m in results.masks.xy]

        boxes = results.boxes.xyxy.tolist()
        track_ids = results.boxes.id.int().cpu().tolist()
        clss = results.boxes.cls.cpu().tolist()

        for mask, box, cls, t_id in zip(masks or [None] * len(boxes), boxes, clss, track_ids):
            color = colors(t_id, True)  # Assign different color to each tracked object.
            label = f"{classes[cls]}:{t_id}"
            if mask is not None and mask.size > 0:
                if box[0] > line_x:
                    count += 1
                    cv2.polylines(im0, [mask], True, color, 2)
                    x, y = mask.min(axis=0)
                    (w_m, _), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
                    cv2.rectangle(im0, (x, y - 20), (x + w_m, y), color, -1)
                    cv2.putText(im0, label, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
            else:
                if box[0] > line_x:
                    count += 1
                    annotator.box_label(box=box, color=color, label=label)

    # Generate draggable sweep line
    annotator.sweep_annotator(line_x=line_x, line_y=h, label=f"COUNT:{count}")

    cv2.imshow(window_name, im0)
    video_writer.write(im0)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

# Release the resources
cap.release()
video_writer.release()
cv2.destroyAllWindows()

sweep_annotator 메서드에 대한 자세한 내용은 참고 섹션의 여기에서 확인하세요.

적응형 레이블 주석#

SolutionAnnotator.adaptive_label은 shape 인수로 모양을 지정하는 레이블을 그립니다(이 인수는 이전의 circle_label 및 text_label 메서드를 대체합니다).

  • 사각형: annotator.adaptive_label(box, label=names[int(cls)], color=colors(cls, True), shape="rect")
  • 원: annotator.adaptive_label(box, label=names[int(cls)], color=colors(cls, True), shape="circle")


시청: Python 라이브 데모로 알아보는 텍스트 및 원형 주석 심층 가이드 | Ultralytics 주석 🚀
Ultralytics 유틸리티를 사용한 적응형 레이블 주석
import cv2

from ultralytics import YOLO
from ultralytics.solutions.solutions import SolutionAnnotator
from ultralytics.utils.plotting import colors

model = YOLO("yolo26s.pt")
names = model.names
cap = cv2.VideoCapture("path/to/video.mp4")

w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS))
writer = cv2.VideoWriter("Ultralytics circle annotation.avi", cv2.VideoWriter_fourcc(*"MJPG"), fps, (w, h))

while True:
    ret, im0 = cap.read()
    if not ret:
        break

    annotator = SolutionAnnotator(im0)
    results = model.predict(im0)[0]
    boxes = results.boxes.xyxy.cpu()
    clss = results.boxes.cls.cpu().tolist()

    for box, cls in zip(boxes, clss):
        annotator.adaptive_label(box, label=names[int(cls)], color=colors(cls, True), shape="circle")
    writer.write(im0)
    cv2.imshow("Ultralytics circle annotation", im0)

    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

writer.release()
cap.release()
cv2.destroyAllWindows()

자세한 내용은 SolutionAnnotator 참조 페이지를 확인하세요.

기타#

코드 프로파일링#

with을 사용하거나 데코레이터를 적용하여 코드의 실행 또는 처리 시간을 확인합니다.

from ultralytics.utils.ops import Profile

with Profile(device="cuda:0") as dt:
    pass  # 측정할 작업

print(dt)
# >>> "경과 시간은 9.5367431640625e-07초입니다"

Ultralytics 지원 형식#

Ultralytics에서 지원하는 이미지 또는 동영상 형식을 프로그래밍 방식으로 사용해야 하나요? 필요한 경우 다음 상수를 사용하세요:

from ultralytics.data.utils import IMG_FORMATS, VID_FORMATS

print(IMG_FORMATS)
# {'avif', 'bmp', 'dng', 'heic', 'heif', 'jp2', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp'}

print(VID_FORMATS)
# {'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv', 'webm'}

배수로 만들기#

x 이상이면서 y로 나누어떨어지는 가장 작은 정수를 계산합니다.

from ultralytics.utils.ops import make_divisible

make_divisible(7, 3)
# >>> 9
make_divisible(7, 2)
# >>> 8

자주 묻는 질문#

  • Ultralytics 패키지에는 머신러닝 워크플로를 간소화하고 최적화하도록 설계된 유틸리티가 포함되어 있습니다. 주요 유틸리티에는 데이터셋 레이블링을 위한 자동 어노테이션, COCO를 YOLO 형식으로 변환하는 convert_coco, 이미지 압축, 데이터셋 자동 분할이 있습니다. 이러한 도구는 수작업을 줄이고 일관성을 보장하며 데이터 처리 효율을 높입니다.

  • 사전 학습된 Ultralytics YOLO 객체 감지 모델이 있다면, SAM 모델과 함께 사용하여 데이터셋에 세그멘테이션 형식으로 자동 어노테이션을 적용할 수 있습니다. 예시는 다음과 같습니다:

    from ultralytics.data.annotator import auto_annotate
    
    auto_annotate(
        data="path/to/new/data",
        det_model="yolo26n.pt",
        sam_model="mobile_sam.pt",
        device="cuda",
        output_dir="path/to/save_labels",
    )

    자세한 내용은 auto_annotate 참조 섹션을 확인하거나, 코드 작성 없이 호스팅 방식으로 사용할 수 있는 대안인 Ultralytics Platform을 이용하세요. SAM 2.1, SAM 3 또는 SAM 3.1을 사용한 클릭 기반 마스킹이나, 감지, 세그멘테이션, OBB 작업을 위한 사전 학습 및 파인튜닝된 YOLO 모델의 예측을 지원합니다.

  • 객체 감지를 위해 COCO JSON 어노테이션을 YOLO 형식으로 변환하려면 convert_coco 유틸리티를 사용할 수 있습니다. 코드 예제는 다음과 같습니다:

    from ultralytics.data.converter import convert_coco
    
    convert_coco(
        "coco/annotations/",
        use_segments=False,
        use_keypoints=False,
        cls91to80=True,
    )

    자세한 내용은 convert_coco 참조 페이지를 확인하세요.

  • Ultralytics Platform은 데이터셋 분석을 자동으로 수행합니다. Charts 탭에서 데이터 분할 분포, 상위 클래스 개수, 이미지 크기 히스토그램, 어노테이션 위치의 2D 히트맵을 확인하여 학습 전에 불균형과 이상치를 파악할 수 있습니다.

  • 기존 바운딩 박스 데이터(x y w h 형식)를 세그먼트로 변환하려면 yolo_bbox2segment 함수를 사용할 수 있습니다. 이미지와 레이블을 별도의 디렉터리에 정리해야 합니다.

    from ultralytics.data.converter import yolo_bbox2segment
    
    yolo_bbox2segment(
        im_dir="path/to/images",
        save_dir=None,  # 이미지 디렉터리 옆의 "labels-segment"에 저장됨
        sam_model="sam_b.pt",
    )

    자세한 내용은 yolo_bbox2segment 참조 페이지를 확인하세요.

댓글