Ultralytics YOLOでセグメンテーションオブジェクトを分離する方法#
インスタンスセグメンテーションでは、検出したオブジェクトごとにピクセル単位で正確なマスクが生成されるため、各オブジェクトを画像から個別に切り出せます。このガイドでは、PredictモードとOpenCVを使用して、Ultralytics YOLOのセグメンテーション結果からオブジェクトを分離する方法を説明します。背景を黒または透明にして、PNGとして保存できます。
視聴: PythonでUltralytics YOLOのセグメンテーションとOpenCVを使用して背景を除去し、物体を切り出す方法 🚀
セグメンテーションオブジェクトを分離する理由#
画像から個々のオブジェクトを切り出すことで、さまざまな後続ワークフローを実現できます。
- 商品写真、カタログ、クリエイティブ編集のための背景除去。
- 検出結果から分類データセットを構築するためのオブジェクトごとのクロップ。
- OCR、色分析、測定などの後続処理で周囲のシーンではなくオブジェクトだけを対象にするための対象を絞った処理。
- オブジェクトを新しい背景に合成するための透明PNGエクスポート。
この手順は任意のUltralytics YOLOセグメンテーションモデルで使用でき、4つの段階で構成されます。推論を実行 → 各輪郭を抽出 → オブジェクトを分離 → 結果を保存。
セグメンテーション推論を実行する#
必要なライブラリをインストールし、セグメンテーションモデル(マスクの生成に必要な-segサフィックスを使用)を読み込んで、入力画像に対して予測を実行します。
from ultralytics import YOLO
# セグメンテーションモデルを読み込む
model = YOLO("yolo26n-seg.pt")
# 入力画像で推論を実行する
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 # 入力画像のベース名
# 画像内で検出された各オブジェクトを反復処理する
for ci, c in enumerate(r):
label = c.names[c.boxes.cls.tolist().pop()] # クラス名
# 二値マスクを作成し、オブジェクトの輪郭を描画する
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チャンネルに変換し、オブジェクトと重なるピクセルだけを残します。輪郭の外側はすべて黒になります。
# 黒い背景でオブジェクトを分離する
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img)
画像全体ではなくオブジェクトの領域だけを残すには、検出結果のバウンディングボックスに合わせてスライスします。
# バウンディングボックスの座標
x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# 分離した画像をオブジェクト領域に合わせてクロップする
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タスクとPredictモードのドキュメントをご覧ください。
よくある質問#
セグメンテーションモデルを読み込み、推論を実行し、各検出結果の輪郭から二値マスクを作成して、元の画像と組み合わせます。
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として保存する場合)には、マスクを4番目のアルファチャンネルとして重ね、np.dstack([img, b_mask])を使用します。どちらの方法もオブジェクトを分離するで説明しています。検出結果からバウンディングボックスの座標を読み取り、分離した画像をスライスします。
x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32) iso_crop = isolated[y1:y2, x1:x2]バウンディングボックスの結果について詳しくは、Predictモードのドキュメントをご覧ください。
Ultralytics YOLOは、高精度なマスクとバウンディングボックスを生成する、リアルタイムの高速なインスタンスセグメンテーションを提供します。また、推論結果から数行のOpenCVコードでオブジェクトを分離できる、シンプルなPython APIも備えています。
はい。
predict()でsave_crop引数を使用すると、元の背景を含むバウンディングボックスの切り抜きを保存できます。results = model.predict(source="path/to/your/image.jpg", save_crop=True)詳しくは、予測モードの推論引数のセクションをご覧ください。