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の場合、アノテーションファイルがある画像のみを分割します
)

この関数の詳細については、リファレンスページを参照してください。

セグメントポリゴンからバイナリマスクへの変換#

単一のポリゴン(リスト形式)を、指定した画像サイズのバイナリマスクに変換します。ポリゴンは、ポリゴンの輪郭を定義するN座標を1次元配列に並べたもので、x, yの値が交互に続く必要があります。

警告

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,) 形式の1次元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, width, height)形式に変換します。(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))  # 関数のdocstringを出力

詳細については、各関数のdocstringを参照するか、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)
# >>> "Elapsed time is 9.5367431640625e-07 s"

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を利用でき、事前学習済みおよびファインチューニング済みのYOLOモデルによるdetect、segment、OBBタスクの予測も利用できます。

  • 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リファレンスページをご覧ください。

コメント