🔥

SAM3 テキストプロンプトでセグメンテーション

に公開

Metaから発表されたSAM3を試す。
SAM2にはなかったテキストによるプロンプトがサポートされたとのことで
これは、大喜びしている人は沢山いるんじゃないでしょうか。

Sam3 HP
https://ai.meta.com/sam3/

github repository
https://github.com/facebookresearch/sam3

install

実行環境はWSLのubuntu24.04を使用
Pythonはインストール済みで、バージョンは3.12.10

RTX 3060でやってみたらWSL自体が落ちてしまったので
RTX 4090を使用しています。

基本的にはGithubに書いてあることと同じ

Step 01 仮想環境を作る

python -m venv venv
source ./venv/bin/activate

Step 02 CUDAのインストール

pip install torch==2.7.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126

Step 03

リポジトリをクローンしてインストール

git clone https://github.com/facebookresearch/sam3.git
cd sam3
pip install -e .

ここまでだと、モジュールが足らないとエラーが出てしまうので
以下のコマンドを実行して足りないモジュールをインストールします。

pip install -e ".[notebooks]"

Step 04

基本的な使用

画像に対してテキストプロンプトを適用してみる

import sys
# sam3をモジュール検索パスに追加
sys.path.insert(0, './sam3/')

import torch
from PIL import Image, ImageDraw, ImageFont
import numpy as np
from sam3.model_builder import build_sam3_image_model
from sam3.model.sam3_image_processor import Sam3Processor


image_path = r"./sample/images/driving_camera.png"

# Load the model
model = build_sam3_image_model()
processor = Sam3Processor(model)

# Load an image
image = Image.open(image_path)

if image.mode == 'RGBA':
    image = image.convert('RGB')

inference_state = processor.set_image(image)

# Prompt the model with text
prompt = "traffice sign"
output = processor.set_text_prompt(state=inference_state, prompt=prompt)

# Get the masks, bounding boxes, and scores
masks, boxes, scores = output["masks"], output["boxes"], output["scores"]


## セグメンテーションとバウンディングボックス、scoreを画像に描画して保存

num_results = len(masks)

# 元画像をnumpy配列に変換
img_array = np.array(image)
result_image = Image.fromarray(img_array)
draw = ImageDraw.Draw(result_image, 'RGBA')

# フォント設定(デフォルトフォントを使用)
try:
    font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
except:
    font = ImageFont.load_default()

# カラーマップ(複数の結果用)
colors = [
    (255, 0, 0, 100),      # 赤
    (0, 255, 0, 100),      # 緑
    (0, 0, 255, 100),      # 青
    (255, 255, 0, 100),    # 黄
    (255, 0, 255, 100),    # マゼンタ
    (0, 255, 255, 100),    # シアン
]

# 各検出結果を描画
for i in range(num_results):
    color = colors[i % len(colors)]
    box_color = (color[0], color[1], color[2], 255)  # 不透明な色
    
    # マスクを画像に重ねる
    mask = masks[i]
    if isinstance(mask, torch.Tensor):
        mask = mask.cpu().numpy()
    
    # マスクが3次元の場合は2次元に変換
    if len(mask.shape) == 3:
        mask = mask.squeeze()
    
    # マスクをブール値に変換
    mask_bool = mask > 0.5
    
    # マスク領域に半透明な色を重ねる
    overlay = Image.new('RGBA', result_image.size, (0, 0, 0, 0))
    overlay_draw = ImageDraw.Draw(overlay)
    
    # マスクの各ピクセルに色を付ける
    mask_resized = Image.fromarray((mask_bool * 255).astype(np.uint8)).resize(result_image.size, Image.NEAREST)
    mask_array = np.array(mask_resized)
    
    for y in range(mask_array.shape[0]):
        for x in range(mask_array.shape[1]):
            if mask_array[y, x] > 0:
                overlay_draw.point((x, y), fill=color)
    
    result_image = Image.alpha_composite(result_image.convert('RGBA'), overlay).convert('RGB')
    draw = ImageDraw.Draw(result_image)
    
    # バウンディングボックスを描画
    box = boxes[i]
    if isinstance(box, torch.Tensor):
        box = box.cpu().numpy()
    
    x1, y1, x2, y2 = box
    draw.rectangle([x1, y1, x2, y2], outline=box_color, width=3)
    
    # スコアを描画
    score = scores[i]
    if isinstance(score, torch.Tensor):
        score = score.cpu().item()
    
    text = f"Score: {score:.2f}"
    
    # テキストの背景を描画
    text_bbox = draw.textbbox((x1, y1 - 25), text, font=font)
    draw.rectangle(text_bbox, fill=box_color)
    draw.text((x1, y1 - 25), text, fill=(255, 255, 255), font=font)

# 結果を保存
output_path = "./sample/images/result_with_annotations.png"
result_image.save(output_path)
print(f"結果を保存しました: {output_path}")
print(f"検出数: {num_results}")

検出例

対象画像

テキストプロンプト : traffic sign

まずは交通標識(traffic sign)というプロンプトで認識されるかテスト
一つ向こうの交差点の標識はさすがに小さくてにんしきしてませんが、規制標識は認識してくれてますね。

テキストプロンプト : traffic light

次、信号機(traffic light) 信号機したの方向指示まで認識してくれてますね。

result_with_annotations

テキストプロンプト : license plate

次は、車のナンバープレート(license plate)
なんか、もう余裕ですね。

テキストプロンプト : blue car

正面の青い車だけ検出できるかやってみましょう。(blue car)
Socre 0.96 という高い確信度で認識できてますね。

テキストプロンプト : taillight

こんどは、車の部品を指定したらどうかな。テールライト(taillight)

青い車の左の軽のミニバンのテールライトは取得できていないですが、ほかの車のテールライトは取得できてますね。結構スコアも高い。

テキストプロンプト : tire

タイヤはどうかなっと(tire)
オクルージョンで一部しか見えてないタイヤもセグメンテーションで来てますね。
すごいすごい。

テキストプロンプト : pedestrian bridge

歩道橋は検出できるかテスト(pedestrian bridge)

おー!、ちゃんとセグメンテーションンされている!
歩行者や信号機も避けてセグメンテーションされているので、これは人力でセグメンテーションするより質がいいんじゃないかな。

所感

ちょこっと試しただけでしたが、SAM3凄いぞ。
yolo-worldやgrounding Dino で教師データを作ったりしているんですが、これからはSAM3一択って感じになりそうです。
アノテーション作業から僕を救ってくれそうです。

Discussion