【第9週】物体の検出と領域の認識(img2box)
講義目録:即戦力化 ディープラーニング実習
はじめに
第9週では 「物体の検出(Object Detection)と領域の認識(Segmentation)」 を扱います。
これまでに学んだ 画像生成 → 特徴抽出 の流れをさらに発展させ、画像のどこに何が写っているのか をピクセルレベルで把握する手法を体験します。
自動運転・医用画像・ドローン点検・AR/VR などの実サービスは、ほぼ例外なくこの技術を土台にしています。
体験する内容は、次のgoogle colabで確認できます。
Google Colabへのリンク
1. 実習の目的
目標 | 内容 |
---|---|
① 物体検出 (img2box) | YOLOv8 を用いて 画像内の物体にバウンディングボックスを描画し,クラス名・信頼度を取得 |
② インスタンスセグメンテーション | Mask R-CNN/YOLOv8‑Seg で 物体ごとのマスク を生成し,背景と分離 |
③ セマンティックセグメンテーション | COCO Panoptic で 画素ごとにラベル を付与し,シーン全体を色分け |
実装はすべて Google Colab + PyTorch で完結します。
2. 物体の検出と領域の認識
2-1. 物体の検出とは
-
目的
画像(または動画フレーム)を入力し,矩形(バウンディングボックス)とクラスラベル を返す。x, y, w, h, class_id, confidence
-
代表的アーキテクチャ
系列 例 特徴 2‑stage Faster R‑CNN Region Proposal → 分類。精度高だが遅め 1‑stage YOLOv8, SSD 画像をグリッドに分割して一括予測。高速・軽量 ViT系 DETR, DINO Transformer で end‑to‑end。後処理最小 -
評価指標
- IoU (Intersection over Union) ― GT box との重なり率
- mAP (mean Average Precision) ― IoU > 0.5 / 0.75 など複数しきい値で平均
-
応用例
歩行者検出、自動レジ、工場ラインの不良品検出、ドローンの障害物回避 など
2-2. 領域の認識とは
物体検出が「箱で囲む」のに対し,領域認識は ピクセル単位でクラスを判定 します。目的により次の 2 系統があります。
区分 | 例 | 出力 | 主な用途 |
---|---|---|---|
セマンティックセグメンテーション | U‑Net, DeepLab v3+ | 各ピクセルに背景・道路・空・建物 … の カテゴリ ID | 自動運転の路面把握,衛星画像の土地利用分類 |
インスタンスセグメンテーション | Mask R‑CNN, YOLOv8‑Seg, Segment Anything | 物体ごと に独立したマスク | AR合成,フォトレタッチ,医用臓器抽出 |
-
マスク品質指標
- Dice Coefficient / F1‑score
- Panoptic Quality (PQ) — インスタンス + セマンティックの複合指標
-
近年のトレンド
- Zero‑Shot Segmentation:テキストプロンプトだけで未知クラスに対応(Segment Anything + CLIP)
- リアルタイム対応:Mobile‑Seg, YOLACT++ でスマホやエッジデバイス実装が加速
次章からは Colab ノートに沿って
- 学習済み YOLOv8 をダウンロード → 物体検出 → 可視化
- 同じモデルの YOLOv8‑Seg 重み に差し替えてマスク生成
- mAP・IoU を
torchmetrics
で算出
という流れで手を動かします。
物体検出・セグメンテーションは “画像理解の最終目的地” とも言える重要テーマです。
ここで得た知識は第10週の 画像の分類と応用 に直結します。準備ができたらコードを実行して結果を確認してみましょう。
3. 物体検出 (Object Detection)
ここでは YOLOv8n(Nano モデル)を使ってサンプル画像に写る物体を検出します。
その後、結果を可視化します。
3‑1. 環境準備
# 1) ランタイム準備 ─ ultralytics を CPU 環境にインストール
!pip -q install --upgrade ultralytics
3‑2. モデル読込
YOLOv8を読み込みます。
from ultralytics import YOLO
model = YOLO("yolov8n.pt") # COCO 80 クラス学習済み (Nano)
3‑3. 画像の取得
import requests, io
from PIL import Image
sample1_url = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526647/156b4b90-24bc-42f1-a3c2-0430c96b831d.png"
def load_rgb(url:str):
r = requests.get(url)
r.raise_for_status()
return Image.open(io.BytesIO(r.content)).convert("RGB")
sample1 = load_rgb(sample1_url)
次の画像をsample1として読み込みました。
3‑4. 物体検出 (推論)
results1 = model(sample1, imgsz=640, conf=0.25, save=True)
3‑5. 結果の可視化
from pathlib import Path
from IPython.display import display
# 推論結果画像を表示するユーティリティ
def show(results):
pred_path = Path(results[0].save_dir) / Path(results[0].path).name
display(Image.open(pred_path))
show(results1)
これにより次のような図が表示されます。
画像には、物体として、リンゴ、コップ、バナナ、ナイフ、食卓が移っていると判定されています。
物体名横の数字は、その物体が写っている確率を指しています。
「リンゴが90%の確率で存在する」という意味です。
食卓の確率は28%とだいぶん低いですね。
3‑6. 検出結果の一覧と信頼度
検出結果を図ではなく、数字として表示します。
# 1 枚目の検出オブジェクトを (クラス名, conf, x1,y1,x2,y2) で列挙
for cls_id, conf, box in zip(results1[0].boxes.cls,
results1[0].boxes.conf,
results1[0].boxes.xyxy):
label = model.names[int(cls_id)]
x1, y1, x2, y2 = box.tolist()
print(f"{label:<12} conf={conf:.2f} box=({x1:.0f},{y1:.0f},{x2:.0f},{y2:.0f})")
これで YOLOv8 による物体検出の基本フロー が再現できました。
実習
次の画像 sample2 に対して物体検出を行ってください。
この画像のURLは次の通りです。
sample2_url = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526647/85a14455-3e53-4907-850c-815e27453c85.png"
次節では同じ画像に インスタンスセグメンテーション を適用して、ピクセルレベルのマスク生成を体験します。
4. インスタンスセグメンテーション (Instance Segmentation)
ここでは YOLOv8‑Seg を用いて、先ほどと同じサンプル画像に対して 物体ごとのピクセルマスク を生成します。
4‑1. モデル読込(Segmentation 用)
from ultralytics import YOLO
seg_model = YOLO("yolov8n-seg.pt") # Nano のセグメンテーション版
4‑2. YOLOv8による推論
seg_results1 = seg_model(sample1, imgsz=640, conf=0.25, save=True)
4‑3. 結果の可視化
from pathlib import Path
from IPython.display import display
from PIL import Image
# 予測画像の表示
def show_seg(res):
pred_path = Path(res[0].save_dir) / Path(res[0].path).name
display(Image.open(pred_path))
show_seg(seg_results1)
出力される画像はこちらです。
検出した物体だけに色が塗られていることがわかるでしょうか?
参考までに元画像も張っておきますね。
4‑4. 検出インスタンスの一覧とマスク枚数
# 例: 1 枚目の結果をプリント
seg_boxes = seg_results1[0].boxes # バウンディングボックス
seg_masks = seg_results1[0].masks # マスク (N, H, W)
print(f"Detected instances : {len(seg_boxes)}")
print(f"Mask tensor shape : {seg_masks.data.shape}") # (N,H,W)
# ラベルと信頼度を列挙
for cls_id, conf in zip(seg_boxes.cls, seg_boxes.conf):
label = seg_model.names[int(cls_id)]
print(f"{label:<12} conf={conf:.2f}")
結果は次のようになります。4種類の物体が検出されています。
Detected instances : 4
Mask tensor shape : torch.Size([4, 448, 640])
cup conf=0.93
apple conf=0.80
knife conf=0.72
banana conf=0.69
4-5. 検出インスタンスの場所を表す画像
次に、検出された物体(インスタンス)の位置を表す図を出力しましょう。
# マスク画像の可視化
import matplotlib.pyplot as plt
for i, mask in enumerate(seg_masks.data):
plt.figure(figsize=(3, 3))
plt.title(f"instance {i}: {seg_model.names[int(seg_boxes.cls[i])]} ({seg_boxes.conf[i]:.2f})")
plt.axis('off')
# mask は 0/1 (bool) の形状 (H, W)。cmap='gray' で白黒表示
plt.imshow(mask.cpu(), cmap='gray')
plt.show()
コップ、リンゴ、ナイフ、バナナの場所が検出できていることがわかります。
元画像と見比べてみてくださいね
実習
画像 sample2 に対して物体検出を行ってください。
この画像のURLは次の通りです。
sample2_url = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526647/85a14455-3e53-4907-850c-815e27453c85.png"
これで インスタンスセグメンテーションの基礎フロー を体験できました。次節ではセマンティックセグメンテーション(画素ごとカテゴリ分類)の手法とコード例へと進みます。
5. セマンティックセグメンテーション
ここでは、Facebook Research が公開する DETR‑R50‑Panoptic を用います。
このモデルは banana, apple, knife など 133 クラスの物体検出が可能です。
では③セマンティックセグメンテーションを実行しましょう。
画像内のすべてのピクセルにカテゴリ ID を割り当て、シーン全体を色分けします。
利用する画像はこれまでと同じ sample1 (リンゴやバナナが写った画像)です。
5‑1. モデル読込と前処理
# transformers 4.40 以降で Panoptic API が利用可能
!pip -q install --upgrade "transformers>=4.40" pillow
# DETR-R50 Panoptic 用クラスを使用
from transformers import DetrImageProcessor, DetrForSegmentation
import torch, numpy as np, matplotlib.pyplot as plt
from PIL import Image
import io, requests
# 1️⃣ モデル&プロセッサをロード
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50-panoptic")
pan_model = DetrForSegmentation.from_pretrained(
"facebook/detr-resnet-50-panoptic"
).eval()
5-2. 推論実行
先ほどと同じsample1の画像に対して、セマンティックセグメンテーションを実行します。
with torch.no_grad():
inputs = processor(images=sample1, return_tensors="pt")
outputs = pan_model(**inputs)
# 元画像サイズにリサイズして panoptic 形式へ
processed = processor.post_process_panoptic_segmentation(
outputs, target_sizes=[sample1.size[::-1]] # (H,W)
)[0]
seg_map = processed["segmentation"] # (H,W) tensor, 各ピクセル=segment_id
segments_info = processed["segments_info"] # list(dict) with label_id & score
これで推論は終わりです。
とっても簡単ですね。
5-3. 可視化
それでは、解析結果を表示していきましょう。
num_segments = seg_map.max().item() + 1
palette = np.random.randint(0, 255, size=(num_segments, 3), dtype=np.uint8)
palette[0] = (0,0,0) # 背景
colored = palette[seg_map.numpy()] # (H,W,3) uint8
plt.figure(figsize=(6,3))
plt.suptitle("Sample1: Panoptic Segmentation", fontsize=14)
plt.subplot(1,2,1)
plt.title("Original")
plt.axis('off'); plt.imshow(sample1)
plt.subplot(1,2,2)
plt.title("Segmentation")
plt.axis('off'); plt.imshow(colored)
plt.show()
このように、画面上の全ピクセルに対して、何が写っているのかを示すセグメントを表示してくれます。
赤はリンゴで、白はコップですね。
では、左上の赤紫はなんでしょう?
これを次に見ていきたいと思います。
5-4. 検出クラス一覧
from IPython.display import HTML, display
id2label = pan_model.config.id2label # 133 クラス
rows = ""
for seg in segments_info:
seg_id = seg["id"] # セグメント固有 ID
cid = seg["label_id"] # COCO クラス ID
score = seg["score"] # 信頼度
label = id2label[cid]
rgb = palette[seg_id]
hexcol = f"#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}"
rows += f"<tr><td>{seg_id}</td><td>{label}</td><td>{score:.3f}</td><td style='background:{hexcol};width:40px;'></td><td>{hexcol}</td></tr>"
html = f"""
<table>
<tr><th>seg_id</th><th>label</th><th>score</th><th>color</th><th>hex</th></tr>
{rows}
</table>
"""
display(HTML(html))
"""
display(HTML(html))
これで、色が示す物体名がわかります。
赤紫は、オーブンだったのですね。 えっオーブン? 私にはよくわかりません。
ま、そういうものとしておきましょう。
5-5. 実習
sample2.png に対しても、セマンティックセグメンテーションを実行しましょう。
5-6. ポイントまとめ
-
segments_info に
label_id
とscore
(信頼度)が含まれます。 - COCO 133 クラス完全一覧は
pan_model.config.id2label
で取得可能。 -
palette
を固定値にすればクラスごと同じ色で描画することもできます。
6.まとめ
今週は 「物体検出 → インスタンスセグメンテーション → セマンティック(パノプティック)セグメンテーション」 という三段階で、画像理解を “箱” から “ピクセル” へと深掘りしました。
ステップ | 使用モデル | 出力 | 主なコードポイント |
---|---|---|---|
① 物体検出 | YOLOv8n | バウンディングボックス+ラベル+信頼度 |
results = model(img) → results[0].boxes
|
② インスタンスSeg | YOLOv8n‑Seg | 物体ごとのマスク |
results[0].masks を可視化・後処理 |
③ セマンティックSeg | DETR‑R50 Panoptic (COCO 133) | ピクセル単位ラベル+segments_info | processor.post_process_panoptic_segmentation() |
画像理解は「何が写っているか」だけでなく、「どこに写っているか」を把握することにより応用範囲が広がり明日。
今回の3技術は、画像処理タスクの基礎となります。
そして画像処理はとっても広いため、知っていて損のない技術なのです。
🔭 次回予告:「第10週 画像の分類と応用」
次週(第十週)は、「画像分類とその応用」 に取り組みます。
畳み込みニューラルネットワーク(CNN)を軸に、事前学習モデルの転移学習・ファインチューニングで分類性能を高めるプロセスを体験し、医用診断や不良品検査など実サービスへ展開するヒントまでをカバーする予定です。