Ultralytics YOLOを使用してセグメンテーションオブジェクトを分離する方法#
インスタンスセグメンテーションは検出されたすべてのオブジェクトに対してピクセル単位で正確なマスクを生成するため、画像からそれぞれのオブジェクトを個別に切り抜くことができます。このガイドでは、Predict ModeとOpenCVを使用して、Ultralytics YOLOのセグメンテーション結果からオブジェクトを抽出し、単色の黒背景または透明背景でPNGとして保存する方法を説明します。
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")model.predict() を source なしで呼び出した場合、Ultralytics はパッケージに同梱されているサンプル画像(bus.jpg および zidane.jpg)にフォールバックします。これはワークフローを素早くテストする際に便利です。
オブジェクトの輪郭の抽出#
results 内の各アイテムは1つの画像に対応しており、結果をイテレートすると1回に1つの検出結果が取得されます。検出ごとに元の画像をコピーし、クラスラベルを読み取り、オブジェクトのマスク輪郭を空白のバイナリマスクに描画します。このマスクの白い領域は、どのピクセルがオブジェクトに属しているかを正確に示します。
このセクションおよび次のセクションのコードスニペットは、以下の検出ループの内部で実行されます。コピー&ペーストしてそのまま使える完全なスクリプトは、Full Exampleにあります。
{ width="240", align="right" }
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]は、この単一検出結果におけるオブジェクトの mask 輪郭を(x, y)ポイント座標として返します。.astype(np.int32)は、OpenCV のdrawContours()が受け付けないfloat32からポイントを変換します。.reshape(-1, 1, 2)は、ポイントをdrawContours()が期待する[N, 1, 2]のレイアウトに再形状(リシェイプ)します。ここで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() に渡すと、マスクなしでバウンディングボックスのクロップが自動的に保存されます。
結果の保存 (オプション)#
分離した各オブジェクトをどう扱うかはユーザー次第です。一般的な次のステップは、後で使用するためにディスクに書き出すことです。
# 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)#
Ultralytics YOLOを使用してセグメンテーションタスクのオブジェクトを分離するにはどうすればよいですか?#
セグメンテーションモデルを読み込み、推論を実行し、各検出の輪郭からバイナリマスクを構築して、それを元の画像と組み合わせます。
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)検出ごとのループの完全なコードについては、Full Exampleを参照してください。
セグメンテーション後に分離したオブジェクトを保存するためのオプションにはどのようなものがありますか?#
主に2つのスタイルがあります。黒背景の場合は、マスクを3チャンネルに変換して cv2.bitwise_and() を使用します。透明背景(PNGとして保存する場合)の場合は、np.dstack([img, b_mask]) を使用してマスクを4つ目のアルファチャンネルとしてスタックします。どちらの方法もIsolate the Objectに示されています。
分離したオブジェクトをバウンディングボックスにクロップするにはどうすればよいですか?#
検出結果からバウンディングボックスの座標を読み取り、分離した画像に対してスライスを行います。
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を使用するべき理由は?#
Ultralytics YOLOは、正確なマスクとバウンディングボックスの生成を伴う高速なリアルタイムインスタンスセグメンテーションを提供し、推論結果を数行のOpenCVコードで分離オブジェクトに変換できるシンプルなPython APIを備えています。
Ultralytics YOLOを使用して、背景を含めた分離オブジェクトを保存できますか?#
はい。元の背景付きでバウンディングボックスの切り抜きを保存するには、predict() で save_crop 引数を使用します。
results = model.predict(source="path/to/your/image.jpg", save_crop=True)詳細については、Predict Mode Inference Argumentsセクションをお読みください。