YOLOE オープンボキャブラリ物体検出・セグメンテーション(ソースコードと実行結果)

Python開発環境,ライブラリ類
ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.htmlで詳しく解説しているので、必要に応じて参照してください。
Python 3.12 のインストール
インストール済みの場合は実行不要。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。
REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul
【関連する外部ページ】
Python の公式ページ: https://www.python.org/
AI エディタ Windsurf のインストール
Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。
winget install --scope machine Codeium.Windsurf -e --silent
【関連する外部ページ】
Windsurf の公式ページ: https://windsurf.com/
Gitのインストール
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。
REM Git をシステム領域にインストール
winget install --scope machine --id Git.Git -e --silent
REM Git のパス設定
set "GIT_PATH=C:\Program Files\Git\cmd"
if exist "%GIT_PATH%" (
echo "%PATH%" | find /i "%GIT_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%GIT_PATH%" /M >nul
)
コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install transformers pillow accelerate opencv-python
YOLOE オープンボキャブラリ物体検出・セグメンテーションプログラム
このプログラムが示すAI能力
このプログラムは、動画やカメラからの視覚入力に対してオープンボキャブラリ物体検出・セグメンテーションを実行する視覚認識能力を持つ。従来の固定されたクラス分類とは異なり、テキストプロンプトによって任意の物体クラスを検出・分割できる柔軟な視覚理解機能を実現している[1]。
主要技術
- YOLOE
オープンボキャブラリ物体検出・セグメンテーションモデルである。RepRTA、SAVPE、LRPCの3つの技術により、テキストプロンプト、視覚プロンプト、プロンプトフリーの多様な入力方式に対応する[1][2]。
- Re-parameterizable Region-Text Alignment(RepRTA)
テキストプロンプトに対応する技術である。事前学習済みテキスト埋め込みを補助ネットワークで改良し、推論時に視覚・テキスト間の整合性を向上させる[1][3]。
- Semantic-Activated Visual Prompt Encoder(SAVPE)
視覚プロンプトを処理する技術である。セマンティック分岐と活性化分岐を分離することで、視覚埋め込みと精度を向上させる[1][3]。
参考文献
- [1] Wang, A., Liu, L., Chen, H., Lin, Z., Han, J., & Ding, G. (2025). YOLOE: Real-Time Seeing Anything. arXiv preprint arXiv:2503.07465.
- [2] THU-MIG. (2025). YOLOE: Real-Time Seeing Anything [ICCV 2025]. GitHub repository. https://github.com/THU-MIG/yoloe
- [3] Ultralytics. (2025). YOLOE: Real-Time Seeing Anything - Ultralytics YOLO Documentation. https://docs.ultralytics.com/models/yoloe/
# YOLOE オープンボキャブラリ物体検出・セグメンテーションプログラム
# 特徴技術名: YOLOE (Real-Time Seeing Anything)
# 出典: Wang, A., Liu, L., Chen, H., et al. (2025). YOLOE: Real-Time Seeing Anything. arXiv preprint arXiv:2503.07465.
# 特徴機能: RepRTA(Re-parameterizable Region-Text Alignment)+ SAVPE(Semantic-Activated Visual Prompt Encoder)+ LRPC(Lazy Region-Prompt Contrast)による多様なプロンプト対応。テキスト、視覚、プロンプトフリーによる任意物体検出・セグメンテーション機能
# 学習済みモデル: yoloe-11s-seg.pt (小型セグメンテーション), yoloe-11m-seg.pt (中型), yoloe-11l-seg.pt (大型) - Objects365 + LVIS データセット対応、Ultralyticsから自動ダウンロード
# 方式設計:
# 関連利用技術:
# - RepRTA (Re-parameterizable Region-Text Alignment): テキストプロンプト処理、軽量補助ネットワークによる視覚-テキスト整合
# - SAVPE (Semantic-Activated Visual Prompt Encoder): 視覚プロンプト処理、セマンティック・活性化分岐の分離設計
# - LRPC (Lazy Region-Prompt Contrast): プロンプトフリー処理、内蔵大語彙による物体認識
# - YOLO11: ベースとなる物体検出+セグメンテーションアーキテクチャ、リアルタイム推論を実現
# - OpenCV: カメラ入力とリアルタイム画像処理、マスク可視化
# - PIL (Python Imaging Library): 日本語フォント描画と画像処理
# 入力と出力:
# 入力: 動画(ユーザは「0:動画ファイル,1:カメラ,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://github.com/opencv/opencv/blob/master/samples/data/vtest.aviを使用)
# 出力: リアルタイム検出結果+セグメンテーションマスク表示付き動画表示
# 処理手順:
# 1. YOLOEモデルロード
# 2. カスタムクラス設定(set_classes + get_text_pe)
# 3. フレーム取得と推論実行
# 4. 検出結果+セグメンテーションマスクの描画と表示
# 前処理: フレームバッファクリア(最新フレーム取得)、テキスト埋め込みの事前エンコード、色分けパレット生成
# 後処理: 検出結果+マスクの可視化、信頼度情報表示、日本語フォント対応、透明度調整済みマスク合成
# 追加処理: RepRTAによる視覚-テキスト整合最適化、SAVPEによる視覚プロンプト高精度化、LRPCによる大語彙対応
# 調整を必要とする設定値: CONF_THRESHOLD (0.3) - 検出信頼度閾値、MASK_ALPHA (0.5) - マスク透明度、高くすると誤検出減少・低くすると検出感度向上
# 将来方策: 信頼度閾値の自動調整機能(フレーム内検出数に基づく動的調整アルゴリズム実装)、マスク品質向上機能
# その他の重要事項: Windows環境対応、DirectShowバックエンド使用、GPU推論対応、YOLO-Worldv2比+3.5AP向上・1.4倍高速化、セグメンテーション精度向上
# 前準備: pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
# pip install ultralytics opencv-python pillow
import cv2
import numpy as np
import torch
from ultralytics import YOLOE
from PIL import Image, ImageDraw, ImageFont
import tkinter as tk
from tkinter import filedialog
import urllib.request
import os
import colorsys
def generate_colors(num_classes):
"""クラス数に応じた色分けパレットを生成"""
colors = []
for i in range(num_classes):
hue = (i * 137.508) % 360 / 360 # 黄金角による均等分散
saturation = 0.9
value = 0.85
rgb = colorsys.hsv_to_rgb(hue, saturation, value)
colors.append(tuple(int(c * 255) for c in rgb))
return colors
def draw_masks(image, masks, boxes, class_ids, confidences, class_names, colors, alpha=0.5):
"""セグメンテーションマスクを色分けして描画"""
if masks is None or len(masks) == 0:
return image
overlay = image.copy()
for i, mask in enumerate(masks):
if i >= len(class_ids) or i >= len(colors):
continue
# マスクデータの処理
if hasattr(mask, 'data'):
mask_data = mask.data.cpu().numpy()
else:
mask_data = mask
# マスクが3次元の場合、2次元に変換
if len(mask_data.shape) == 3:
mask_data = mask_data[0]
# マスクサイズを画像サイズに合わせる
if mask_data.shape[:2] != image.shape[:2]:
mask_data = cv2.resize(mask_data, (image.shape[1], image.shape[0]), interpolation=cv2.INTER_NEAREST)
# バイナリマスクに変換(効率化)
mask_binary = mask_data > 0.5
# クラスIDに対応する色を取得
class_id = int(class_ids[i])
color = colors[class_id % len(colors)]
# マスク領域を色で塗りつぶし(効率化)
overlay[mask_binary] = color
# 透明度を適用してマスクを合成
return cv2.addWeighted(image, 1 - alpha, overlay, alpha, 0)
def draw_detection_info(image, boxes, class_ids, confidences, class_names, colors):
"""検出結果のbounding boxとラベル情報を描画"""
if boxes is not None and len(boxes) > 0:
for i, box in enumerate(boxes):
if i < len(class_ids) and i < len(confidences):
# Bounding box座標の取得
if hasattr(box, 'xyxy'):
x1, y1, x2, y2 = map(int, box.xyxy[0].cpu().numpy())
else:
x1, y1, x2, y2 = map(int, box)
# クラス情報の取得
class_id = int(class_ids[i])
confidence = float(confidences[i])
class_name = class_names.get(class_id, f'Class {class_id}') if class_names else f'Class {class_id}'
# 色の取得
color = colors[class_id % len(colors)]
# Bounding boxの描画
cv2.rectangle(image, (x1, y1), (x2, y2), color, 2)
# ラベルテキストの準備
label = f'{class_name}: {confidence:.2f}'
# ラベル背景の描画
(text_width, text_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
cv2.rectangle(image, (x1, y1 - text_height - 10), (x1 + text_width, y1), color, -1)
# ラベルテキストの描画
cv2.putText(image, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
return image
def process_frame(frame, model, classes, count, colors):
# YOLOEによる推論実行(最適化設定)
results = model(frame, conf=CONF_THRESHOLD, imgsz=640, max_det=300, augment=False)
# 元の画像をコピー
annotated = frame.copy()
# 検出結果の処理
for result in results:
masks = None
boxes = None
class_ids = []
confidences = []
class_names = result.names if hasattr(result, 'names') else {}
# マスク情報の取得
if hasattr(result, 'masks') and result.masks is not None:
masks = result.masks
# Bounding box情報の取得
if hasattr(result, 'boxes') and result.boxes is not None:
boxes = result.boxes
for box in boxes:
if hasattr(box, 'cls') and hasattr(box, 'conf'):
class_ids.append(int(box.cls))
confidences.append(float(box.conf))
# セグメンテーションマスクの描画
if masks is not None:
annotated = draw_masks(annotated, masks, boxes, class_ids, confidences,
class_names, colors, alpha=MASK_ALPHA)
# 検出結果(bounding box + ラベル)の描画
if boxes is not None:
annotated = draw_detection_info(annotated, boxes, class_ids, confidences,
class_names, colors)
# 検出統計情報の表示
num_detections = len(class_ids)
if num_detections > 0:
detection_text = f'検出物体数: {num_detections}'
# 日本語フォント表示
try:
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
img_pil = Image.fromarray(cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB))
ImageDraw.Draw(img_pil).text((10, 110), detection_text, font=font, fill=(0, 255, 255))
annotated = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
except:
cv2.putText(annotated, detection_text, (10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2)
# 各オブジェクトの詳細情報表示
y_pos = 135
for i in range(min(num_detections, 10)): # 最大10個まで表示
if i < len(class_ids) and i < len(confidences):
class_id = class_ids[i]
conf = confidences[i]
name = class_names.get(class_id, f'Class {class_id}') if class_names else f'Class {class_id}'
conf_text = f'{i+1}. {name}: {conf:.2f}'
cv2.putText(annotated, conf_text, (10, y_pos + i * 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, FONT_COLOR_DETECTION, 1)
# 情報テキストの描画
info = f'Frame: {count} | YOLOE Detection+Segmentation (Classes: {len(classes)})'
cv2.putText(annotated, info, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, FONT_COLOR_INFO, 2)
# モード情報の表示
mode = f'Mode: Open Vocabulary Detection + Segmentation'
cv2.putText(annotated, mode, (10, 55), cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, FONT_COLOR_PROMPT, 2)
# マスク透明度情報の表示
alpha_info = f'Mask Alpha: {MASK_ALPHA:.1f}'
cv2.putText(annotated, alpha_info, (10, 80), cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, FONT_COLOR_MASK, 2)
return annotated
# 定数定義
MODEL_NAME = 'yoloe-11s-seg.pt'
CONF_THRESHOLD = 0.3
MASK_ALPHA = 0.5 # マスクの透明度 (0.0-1.0)
FONT_SCALE = 0.6
FONT_COLOR_INFO = (0, 255, 0)
FONT_COLOR_PROMPT = (255, 0, 255)
FONT_COLOR_DETECTION = (255, 255, 0)
FONT_COLOR_MASK = (0, 255, 255)
RANDOM_SEED = 42
FONT_PATH = 'C:/Windows/Fonts/msgothic.ttc'
FONT_SIZE = 20
SAMPLE_VIDEO_URL = 'https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi?raw=true'
# GPU/CPU自動検出
DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
# カスタムクラス定義(オープンボキャブラリの例)
CLASSES = [
'person wearing red shirt', 'person wearing blue shirt', 'white car', 'black car',
'small dog', 'large dog', 'orange cat', 'black cat', 'flying bird', 'perched bird',
'open laptop', 'closed laptop', 'smartphone', 'tablet', 'thick book', 'thin book',
'coffee cup', 'tea cup', 'water bottle', 'plastic bottle', 'wooden chair', 'metal chair',
'dining table', 'computer desk', 'flat screen tv', 'old tv', 'wireless keyboard', 'gaming mouse',
'red apple', 'green apple', 'fresh orange', 'ripe banana', 'hot pizza', 'birthday cake',
'colorful flower', 'white flower', 'green tree', 'dry tree', 'school backpack', 'hiking backpack'
]
# 乱数シード設定
np.random.seed(RANDOM_SEED)
print('YOLOE オープンボキャブラリ物体検出+セグメンテーションプログラムを開始します')
print('YOLOE: Real-Time Seeing Anything with Segmentation')
print('RepRTA + SAVPE + LRPC アーキテクチャ実装')
print('多様なプロンプト対応による物体検出+セグメンテーション機能')
print('マスクの色分け表示機能搭載')
print('終了するには \'q\' キーを押してください')
print('クラス一覧表示は \'r\' キーを押してください')
# YOLOEモデルロード
print(f'YOLOEセグメンテーションモデル \'{MODEL_NAME}\' をロードしています...')
model = YOLOE(MODEL_NAME)
# GPU/CPU設定と自動フォールバック
print(f'デバイス設定: {DEVICE}')
try:
if DEVICE == 'cuda':
print(f'GPU検出: {torch.cuda.get_device_name()}')
model = model.to('cuda')
else:
print('GPU未検出: CPUを使用します')
model = model.to('cpu')
except Exception as e:
print(f'GPU初期化失敗、CPUにフォールバック: {e}')
DEVICE = 'cpu'
model = model.to('cpu')
# 重要: オープンボキャブラリ機能を有効にするためのクラス設定
print('カスタムクラスを設定中...')
model.set_classes(CLASSES, model.get_text_pe(CLASSES))
print(f'設定されたクラス数: {len(CLASSES)}')
print('設定されたクラス(最初の10個):', CLASSES[:10])
# 色分けパレットの生成
print('マスク色分けパレットを生成中...')
colors = generate_colors(len(CLASSES))
print(f'生成された色数: {len(colors)}')
print('オープンボキャブラリ物体検出+セグメンテーション機能を初期化中...')
print('0: 動画ファイル')
print('1: カメラ')
print('2: サンプル動画')
choice = input('選択: ')
temp_file = None
if choice == '0':
root = tk.Tk()
root.withdraw()
path = filedialog.askopenfilename()
if not path:
exit()
cap = cv2.VideoCapture(path)
elif choice == '1':
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
elif choice == '2':
# サンプル動画ダウンロード・処理
url = SAMPLE_VIDEO_URL
filename = 'vtest.avi'
try:
urllib.request.urlretrieve(url, filename)
temp_file = filename
cap = cv2.VideoCapture(filename)
except Exception as e:
print(f'動画のダウンロードに失敗しました: {url}')
print(f'エラー: {e}')
exit()
else:
print('無効な選択です')
exit()
if not cap.isOpened():
print('動画の読み込みに失敗しました')
exit()
print(f'検出対象クラス: {len(CLASSES)}種類のカスタムクラス')
print(f'マスク透明度: {MASK_ALPHA}')
print(f'信頼度閾値: {CONF_THRESHOLD}')
count = 0
# メイン処理
try:
while True:
cap.grab()
ret, frame = cap.retrieve()
if not ret:
break
count += 1
frame = process_frame(frame, model, CLASSES, count, colors)
cv2.imshow('YOLOE Open Vocabulary Detection + Segmentation', frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('r'):
print('\n=== 現在設定されているカスタムクラス ===')
for i, name in enumerate(CLASSES, 1):
color = colors[(i-1) % len(colors)]
print(f'{i:2d}. {name} (色: RGB{color})')
print('========================================\n')
finally:
cap.release()
cv2.destroyAllWindows()
if temp_file:
try:
os.remove(temp_file)
except OSError:
pass
print('プログラムを終了しました')
print('YOLOEのオープンボキャブラリ機能により、カスタム定義したクラスの検出+セグメンテーションが可能になりました')
print('各クラスは異なる色のマスクで表示され、透明度調整により元画像との合成表示を実現しました')