RT-DETRv2による物体検出(COCO 80クラス)(ソースコードと説明と利用ガイド)
【概要】RT-DETRv2は、Transformerベースのリアルタイム物体検出技術で、動画やカメラ映像からCOCO 80クラスの物体を自動検出。CLAHE画像処理により検出精度を向上させ、ResNet-50D、ResNet-101D、HGNetv2-Lの3つのモデルから選択可能。日本語表示対応、検出結果の自動保存機能を備える。
プログラム利用ガイド
1. このプログラムの利用シーン
動画ファイルやウェブカメラの映像から、リアルタイムで物体を自動検出するためのソフトウェアである。監視システム、交通量調査、品質管理、動物観察など、動画内の物体を自動認識する用途に適用できる。
2. 主な機能
- リアルタイム物体検出: 動画の各フレームからCOCOクラス物体を検出し、バウンディングボックスとラベルで表示する。
- CLAHE画像処理: 適応ヒストグラム均等化により検出精度を向上させる。
- モデル選択: ResNet-50D、ResNet-101D、HGNetv2-Lの3つのバックボーンから性能要件に応じて選択可能である。
- 結果保存: 検出結果をテキストファイル(result.txt)に自動保存する。
- GPU/CPU自動対応: 実行環境に応じてCUDAまたはCPUを自動選択する。
3. 基本的な使い方
- プログラム起動とモデル選択:
プログラム実行後、モデル選択画面で1(ResNet-50D)、2(ResNet-101D)、3(HGNetv2-L)から選択する。
- 入力ソースの選択:
処理対象として0(動画ファイル)、1(カメラ)、2(サンプル動画)のいずれかを入力する。動画ファイルを選択した場合、ファイル選択ダイアログが表示される。
- 処理実行:
選択後、自動的に物体検出処理が開始される。検出された物体はバウンディングボックスとクラス名、信頼度とともに表示される。
- 終了方法:
表示画面でqキーを押すとプログラムが終了し、処理結果がresult.txtに保存される。
4. 便利な機能
- 信頼度表示: 各検出結果に信頼度がパーセンテージで表示され、検出精度を確認できる。
- フレーム情報表示: 画面上部に現在のフレーム番号と検出物体数が表示される。
- 自動ファイル管理: サンプル動画が自動ダウンロードされ、結果ファイルが自動生成される。
- Windows日本語対応: Meiryoフォントを使用した日本語表示に対応する。
- クラス別統計: 検出されたクラスごとの出現回数を記録し、結果ファイルに保存する。
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/
必要なライブラリのインストール
コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する:
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install transformers opencv-python numpy pillow
RT-DETRv2による物体検出プログラム(COCO検出)
概要
このプログラムは、RT-DETRv2(Real-Time Detection Transformer version 2)を用いた物体検出システムである。動画フレームからリアルタイムで物体を検出し、バウンディングボックスとともに結果を表示する。CLAHE(Contrast Limited Adaptive Histogram Equalization)による画像前処理により、検出精度の向上を図る。
主要技術
RT-DETRv2(Real-Time Detection Transformer version 2)
RT-DETRv2は、RT-DETRの改良版として開発されたTransformerベースのリアルタイム物体検出アルゴリズムである[1]。Bag-of-Freebiesによる改良ベースラインと選択的マルチスケール特徴抽出を特徴とする。deformable attentionモジュールにおいて、異なるスケールの特徴に対して異なる数のサンプリングポイントを設定することで、デコーダによる選択的マルチスケール特徴抽出を実現する。
CLAHE(Contrast Limited Adaptive Histogram Equalization)
CLAHEは、画像を小さな領域に分割し、各領域で局所的なヒストグラム均等化を実行する適応型ヒストグラム均等化手法である[2]。YUVカラー空間における明度チャンネル(Y)に適用される。
技術的特徴
- CLAHE前処理
CLAHE(Contrast Limited Adaptive Histogram Equalization)をYUVカラー空間における明度チャンネル(Y)に適用し、画像コントラストを向上させる。
- マルチモデル対応
ResNet-50D、ResNet-101D、HGNetv2-Lをバックボーンとする3つのモデルから選択可能である。
- GPU/CPU自動選択
実行環境に応じてCUDAまたはCPUを自動選択し、処理を実行する。
実装の特色
以下の機能を備える:
- 3つの入力ソース選択(動画ファイル、カメラ、サンプル動画)
- 信頼度閾値による検出結果のフィルタリング(デフォルト0.25)
- リアルタイム処理結果の画面表示
- 処理結果のテキストファイル保存機能
- Pillowを用いた日本語テキスト描画(Windows環境対応)
- COCOデータセット物体検出
- クラス別検出統計機能
参考文献
[1] Lv, W., Zhao, Y., Chang, Q., Huang, K., Wang, G., & Liu, Y. (2024). RT-DETRv2: Improved Baseline with Bag-of-Freebies for Real-Time Detection Transformer. arXiv preprint arXiv:2407.17140. https://arxiv.org/abs/2407.17140
[2] Zuiderveld, K. (1994). Contrast Limited Adaptive Histogram Equalization. In Graphics Gems IV (pp. 474-485). Academic Press Professional. https://en.wikipedia.org/wiki/Adaptive_histogram_equalization
ソースコード
"""
プログラム名: RT-DETRv2による物体検出プログラム(COCO 80クラス)
特徴技術名: RT-DETRv2 (Real-Time Detection Transformer version 2)
出典: W. Lv, Y. Zhao, Q. Chang, K. Huang, G. Wang, and Y. Liu, "RT-DETRv2: Improved Baseline with Bag-of-Freebies for Real-Time Detection Transformer," arXiv preprint arXiv:2407.17140, 2024.
特徴機能: Bag-of-Freebiesによる改良ベースラインと選択的マルチスケール特徴抽出による物体検出
学習済みモデル: PekingU/rtdetr_v2_r50vd/r101vd/hgnetv2_l(Hugging Face Transformers)、COCOデータセットで事前学習済み
特徴技術および学習済モデルの利用制限: Apache License 2.0に準拠(Hugging Face Transformers)。学術研究および商用利用が可能。ただし、モデルの再配布時にはライセンス表記が必要。必ず利用者自身でHugging Faceのモデルカードおよびライセンス情報を確認すること。
方式設計:
関連利用技術:
- PyTorch: ディープラーニングフレームワーク、GPU/CPU自動選択
- Transformers: Hugging Face Transformersライブラリ
- OpenCV: 画像・動画処理、カメラ制御
- CLAHE (Contrast Limited Adaptive Histogram Equalization): 低照度環境での画像品質向上
入力と出力: 入力: 動画(ユーザは「0:動画ファイル,1:カメラ,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.aviを使用)、出力: OpenCV画面でリアルタイム表示、検出結果をresult.txtに保存
処理手順: 1.動画フレーム取得→2.CLAHE前処理→3.RT-DETRv2推論実行→4.バウンディングボックス抽出→5.結果描画
前処理、後処理: 前処理:CLAHE適用による画像コントラスト強化、後処理:post_process_object_detection()による結果整形
調整を必要とする設定値: CONF_THRESH(信頼度閾値、デフォルト0.25)- 検出感度を制御、値が低いほど多くの物体を検出
将来方策: 信頼度閾値の自動最適化 - 検出結果の時系列分析により、シーンごとに最適な閾値を動的に学習・適用する機能
その他の重要事項: COCOクラス検出可能、Windows環境での動作を想定(フォントはC:/Windows/Fonts/meiryo.ttc を使用)
前準備:
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install transformers opencv-python numpy pillow
"""
import cv2
import numpy as np
import torch
from transformers import RTDetrV2ForObjectDetection, AutoImageProcessor
import tkinter as tk
from tkinter import filedialog
import urllib.request
import time
import sys
import io
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
import warnings
import threading
warnings.filterwarnings('ignore')
# Windows文字エンコーディング設定
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', line_buffering=True)
# GPU/CPU自動選択
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f'デバイス: {str(device)}')
# GPU使用時の最適化
if device.type == 'cuda':
torch.backends.cudnn.benchmark = True
# モデル情報の構造化
MODEL_INFO = {
'1': {
'name': 'PekingU/rtdetr_v2_r50vd',
'desc': 'ResNet-50D backbone (高速性と精度のバランス)',
'backbone': 'ResNet-50D'
},
'2': {
'name': 'PekingU/rtdetr_v2_r101vd',
'desc': 'ResNet-101D backbone (高精度)',
'backbone': 'ResNet-101D'
},
'3': {
'name': 'PekingU/rtdetr_v2_hgnetv2_l',
'desc': 'HGNetv2-L backbone (最高精度)',
'backbone': 'HGNetv2-L'
}
}
# 調整可能な設定値
CONF_THRESH = 0.25 # 信頼度閾値 - 検出感度制御
CLAHE_CLIP_LIMIT = 3.0 # CLAHE制限値
CLAHE_TILE_SIZE = (8, 8) # CLAHEタイルサイズ
WINDOW_NAME = "RT-DETRv2 COCO Detection" # OpenCVウィンドウ名
# CLAHEオブジェクトをグローバルスコープで一度だけ定義(AIモデルの入力用にCLAHEを適用)
clahe = cv2.createCLAHE(clipLimit=CLAHE_CLIP_LIMIT, tileGridSize=CLAHE_TILE_SIZE)
# BGR→RGB色変換のヘルパー関数
def bgr_to_rgb(color_bgr):
"""BGRカラーをRGBカラーに変換"""
return (color_bgr[2], color_bgr[1], color_bgr[0])
# クラスごとの色生成(HSVからBGRに変換)
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
# 日本語クラス名マッピング(COCO対応)
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_MAIN = 16
font_main = ImageFont.truetype(FONT_PATH, FONT_SIZE_MAIN)
# グローバル変数
frame_count = 0
results_log = []
class_counts = {}
model = None
processor = None
id2label = {}
CLASS_COLORS = []
class ThreadedVideoCapture:
"""スレッド化されたVideoCapture(常に最新フレームを取得)"""
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)
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('=== RT-DETRv2オブジェクト検出プログラム ===')
print('=' * 60)
print('概要: CLAHEを適用し、リアルタイムでオブジェクトを検出します')
print('機能: RT-DETRv2による物体検出(COCOデータセット対応)')
print('技術: CLAHE (コントラスト強化) + Transformers + RT-DETRv2')
print('操作: qキーで終了')
print('出力: 各フレームごとに処理結果を表示し、終了時にresult.txtへ保存')
print()
# ===== 物体検出タスク固有の処理 =====
def draw_detection_results(frame, detections):
"""物体検出の描画処理"""
# バウンディングボックスを描画(OpenCVで)
for det in detections:
color_seed = det['class']
color = CLASS_COLORS[color_seed % len(CLASS_COLORS)]
cv2.rectangle(frame, (det['x1'], det['y1']),
(det['x2'], det['y2']), color, 2)
# 構造化されたテキスト描画を実行
texts_to_draw = []
for det in detections:
color_seed = det['class']
color = CLASS_COLORS[color_seed % len(CLASS_COLORS)]
jp_name = CLASS_NAMES_JP.get(det['name'], det['name'])
label = f"{jp_name}: {det['conf']:.2f}"
texts_to_draw.append({
'text': label,
'org': (det['x1'], det['y1']-20),
'color': bgr_to_rgb(color),
'font_type': 'main'
})
frame = draw_texts_with_pillow(frame, texts_to_draw)
# 統計情報を描画
info_text = f"Objects: {len(detections)} | Frame: {frame_count} | Classes: {len(set(d['name'] for d in detections)) if detections else 0}"
cv2.putText(frame, info_text, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
return frame
def format_detection_output(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 draw_texts_with_pillow(bgr_frame, texts):
"""テキスト描画, texts: list of dict with keys {text, org, color, font_type}"""
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'] # RGB
draw.text((x, y), text, font=font_main, fill=color)
return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
def detect_objects(frame):
"""共通の検出処理(CLAHE、推論、検出を実行)"""
global model, processor, id2label
# AIモデルの入力用にCLAHEを適用(YUV色空間で輝度チャンネルのみ処理)
yuv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV)
yuv_frame[:, :, 0] = clahe.apply(yuv_frame[:, :, 0])
enh_frame = cv2.cvtColor(yuv_frame, cv2.COLOR_YUV2BGR)
# RT-DETRv2推論処理
img_pil = Image.fromarray(cv2.cvtColor(enh_frame, cv2.COLOR_BGR2RGB))
inputs = processor(images=img_pil, return_tensors='pt')
for k in inputs:
if isinstance(inputs[k], torch.Tensor):
inputs[k] = inputs[k].to(device)
with torch.no_grad():
outputs = model(**inputs)
target_sizes = torch.tensor([enh_frame.shape[:2]], device=device)
results = processor.post_process_object_detection(
outputs,
target_sizes=target_sizes,
threshold=CONF_THRESH
)[0]
curr_dets = []
if len(results['scores']) > 0:
scores = results['scores'].cpu().numpy()
labels = results['labels'].cpu().numpy()
boxes = results['boxes'].cpu().numpy()
# スコア降順でソート
order = np.argsort(scores)[::-1]
for i in order:
x1, y1, x2, y2 = map(int, boxes[i])
conf_score = float(scores[i])
cls = int(labels[i])
name = id2label.get(cls, str(cls))
curr_dets.append({
'x1': x1, 'y1': y1,
'x2': x2, 'y2': y2,
'conf': conf_score,
'class': cls,
'name': name
})
return curr_dets
def process_video_frame(frame, timestamp_ms, is_camera):
"""動画用ラッパー"""
# 共通の検出処理
detections = detect_objects(frame)
# クラスごとの検出数を更新
global class_counts
for det in detections:
name = det['name']
if name not in class_counts:
class_counts[name] = 0
class_counts[name] += 1
# 物体検出固有の描画処理
frame = draw_detection_results(frame, detections)
# 物体検出固有の出力フォーマット
result = format_detection_output(detections)
return 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()
# モデル選択(対話的実装に改善)
print("\n=== RT-DETRv2モデル選択 ===")
print('使用するRT-DETRv2モデルを選択してください:')
for key, info in MODEL_INFO.items():
print(f'{key}: {info["name"]} ({info["desc"]})')
print()
model_choice = ''
while model_choice not in MODEL_INFO.keys():
model_choice = input("選択 (1/2/3) [デフォルト: 1]: ").strip()
if model_choice == '':
model_choice = '1'
break
if model_choice not in MODEL_INFO.keys():
print("無効な選択です。もう一度入力してください。")
# モデルの初期化
print(f"\nRT-DETRv2モデルをロード中...")
try:
model_name = MODEL_INFO[model_choice]['name']
model = RTDetrV2ForObjectDetection.from_pretrained(model_name)
processor = AutoImageProcessor.from_pretrained(model_name)
model.to(device)
model.eval()
# ラベルマッピングとクラス色の設定
id2label = {int(k): v for k, v in model.config.id2label.items()}
NUM_CLASSES = len(id2label)
CLASS_COLORS = generate_class_colors(NUM_CLASSES)
# 検出可能なクラスを表示
print(f"\n検出可能なクラス数: {len(id2label)}")
print(f"クラス一覧: {', '.join(id2label.values())}")
print(f"モデル情報: {MODEL_INFO[model_choice]['desc']}")
print("モデルのロード完了")
except Exception as e:
print(f"モデルのロードに失敗しました: {e}")
raise SystemExit(1)
# 入力選択
print("\n=== RT-DETRv2リアルタイム物体検出(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 not path:
raise SystemExit(1)
cap = cv2.VideoCapture(path)
elif choice == '1':
cap = ThreadedVideoCapture(0, is_camera=True)
else:
print('サンプル動画をダウンロード中...')
SAMPLE_URL = 'https://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.avi'
SAMPLE_FILE = 'vtest.avi'
urllib.request.urlretrieve(SAMPLE_URL, SAMPLE_FILE)
cap = cv2.VideoCapture(SAMPLE_FILE)
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 # 10秒ごとに表示
timestamp_ms = 0
total_processing_time = 0.0
try:
while True:
ret, frame = cap.read()
if not ret:
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 result:
if is_camera:
timestamp = datetime.fromtimestamp(current_time).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
print(f'{timestamp}, {result}')
else:
print(f'Frame {frame_count}: {result}')
results_log.append(result)
# 情報提供(カメラモードのみ、info_interval秒ごと)
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=== プログラム終了 ===')
cap.release()
cv2.destroyAllWindows()
if results_log:
with open('result.txt', 'w', encoding='utf-8') as f:
f.write('=== RT-DETRv2物体検出結果 ===\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_THRESH}\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'\n処理結果をresult.txtに保存しました')
print(f'検出されたクラス数: {len(class_counts)}')
実験・探求のアイデア
AIモデル選択実験
- RT-DETR-R18、RT-DETR-R50、RT-DETR-R101の性能比較、実行速度の違い検証
検出パラメータ実験
- 信頼度閾値(0.1〜0.9)の変更による検出数変化の観察
- 特定クラスのみの検出(例:person、car、catのみ)
体験・実験・探求のアイデア
- 重複するバウンディングボックスが現れた場合の検出精度確認
- 照明条件(明るい・暗い環境)での検出性能変化
- 小さな物体と大きな物体の検出精度差の検証
- 動画ファイルでの物体検出と追跡実験
- カメラ解像度変更による検出精度への影響調査
- RT-DETRとYOLO系モデルの同時実行による性能比較