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")sourceを指定せずにmodel.predict()を呼び出すと、Ultralyticsはパッケージに同梱されているサンプル画像(bus.jpgおよびzidane.jpg)にフォールバックします。これはワークフローをすばやくテストする場合に便利です。
オブジェクトの輪郭を抽出する#
resultsの各要素は1つの画像に対応し、結果を反復処理すると一度に1つの検出結果を取得できます。各検出結果について元の画像をコピーし、クラスラベルを読み取り、空のバイナリマスクにオブジェクトのマスク輪郭を描画します。このマスクの白い領域が、オブジェクトに属するピクセルを正確に示します。
このセクションと次のセクションのスニペットは、以下の検出ループの内部で実行します。コピーして実行できる完全なスクリプトは完全な例にあります。
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]は、この単一検出結果に含まれるオブジェクトのマスク輪郭を、(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)
画像全体ではなくオブジェクトの領域だけを残すには、検出結果のバウンディングボックスに合わせてスライスします。
# 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]
その機能は組み込まれています。save_crop=Trueをpredict()に渡すと、マスク処理を行わずに、Ultralyticsがバウンディングボックスのクロップを自動的に保存します。
結果を保存する(任意)#
分離した各オブジェクトをどう扱うかは自由です。一般的な次のステップは、後で使用できるようにディスクへ書き込むことです。
# Save the isolated object to file
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)ここでは、img_nameが入力画像のステム、labelがクラス名、ciが検出インデックスです。そのため、同じクラスの複数のインスタンスにも一意のファイル名が付けられます。上記の任意のクロップを適用した場合は、isolatedをiso_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 TaskとPredict 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の推論引数セクションを参照してください。