YOLO11によるインスタンスセグメンテーション(ソースコードと説明と利用ガイド)
【概要】YOLO11-segを使用してリアルタイムインスタンスセグメンテーションを実行。Enhanced Feature Extractionにより物体検出と同時にピクセルレベルのセグメンテーションを学習し、5種類のモデルサイズによる精度と速度の比較実験が可能。Windows環境での実行手順、プログラムコード、実験アイデアを含む。
プログラム利用ガイド
1. このプログラムの利用シーン
動画ファイルやウェブカメラの映像から、人や車などの物体をリアルタイムで検出し、その位置と種類を特定するためのソフトウェアである。監視映像の分析、交通量調査、動物の個体数カウントなどに利用できる。
2. 主な機能
- 物体検出とインスタンスセグメンテーション:映像内の物体を検出し、その輪郭を抽出する。
- リアルタイムプレビュー:検出結果を元の映像に重ねて表示する。
- 80クラス対応:人、車、動物、日用品など80種類の物体を認識する。
- 日本語表示:検出された物体の名称を日本語で表示する。
- 検出結果の保存:各フレームの検出情報(物体の種類、位置、信頼度)をテキストファイルに記録する。
3. 基本的な使い方
- 起動とモデル選択:
プログラムを起動し、キーボードでモデルサイズを選択する(n/s/m/l/x)。軽量版から高精度版まで選択できる。
- 入力ソースの選択:
キーボードで 0(動画ファイル)、1(ウェブカメラ)、2(サンプル動画)のいずれかを入力する。0を選択した場合はファイル選択ダイアログが表示される。
- 検出結果の確認:
映像が表示され、検出された物体に色付きの枠と名称が表示される。画面左上には検出物体数とその内訳が表示される。
- 終了方法:
映像表示ウィンドウを選択した状態で、キーボードの q キーを押す。
4. 便利な機能
- 統計情報の表示:カメラモードでは10秒ごとに処理速度やフレーム数が表示される。
- 詳細ログ出力:各フレームの検出情報がコンソールに表示される。動画モードではフレーム番号、カメラモードではタイムスタンプが付与される。
- 結果ファイルの自動保存:プログラム終了時に、全フレームの検出結果がresult.txtに保存される。検出されたクラスの一覧と出現回数も記録される。
- 低照度対応:CLAHE処理により、暗い映像でも物体検出精度が向上する。
使用する学習済みモデル
YOLO11-seg事前学習済みモデル:
- 学習データセット: MS COCO 2017(80クラス物体検出+セグメンテーション)
- 検出可能物体: 人、車両、動物、家具、電子機器など80種類
- 出力形式: バウンディングボックス + ピクセルレベルセグメンテーションマスク
- 入力解像度: 640×640ピクセル(デフォルト)
- モデルサイズ: Nano版(軽量)からExtra Large版(高精度)まで5種類
- 技術特徴: C3k2ブロック、C2PSA空間アテンション、SPPF多スケール処理
事前準備
Python, Windsurfをインストールしていない場合の手順(インストール済みの場合は実行不要)。
- 管理者権限でコマンドプロンプトを起動する(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)。
- 以下のコマンドをそれぞれ実行する(winget コマンドは1つずつ実行)。
REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Windsurf をシステム領域にインストール
winget install --scope machine --id Codeium.Windsurf -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
REM Windsurf のパス設定
set "WINDSURF_PATH=C:\Program Files\Windsurf"
if exist "%WINDSURF_PATH%" (
echo "%PATH%" | find /i "%WINDSURF_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%WINDSURF_PATH%" /M >nul
)
必要なパッケージのインストール
管理者権限でコマンドプロンプトを起動し、以下のコマンドを実行する:
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install ultralytics opencv-python numpy pillow
YOLO11物体検出・インスタンスセグメンテーションプログラム
概要
このプログラムは、YOLO11モデルを使用して動画ファイルまたはカメラ映像から物体を検出し、インスタンスセグメンテーションを実行する。COCOデータセット80クラスに対応し、検出結果を画面表示およびテキストファイルに保存する。
主要技術
YOLO11 (You Only Look Once version 11)
Ultralyticsが2024年に開発した物体検出・セグメンテーションモデル[1][2]。C3k2ブロック(カーネルサイズ2のCSPボトルネック構造)による特徴抽出を行う。
CLAHE (Contrast Limited Adaptive Histogram Equalization)
適応的ヒストグラム均等化の一種であり、画像を小領域に分割して局所的にコントラスト強化を行う技術[3][4]。ノイズの過剰増幅を制限する機構を備える。
技術的特徴
- YUV色空間でのCLAHE適用
RGB画像をYUV色空間に変換し、輝度チャンネル(Y)のみにCLAHEを適用する。色相と彩度を保持しながらコントラストを強化する。
- スレッド化されたビデオキャプチャ
バックグラウンドスレッドで常に最新フレームを取得し、メインスレッドでの処理遅延を回避する。カメラモードではDirectShowバックエンドとMJPEGコーデックを使用し、FPS設定とバッファサイズ調整により遅延を最小化する。
- GPU/CPU自動選択
PyTorchのデバイス検出機能により、CUDA対応GPUが利用可能な場合は自動的に選択する。GPU使用時はcuDNNベンチマークモードを有効化する。
- 構造化されたテキスト描画
日本語表示が必要な場合、PILライブラリを使用してテキスト情報を辞書のリストとして受け取り、一括描画する。フォント読み込みに失敗した場合はOpenCVによる描画を使用する。
実装の特色
- モデルサイズ選択
Nano(5.9MB)、Small(19.7MB)、Medium(43.3MB)、Large(53.5MB)、Extra Large(119MB)の5つのモデルから選択できる。
- 詳細な検出結果出力
各検出物体について、クラス名、信頼度スコア、バウンディングボックス座標を出力する。カメラモードではタイムスタンプ、動画ファイルモードではフレーム番号を付与する。
- 日本語クラス名表示
COCOデータセット80クラスの日本語名称をマッピングし、画面表示およびファイル出力に使用する。
- 統計情報の定期表示
カメラモードでは10秒間隔で経過時間、処理フレーム数、実測FPS、平均処理時間を表示する。
参考文献
[1] Jocher, G., & Qiu, J. (2024). Ultralytics YOLO11. GitHub repository. https://github.com/ultralytics/ultralytics
[2] Ultralytics. (2024). YOLO11 Documentation. https://docs.ultralytics.com/models/yolo11/
[3] Pizer, S. M., Amburn, E. P., Austin, J. D., Cromartie, R., Geselowitz, A., Greer, T., ... & Zuiderveld, K. (1987). Adaptive histogram equalization and its variations. Computer Vision, Graphics, and Image Processing, 39(3), 355-368.
[4] Zuiderveld, K. (1994). Contrast Limited Adaptive Histogram Equalization. Graphics Gems IV, 474-485.
ソースコード
"""
プログラム名: YOLO11物体検出・インスタンスセグメンテーションプログラム
特徴技術名: YOLO11 (You Only Look Once version 11)
出典: G. Jocher and J. Qiu, "Ultralytics YOLO11," GitHub repository, 2024. [Online]. Available: https://github.com/ultralytics/ultralytics
特徴機能: C3k2ブロックによる特徴抽出(カーネルサイズ2のCSPボトルネック構造により、計算効率と検出精度を両立)
学習済みモデル: yolo11n-seg.pt/yolo11s-seg.pt/yolo11m-seg.pt/yolo11l-seg.pt/yolo11x-seg.pt(COCOデータセット80クラス対応インスタンスセグメンテーションモデル、自動ダウンロード)
特徴技術および学習済モデルの利用制限: AGPL-3.0ライセンスに準拠(Ultralytics)。学術研究および商用利用が可能だが、商用利用時はEnterprise Licenseの取得を推奨。必ず利用者自身でUltralyticsのライセンス情報を確認すること。
方式設計:
関連利用技術:
- OpenCV: コンピュータビジョンライブラリ、画像・動画処理、カメラ制御
- NumPy: 数値計算ライブラリ、配列処理、データ操作
- Tkinter: GUIライブラリ、ファイル選択ダイアログ
- PIL/Pillow: 画像処理ライブラリ、日本語テキスト描画
- PyTorch: ディープラーニングフレームワーク、GPU/CPU自動選択
- Ultralytics YOLO11: 物体検出・セグメンテーションフレームワーク
入力と出力: 入力: 動画(ユーザは「0:動画ファイル,1:カメラg.,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://github.com/opencv/opencv/blob/master/samples/data/vtest.aviを使用)、出力: OpenCV画面でリアルタイム表示、各フレームごとにprint()で処理結果を表示、プログラム終了時にresult.txtファイルに保存
処理手順: 1.動画フレーム取得→2.CLAHE適用→3.YOLO11モデルによる推論実行→4.検出結果とセグメンテーションマスクの描画→5.リアルタイム表示
前処理、後処理: 前処理:CLAHE適用(YUV色空間で輝度チャンネルのみ処理)、フレームバッファクリア(最新フレーム取得)、画像正規化(YOLO11内部処理)、後処理:検出結果可視化、信頼度フィルタリング、セグメンテーションマスク合成
追加処理: DirectShowバックエンド使用によるカメラ安定化、バッファサイズ=1設定による遅延最小化、乱数シード設定による結果再現性確保
調整を必要とする設定値: CONF_THRESHOLD(信頼度閾値、0.25、YOLO11公式推奨のデフォルト値、検出感度と精度のバランス調整)
将来方策: CONF_THRESHOLDの自動最適化機能実装(フレーム毎の検出数と信頼度分布を統計的に分析し、適合率と再現率のF値が最大となる閾値を動的に算出。実装方法:過去30フレームの検出結果を保持し、信頼度ヒストグラムから最適閾値を計算)
その他の重要事項: Windows環境対応、AGPL-3.0ライセンス、リアルタイム処理特化、COCOクラス検出可能
前準備:
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install ultralytics opencv-python numpy pillow
"""
import cv2
import tkinter as tk
from tkinter import filedialog
import os
import urllib.request
from ultralytics import YOLO
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from collections import defaultdict
import torch
from datetime import datetime
import time
import sys
import io
import threading
import warnings
warnings.filterwarnings('ignore')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', line_buffering=True)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f'デバイス: {str(device)}')
if device.type == 'cuda':
torch.backends.cudnn.benchmark = True
MODEL_INFO = {
'n': {
'name': 'yolo11n-seg.pt',
'size': '5.9 MB',
'desc': 'Nano (軽量・高速)'
},
's': {
'name': 'yolo11s-seg.pt',
'size': '19.7 MB',
'desc': 'Small (バランス型)'
},
'm': {
'name': 'yolo11m-seg.pt',
'size': '43.3 MB',
'desc': 'Medium (汎用)'
},
'l': {
'name': 'yolo11l-seg.pt',
'size': '53.5 MB',
'desc': 'Large (高精度)'
},
'x': {
'name': 'yolo11x-seg.pt',
'size': '119 MB',
'desc': 'Extra Large (最高精度)'
}
}
CONF_THRESHOLD = 0.25
RANDOM_SEED = 42
CLAHE_CLIP_LIMIT = 2.0
CLAHE_TILE_SIZE = (8, 8)
WINDOW_NAME = 'YOLO11物体検出・インスタンスセグメンテーション'
COLOR_GREEN = (0, 255, 0)
COLOR_YELLOW = (0, 255, 255)
COLOR_GREEN_RGB = (0, 255, 0)
COLOR_YELLOW_RGB = (255, 255, 0)
clahe = cv2.createCLAHE(clipLimit=CLAHE_CLIP_LIMIT, tileGridSize=CLAHE_TILE_SIZE)
def bgr_to_rgb(color_bgr):
return (color_bgr[2], color_bgr[1], color_bgr[0])
def generate_class_colors(num_classes):
colors = []
for i in range(num_classes):
hue = int(180.0 * i / num_classes)
hsv = np.uint8([[[hue, 255, 255]]])
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)[0][0]
colors.append((int(bgr[0]), int(bgr[1]), int(bgr[2])))
return colors
CLASS_NAMES_JP = {
'person': '人', 'bicycle': '自転車', 'car': '車', 'motorcycle': 'バイク',
'airplane': '飛行機', 'bus': 'バス', 'train': '電車', 'truck': 'トラック',
'boat': 'ボート', 'traffic light': '信号機', 'fire hydrant': '消火栓',
'stop sign': '停止標識', 'parking meter': 'パーキングメーター', 'bench': 'ベンチ',
'bird': '鳥', 'cat': '猫', 'dog': '犬', 'horse': '馬', 'sheep': '羊',
'cow': '牛', 'elephant': '象', 'bear': '熊', 'zebra': 'シマウマ', 'giraffe': 'キリン',
'backpack': 'リュック', 'umbrella': '傘', 'handbag': 'ハンドバッグ', 'tie': 'ネクタイ',
'suitcase': 'スーツケース', 'frisbee': 'フリスビー', 'skis': 'スキー板',
'snowboard': 'スノーボード', 'sports ball': 'ボール', 'kite': '凧',
'baseball bat': 'バット', 'baseball glove': 'グローブ', 'skateboard': 'スケートボード',
'surfboard': 'サーフボード', 'tennis racket': 'テニスラケット', 'bottle': 'ボトル',
'wine glass': 'ワイングラス', 'cup': 'カップ', 'fork': 'フォーク', 'knife': 'ナイフ',
'spoon': 'スプーン', 'bowl': 'ボウル', 'banana': 'バナナ', 'apple': 'リンゴ',
'sandwich': 'サンドイッチ', 'orange': 'オレンジ', 'broccoli': 'ブロッコリー',
'carrot': 'ニンジン', 'hot dog': 'ホットドッグ', 'pizza': 'ピザ', 'donut': 'ドーナツ',
'cake': 'ケーキ', 'chair': '椅子', 'couch': 'ソファ', 'potted plant': '鉢植え',
'bed': 'ベッド', 'dining table': 'テーブル', 'toilet': 'トイレ', 'tv': 'テレビ',
'laptop': 'ノートPC', 'mouse': 'マウス', 'remote': 'リモコン', 'keyboard': 'キーボード',
'cell phone': '携帯電話', 'microwave': '電子レンジ', 'oven': 'オーブン',
'toaster': 'トースター', 'sink': 'シンク', 'refrigerator': '冷蔵庫',
'book': '本', 'clock': '時計', 'vase': '花瓶', 'scissors': 'ハサミ',
'teddy bear': 'ぬいぐるみ', 'hair drier': 'ドライヤー', 'toothbrush': '歯ブラシ'
}
FONT_PATH = 'C:/Windows/Fonts/meiryo.ttc'
FONT_SIZE = 24
try:
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
except IOError:
font = None
frame_count = 0
results_log = []
class_counts = {}
model = None
class ThreadedVideoCapture:
def __init__(self, src, is_camera=False):
if is_camera:
self.cap = cv2.VideoCapture(src, cv2.CAP_DSHOW)
fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
self.cap.set(cv2.CAP_PROP_FOURCC, fourcc)
self.cap.set(cv2.CAP_PROP_FPS, 60)
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
else:
self.cap = cv2.VideoCapture(src)
self.grabbed, self.frame = self.cap.read()
self.stopped = False
self.lock = threading.Lock()
self.thread = threading.Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
while not self.stopped:
grabbed, frame = self.cap.read()
with self.lock:
self.grabbed = grabbed
if grabbed:
self.frame = frame
def read(self):
with self.lock:
return self.grabbed, self.frame.copy() if self.grabbed else None
def isOpened(self):
return self.cap.isOpened()
def get(self, prop):
return self.cap.get(prop)
def release(self):
self.stopped = True
self.thread.join()
self.cap.release()
def display_program_header():
print('=' * 60)
print('=== YOLO11物体検出・インスタンスセグメンテーションプログラム ===')
print('=' * 60)
print('概要: CLAHEを適用し、リアルタイムでオブジェクトを検出します')
print('機能: YOLO11による物体検出・セグメンテーション(COCOデータセット対応)')
print('技術: CLAHE + YOLO11')
print('操作: qキーで終了')
print('出力: 各フレームごとに処理結果を表示し、終了時にresult.txtへ保存')
print()
def draw_texts_with_pillow(bgr_frame, texts):
img_pil = Image.fromarray(cv2.cvtColor(bgr_frame, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
for item in texts:
text = item['text']
x, y = item['org']
color = item['color']
draw.text((x, y), text, font=font, fill=color)
return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
def draw_detection_results(frame, detection_info):
texts_to_draw = []
texts_to_draw.append({
'text': f'Frame: {frame_count} | Device: {str(device).upper()}',
'org': (10, 30),
'color': COLOR_GREEN_RGB,
'font_type': 'main'
})
if detection_info['total'] > 0:
texts_to_draw.append({
'text': f'検出物体数: {detection_info["total"]}',
'org': (10, 60),
'color': COLOR_YELLOW_RGB,
'font_type': 'main'
})
y_offset = 90
for class_name, count in detection_info['objects'].items():
jp_name = CLASS_NAMES_JP.get(class_name, class_name)
texts_to_draw.append({
'text': f'{jp_name}: {count}個',
'org': (10, y_offset),
'color': COLOR_YELLOW_RGB,
'font_type': 'main'
})
y_offset += 30
if font:
frame = draw_texts_with_pillow(frame, texts_to_draw)
else:
cv2.putText(frame, f'Frame: {frame_count} | Device: {str(device).upper()}',
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLOR_GREEN, 2)
if detection_info['total'] > 0:
cv2.putText(frame, f'Detections: {detection_info["total"]}',
(10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLOR_YELLOW, 2)
y_offset = 90
for class_name, count in detection_info['objects'].items():
info_text = f'{class_name}: {count}'
cv2.putText(frame, info_text, (10, y_offset), cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLOR_YELLOW, 2)
y_offset += 30
return frame
def format_detection_output(detection_info, detections):
if len(detections) == 0:
return 'count=0'
else:
parts = []
for det in detections:
x1, y1, x2, y2 = det['x1'], det['y1'], det['x2'], det['y2']
class_name = det['name']
conf = det['conf']
parts.append(f'class={class_name},conf={conf:.3f},box=[{x1},{y1},{x2},{y2}]')
return f'count={len(detections)}; ' + ' | '.join(parts)
def detect_objects(frame):
global model
yuv_img = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV)
yuv_img[:,:,0] = clahe.apply(yuv_img[:,:,0])
clahe_frame = cv2.cvtColor(yuv_img, cv2.COLOR_YUV2BGR)
results = model(clahe_frame, conf=CONF_THRESHOLD, verbose=False)
return results[0]
def process_video_frame(frame, timestamp_ms, is_camera):
final_results = detect_objects(frame)
processed_frame = final_results.plot(img=frame.copy())
detection_info = {'objects': defaultdict(int), 'total': 0}
detections = []
if final_results.boxes is not None:
detection_info['total'] = len(final_results.boxes)
for box in final_results.boxes:
if hasattr(box, 'cls') and box.cls is not None:
cls_id = int(box.cls.item())
if cls_id < len(model.names):
class_name = model.names[cls_id]
detection_info['objects'][class_name] += 1
xyxy = box.xyxy[0].cpu().numpy()
conf = float(box.conf.item())
detections.append({
'x1': int(xyxy[0]),
'y1': int(xyxy[1]),
'x2': int(xyxy[2]),
'y2': int(xyxy[3]),
'conf': conf,
'class': cls_id,
'name': class_name
})
global class_counts
for class_name, count in detection_info['objects'].items():
if class_name not in class_counts:
class_counts[class_name] = 0
class_counts[class_name] += count
processed_frame = draw_detection_results(processed_frame, detection_info)
result = format_detection_output(detection_info, detections)
return processed_frame, result
def video_frame_processing(frame, timestamp_ms, is_camera):
global frame_count
current_time = time.time()
frame_count += 1
processed_frame, result = process_video_frame(frame, timestamp_ms, is_camera)
return processed_frame, result, current_time
display_program_header()
np.random.seed(RANDOM_SEED)
torch.manual_seed(RANDOM_SEED)
print('=== YOLO11モデル選択 ===')
print('使用するYOLO11モデルを選択してください:')
for key, info in MODEL_INFO.items():
print(f'{key}: {info["name"]} ({info["size"]}) - {info["desc"]}')
print()
model_choice = ''
while model_choice not in MODEL_INFO.keys():
model_choice = input("選択 (n/s/m/l/x) [デフォルト: n]: ").strip().lower()
if model_choice == '':
model_choice = 'n'
break
if model_choice not in MODEL_INFO.keys():
print("無効な選択です。もう一度入力してください。")
MODEL_NAME = MODEL_INFO[model_choice]['name']
selected_size = MODEL_INFO[model_choice]['size']
print(f'\nモデル: {MODEL_NAME} ({selected_size}) を選択しました。')
print('=' * 60)
if not os.path.exists(MODEL_NAME):
print(f'モデルファイル {MODEL_NAME} はローカルに存在しません。')
print(f'Ultralyticsライブラリによる自動ダウンロードを試みます...')
print(f'YOLO11モデル {MODEL_NAME} をロード中...')
try:
model = YOLO(MODEL_NAME)
model.to(device)
model.eval()
print(f'モデルのロードが完了しました')
print('')
except Exception as e:
print(f'モデルのロードに失敗しました: {e}')
raise SystemExit(1)
print("=== YOLO11リアルタイム物体検出・セグメンテーション(COCO対応) ===")
print("0: 動画ファイル")
print("1: カメラ")
print("2: サンプル動画")
choice = input("選択: ")
is_camera = (choice == '1')
if choice == '0':
root = tk.Tk()
root.withdraw()
path = filedialog.askopenfilename()
if path:
cap = cv2.VideoCapture(path)
else:
raise SystemExit(1)
elif choice == '1':
cap = ThreadedVideoCapture(0, is_camera=True)
elif choice == '2':
SAMPLE_URL = 'https://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.avi'
SAMPLE_FILE = 'vtest.avi'
if not os.path.exists(SAMPLE_FILE):
print(f'サンプル動画 {SAMPLE_FILE} をダウンロードします...')
urllib.request.urlretrieve(SAMPLE_URL, SAMPLE_FILE)
print('ダウンロードが完了しました。')
cap = cv2.VideoCapture(SAMPLE_FILE)
else:
raise SystemExit(1)
if not cap.isOpened():
print('動画ソースを開けませんでした。プログラムを終了します。')
raise SystemExit(1)
if is_camera:
actual_fps = cap.get(cv2.CAP_PROP_FPS)
print(f'カメラのfps: {actual_fps}')
timestamp_increment = int(1000 / actual_fps) if actual_fps > 0 else 33
else:
video_fps = cap.get(cv2.CAP_PROP_FPS)
timestamp_increment = int(1000 / video_fps) if video_fps > 0 else 33
print('\n=== 動画処理開始 ===')
print('操作方法:')
print(' q キー: プログラム終了')
start_time = time.time()
last_info_time = start_time
info_interval = 10.0
timestamp_ms = 0
total_processing_time = 0.0
try:
while True:
ret, frame = cap.read()
if not ret:
print('動画の終端に達したか、フレームを読み込めませんでした。')
break
timestamp_ms += timestamp_increment
processing_start = time.time()
processed_frame, result, current_time = video_frame_processing(frame, timestamp_ms, is_camera)
processing_time = time.time() - processing_start
total_processing_time += processing_time
cv2.imshow(WINDOW_NAME, processed_frame)
if is_camera:
timestamp = datetime.fromtimestamp(current_time).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
print(timestamp, result)
else:
print(frame_count, result)
results_log.append(result)
if is_camera:
elapsed = current_time - last_info_time
if elapsed >= info_interval:
total_elapsed = current_time - start_time
actual_fps = frame_count / total_elapsed if total_elapsed > 0 else 0
avg_processing_time = (total_processing_time / frame_count * 1000) if frame_count > 0 else 0
print(f'[情報] 経過時間: {total_elapsed:.1f}秒, 処理フレーム数: {frame_count}, 実測fps: {actual_fps:.1f}, 平均処理時間: {avg_processing_time:.1f}ms')
last_info_time = current_time
if cv2.waitKey(1) & 0xFF == ord('q'):
break
finally:
print('\n=== プログラム終了 ===')
if cap:
cap.release()
cv2.destroyAllWindows()
if results_log:
with open('result.txt', 'w', encoding='utf-8') as f:
f.write('=== YOLO11物体検出・セグメンテーション結果 ===\n')
f.write(f'処理フレーム数: {frame_count}\n')
f.write(f'使用モデル: {MODEL_NAME}\n')
f.write(f'モデル情報: {MODEL_INFO[model_choice]["desc"]}\n')
f.write(f'使用デバイス: {str(device).upper()}\n')
if device.type == 'cuda':
f.write(f'GPU: {torch.cuda.get_device_name(0)}\n')
f.write(f'画像処理: CLAHE適用(YUV色空間)\n')
f.write(f'信頼度閾値: {CONF_THRESHOLD}\n')
f.write(f'\n検出されたクラス一覧:\n')
for class_name, count in sorted(class_counts.items()):
jp_name = CLASS_NAMES_JP.get(class_name, class_name)
f.write(f' {jp_name} ({class_name}): {count}回\n')
if is_camera:
f.write('\n形式: タイムスタンプ, 検出結果\n')
else:
f.write('\n形式: フレーム番号, 検出結果\n')
f.write('\n')
f.write('\n'.join(results_log))
print(f'処理結果をresult.txtに保存しました')
print(f'検出されたクラス数: {len(class_counts)}')
実験・探求のアイデア
YOLO11-segモデル選択実験
異なるYOLO11-segモデルを比較できる:
yolo11n-seg.pt:Nano版(最高効率、エッジデバイス最適)yolo11s-seg.pt:Small版(バランス型、実用性重視)yolo11m-seg.pt:Medium版(汎用用途、精度向上)yolo11l-seg.pt:Large版(高精度重視、計算コスト増)yolo11x-seg.pt:Extra Large版(最高性能、最大計算要求)
空間アテンション機構の検証実験
C2PSAの並列空間アテンション効果を定量的に評価:
- 小物体検出:C2PSAによる小さな物体の検出精度向上の測定
- 重複物体分離:密集環境でのインスタンス分離能力の評価
- 部分遮蔽対応:遮蔽された物体のセグメンテーション復元性能
- 複雑背景処理:背景が複雑な環境での物体境界検出精度
体験・実験・探求のアイデア
アーキテクチャ改良効果の測定: C3k2とC2PSAの技術革新により、従来困難であった複雑シーンでの性能向上を定量的に測定
リアルタイム応用実験:
- 自動運転シミュレーション:車両、歩行者、道路標識の精密セグメンテーション
- 医療画像解析:X線、MRI画像での病変部位セグメンテーション
- 工業検査:製品の欠陥部位自動検出とセグメンテーション
- 映像制作:リアルタイム背景除去と合成
多スケール検出能力の実験: SPPFによる異なるサイズの物体同時検出性能を評価