Ultralytics YOLO27:

Ultralytics YOLOでセグメンテーションオブジェクトを分離する方法#

インスタンスセグメンテーションでは、検出された各オブジェクトに対してピクセル単位で正確なマスクが生成されるため、各オブジェクトを画像から個別に切り出せます。このガイドでは、Predict ModeとOpenCVを使用して、Ultralytics YOLOのセグメンテーション結果を分離したオブジェクトに変換する方法を説明します。保存時の背景には、単色の黒または透明を指定できます。



Watch: How to Remove Background and Isolate Objects with Ultralytics YOLO Segmentation & OpenCV in Python 🚀

セグメンテーションオブジェクトを分離する理由#

画像から個々のオブジェクトを切り出すことで、さまざまな後続ワークフローを実現できます。

  • 商品の撮影画像、カタログ、クリエイティブ編集での背景除去
  • 検出結果から分類データセットを構築するためのオブジェクトごとのクロップ
  • 後続のOCR、色分析、計測などの処理で、周囲のシーンではなくオブジェクトだけを対象にする対象を絞った処理
  • オブジェクトを新しい背景に合成するための透明PNGエクスポート

この手順は、すべてのUltralytics YOLOセグメンテーションモデルで使用でき、推論の実行各輪郭の抽出オブジェクトの分離結果の保存という4つの段階で構成されます。

セグメンテーション推論を実行する#

必要なライブラリをインストールし、セグメンテーションモデル(マスクの生成に必要な-segサフィックス)を読み込んで、入力画像に対して予測を実行します。

from ultralytics import YOLO

# Load a segmentation model
model = YOLO("yolo26n-seg.pt")

# Run inference on a source
results = model.predict(source="path/to/image.jpg")
入力画像がありませんか?YOLOは同梱のサンプル画像を使用します

sourceを指定せずにmodel.predict()を呼び出すと、Ultralyticsはパッケージに同梱されているサンプル画像(bus.jpgおよびzidane.jpg)にフォールバックします。これはワークフローをすばやくテストする場合に便利です。

オブジェクトの輪郭を抽出する#

resultsの各要素は1つの画像に対応し、結果を反復処理すると一度に1つの検出結果を取得できます。各検出結果について元の画像をコピーし、クラスラベルを読み取り、空のバイナリマスクにオブジェクトのマスク輪郭を描画します。このマスクの白い領域が、オブジェクトに属するピクセルを正確に示します。

このセクションと次のセクションのスニペットは、以下の検出ループの内部で実行します。コピーして実行できる完全なスクリプトは完全な例にあります。

Binary Mask Image
from pathlib import Path

import cv2
import numpy as np

for r in results:
    img = np.copy(r.orig_img)
    img_name = Path(r.path).stem  # source image base-name

    # Iterate each detected object in the image
    for ci, c in enumerate(r):
        label = c.names[c.boxes.cls.tolist().pop()]  # class name

        # Build a binary mask and draw the object contour onto it
        b_mask = np.zeros(img.shape[:2], np.uint8)
        contour = c.masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
        cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
`c.masks.xy[0].astype(np.int32).reshape(-1, 1, 2)`は何を行いますか?
  • c.masks.xy[0]は、この単一検出結果に含まれるオブジェクトのマスク輪郭を、(x, y)形式の点座標として返します。
  • .astype(np.int32)は、OpenCVのdrawContours()が受け付けないfloat32から、点を変換します。
  • .reshape(-1, 1, 2)は、点を[N, 1, 2]レイアウトに変形します。このレイアウトをdrawContours()が想定しており、Nは輪郭点の数を表します。

インデックス-1を指定して[contour]を渡すと、指定した輪郭のすべての点が描画され、cv2.FILLEDによって囲まれたすべてのピクセルが白で塗りつぶされます。

オブジェクトを分離する#

バイナリマスクの準備ができたら、元の画像と組み合わせます。背景をどのようにするかに応じて、一般的な方法は2つあります。

分離方法を選択する

マスクを3チャンネルに変換し、オブジェクトと重なるピクセルだけを残します。輪郭の外側はすべて黒になります。

# Isolate object with a black background
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img)
Example Full size Isolated Object Image Black Background
Full-size object on a black background
バウンディングボックスに合わせてクロップする

画像全体ではなくオブジェクトの領域だけを残すには、検出結果のバウンディングボックスに合わせてスライスします。

# Bounding box coordinates
x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# Crop the isolated image to the object region
iso_crop = isolated[y1:y2, x1:x2]
Example Crop Isolated Object Image Black Background
Object cropped to its bounding box
元の背景を含むクロップが必要ですか?

その機能は組み込まれています。save_crop=Truepredict()に渡すと、マスク処理を行わずに、Ultralyticsがバウンディングボックスのクロップを自動的に保存します。

結果を保存する(任意)#

分離した各オブジェクトをどう扱うかは自由です。一般的な次のステップは、後で使用できるようにディスクへ書き込むことです。

# Save the isolated object to file
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)

ここでは、img_nameが入力画像のステム、labelがクラス名、ciが検出インデックスです。そのため、同じクラスの複数のインスタンスにも一意のファイル名が付けられます。上記の任意のクロップを適用した場合は、isolatediso_cropに置き換えます。

完全な例#

以下のスクリプトは、すべての手順を1つの実行可能なブロックにまとめたものです。デフォルトでは黒い背景を使用します。透明PNGにするには、印の付いた1行をnp.dstack([img, b_mask])に変更します。

from pathlib import Path

import cv2
import numpy as np

from ultralytics import YOLO

model = YOLO("yolo26n-seg.pt")
results = model.predict(source="path/to/image.jpg")

for r in results:
    img = np.copy(r.orig_img)
    img_name = Path(r.path).stem

    for ci, c in enumerate(r):
        label = c.names[c.boxes.cls.tolist().pop()]

        # Build a binary mask from the object contour
        b_mask = np.zeros(img.shape[:2], np.uint8)
        contour = c.masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
        cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)

        # Isolate the object (black background)
        mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
        isolated = cv2.bitwise_and(mask3ch, img)  # transparent PNG: isolated = np.dstack([img, b_mask])

        # Save or add your custom post-processing here
        cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)

        # Optional: crop to the bounding box before saving
        # x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
        # cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated[y1:y2, x1:x2])

繰り返し使用する場合は、ループ本体を関数にまとめると、多数の画像に対して呼び出せます。

まとめ#

これで、Ultralytics YOLOでセグメンテーションオブジェクトを分離するための一連の手順が完成しました。推論を実行し、各輪郭からバイナリマスクを作成して、黒または透明の背景上にオブジェクトを抽出し、必要に応じてバウンディングボックスに合わせてクロップします。ワークフローを独自のクラスに適応するには、Segment TaskPredict Modeの完全なドキュメントを参照してください。

FAQ#

  • セグメンテーションモデルを読み込み、推論を実行し、各検出結果の輪郭からバイナリマスクを作成して、元の画像と組み合わせます。

    import cv2
    import numpy as np
    
    from ultralytics import YOLO
    
    model = YOLO("yolo26n-seg.pt")
    results = model.predict(source="path/to/your/image.jpg")
    
    img = np.copy(results[0].orig_img)
    b_mask = np.zeros(img.shape[:2], np.uint8)
    contour = results[0].masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
    cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
    
    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    isolated = cv2.bitwise_and(mask3ch, img)

    検出ごとの完全なループについては、完全な例を参照してください。

  • 主な方法は2つあります。黒い背景の場合は、マスクを3チャンネルに変換してcv2.bitwise_and()を使用します。透明な背景(PNGとして保存する場合)の場合は、np.dstack([img, b_mask])を使用してマスクを4番目のアルファチャンネルとして結合します。どちらの方法もオブジェクトを分離するで説明しています。

  • 検出結果からバウンディングボックスの座標を読み取り、分離した画像をスライスします。

    x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32)
    iso_crop = isolated[y1:y2, x1:x2]

    バウンディングボックスの結果について詳しくは、Predict Modeのドキュメントを参照してください。

  • Ultralytics YOLOは、正確なマスクとバウンディングボックスの生成に対応した高速なリアルタイムインスタンスセグメンテーションを提供します。さらに、シンプルなPython APIにより、数行のOpenCVコードで推論結果を分離したオブジェクトに変換できます。

  • はい。predict()save_crop引数を使用すると、元の背景を含むバウンディングボックスのクロップを保存できます。

    results = model.predict(source="path/to/your/image.jpg", save_crop=True)

    詳しくは、Predict Modeの推論引数セクションを参照してください。

コメント