1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

即戦力化 ディープラーニング実習(第九週)

Posted at

【第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 ノートに沿って

  1. 学習済み YOLOv8 をダウンロード → 物体検出 → 可視化
  2. 同じモデルの YOLOv8‑Seg 重み に差し替えてマスク生成
  3. 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として読み込みました。

sample1.png

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)

これにより次のような図が表示されます。

result1.png

画像には、物体として、リンゴ、コップ、バナナ、ナイフ、食卓が移っていると判定されています。

物体名横の数字は、その物体が写っている確率を指しています。

「リンゴが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 に対して物体検出を行ってください。

sample2.png

この画像の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 を用いて、先ほどと同じサンプル画像に対して 物体ごとのピクセルマスク を生成します。

サンプル画像 sample1
sample1.png

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)

出力される画像はこちらです。

result1_2.png

検出した物体だけに色が塗られていることがわかるでしょうか?

参考までに元画像も張っておきますね。

sample1.png

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()

コップ、リンゴ、ナイフ、バナナの場所が検出できていることがわかります。

mask1.png
mask2.png
mask3.png
mask4.png

元画像と見比べてみてくださいね

sample1.png


実習

画像 sample2 に対して物体検出を行ってください。

sample2.png

この画像の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()

result1_3.png

このように、画面上の全ピクセルに対して、何が写っているのかを示すセグメントを表示してくれます。

赤はリンゴで、白はコップですね。

では、左上の赤紫はなんでしょう?

これを次に見ていきたいと思います。

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))

これで、色が示す物体名がわかります。

result1_5.png

赤紫は、オーブンだったのですね。 えっオーブン? 私にはよくわかりません。

ま、そういうものとしておきましょう。


5-5. 実習

sample2.png に対しても、セマンティックセグメンテーションを実行しましょう。

5-6. ポイントまとめ

  • segments_infolabel_idscore(信頼度)が含まれます。
  • 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)を軸に、事前学習モデルの転移学習・ファインチューニングで分類性能を高めるプロセスを体験し、医用診断や不良品検査など実サービスへ展開するヒントまでをカバーする予定です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?