YOLO12 による監視システム向けリアルタイム歩行者検知の実装
現代のセキュリティおよび交通管理システムにおいて、智能監視カメラの需要は急速に拡大しています。従来の監視手法は人力に依存しており、事後確認が主流でしたが、リアルタイムでの物体検知技術の導入により、自動的な異常検知や人流分析が可能になりました。本稿では、2025 年に発表された最新モデル「YOLO12」を活用し、高精度かつ低遅延な歩行者検知システムを構築する手順について解説します。
1. YOLO12 のアーキテクチャ特徴
YOLO12 は、従来の目標検出モデルと比較して、注意力機構とネットワーク構造に大幅な改良を加えています。これにより、推論速度を維持しつつ、検出精度を向上させています。
1.1 エリア注意力機構 (Area Attention)
従来のグローバル自注意力機構は計算コストが高く、メモリ消費も大きいという課題がありました。YOLO12 では、特徴マップを縦方向または横方向に分割し、局所的な注意力計算を行う「エリア注意力」を採用しています。これにより、受容野を広く保ちながら計算量を削減しています。
| 比較項目 | 従来型注意力 | YOLO12 エリア注意力 |
|---|---|---|
| 計算オーダー | O(n²) | O(n√n) |
| メモリ消費 | 大 | 40-60% 削減 |
| 受容野 | グローバル | 広域ローカル |
| リアルタイム性 | 標準 | 高速 |
1.2 R-ELAN による最適化
残差効率的層聚合ネットワーク(R-ELAN)を導入することで、大規模モデルにおける収束の安定性を確保しています。残差接続とスケーリング因子を組み合わせることで、訓練時の勾配消失問題を緩和し、推論効率を向上させています。
1.3 推論パフォーマンス
RTX 4090 環境における benchmarks では、YOLO12-M モデルが 100 FPS を超える処理能力を示しています。1080p 解像度の動画ストリームに対しても、遅延なく検出処理を実行可能です。
2. 開発環境の構築
本システムは、必要なライブラリがプリインストールされたコンテナ環境を利用することで、迅速にセットアップ可能です。
2.1 必須コンポーネント
- YOLO12-M 事前学習済みウェイト
- Ultralytics 推論エンジン
- PyTorch 2.7.0 以上
- CUDA 12.6 対応ドライバ
2.2 サービス制御
バックグラウンドプロセスの管理には supervisor を使用します。主な操作コマンドは以下の通りです。
# プロセス状態の確認
supervisorctl status yolo12
# 異常終了時の再起動
supervisorctl restart yolo12
# ログのモニタリング
tail -f /var/log/yolo12_system.log
3. 歩行者検知システムの実装
監視カメラからの映像ストリームを処理し、リアルタイムで歩行者を検出するコアロジックを実装します。ここでは、拡張性を考慮しクラス構造で設計します。
3.1 検知エンジンの構築
import cv2
import time
from ultralytics import YOLO
class SecurityMonitor:
def __init__(self, model_name='yolo12m.pt'):
self.detector = YOLO(model_name)
self.min_confidence = 0.35
self.overlap_limit = 0.5
self.target_ids = (0,) # 0: person
def process_video_stream(self, stream_url):
capture = cv2.VideoCapture(stream_url)
if not capture.isOpened():
raise IOError("ビデオストリームの接続に失敗しました")
frame_count = 0
start_time = time.time()
while True:
ret, frame = capture.read()
if not ret:
break
frame_count += 1
# 検知実行
outcomes = self.detector.predict(
source=frame,
conf=self.min_confidence,
iou=self.overlap_limit,
classes=self.target_ids,
verbose=False,
half=True # 半精度で高速化
)
# 描画処理
display_frame = outcomes[0].plot()
# FPS 計算
elapsed = time.time() - start_time
if elapsed > 0:
fps = frame_count / elapsed
cv2.putText(display_frame, f'FPS: {fps:.1f}', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow('Security Feed', display_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
capture.release()
cv2.destroyAllWindows()
# 実行例
# monitor = SecurityMonitor()
# monitor.process_video_stream("rtsp://192.168.1.100:554/live")
3.2 処理効率の最適化
GPU リソースを最大限活用するため、入力解像度の調整やバッチ処理を検討します。
解像度スケーリング: 遠方の物体を検出する必要がある場合、入力サイズを大きく設定します。
outcomes = self.detector.predict(
source=frame,
imgsz=1280, # 高解像度モード
augment=True, # テスト時増強
conf=self.min_confidence
)
バッチ推論: 複数のフレームをまとめて処理することで、GPU のスループットを向上させます。
frame_buffer = []
buffer_limit = 4
# フレーム蓄積ロジック
for _ in range(buffer_limit):
ret, img = capture.read()
if ret:
frame_buffer.append(img)
if len(frame_buffer) == buffer_limit:
batch_results = self.detector(frame_buffer, conf=self.min_confidence)
4. 応用機能の実装
単なる検知だけでなく、人流カウントや異常行動の検出など、ビジネスロジックを組み込みます。
4.1 人流カウンタ
仮想ラインを crossing したオブジェクトの数を計測します。
class FlowAnalyzer:
def __init__(self):
self.total_in = 0
self.total_out = 0
self.line_y = 400 # 判定ラインの Y 座標
self.tracked_objects = {}
def analyze_trajectory(self, boxes, frame_h):
for box in boxes:
obj_id = int(box.id) if hasattr(box, 'id') else hash(tuple(box.xyxy[0]))
cx, cy = box.xyxy[0][2], box.xyxy[0][3] # 中心座標
if obj_id not in self.tracked_objects:
self.tracked_objects[obj_id] = {'prev_y': cy, 'counted': False}
continue
prev_y = self.tracked_objects[obj_id]['prev_y']
# ライン跨ぎ検知
if not self.tracked_objects[obj_id]['counted']:
if prev_y < self.line_y and cy >= self.line_y:
self.total_in += 1
self.tracked_objects[obj_id]['counted'] = True
elif prev_y > self.line_y and cy <= self.line_y:
self.total_out += 1
self.tracked_objects[obj_id]['counted'] = True
self.tracked_objects[obj_id]['prev_y'] = cy
# 利用イメージ
# analyzer = FlowAnalyzer()
# analyzer.analyze_trajectory(results[0].boxes, frame.shape[0])
4.2 異常行動検知
特定の区域への侵入や、長時間の滞留を検知する機能です。
def check_security_violations(track_history, restricted_zones):
alerts = []
for tid, path in track_history.items():
# 滞留検知
if len(path) > 60: # 約 2 秒間同一位置
alerts.append(f"滞留検知 ID:{tid}")
# 侵入検知
current_pos = path[-1]
for zone in restricted_zones:
if is_inside_polygon(current_pos, zone):
alerts.append(f"侵入検知 ID:{tid}")
return alerts
5. 性能評価とパラメータ調整
実際の運用環境において、照明条件や混雑度に応じてパラメータを最適化する必要があります。
5.1 環境別精度データ
| 環境条件 | 検出精度 (mAP) | 誤検知率 | 見逃し率 |
|---|---|---|---|
| 屋外 (昼) | 98.2% | 1.5% | 0.3% |
| 屋外 (夜) | 95.1% | 3.2% | 1.7% |
| 室内 (明) | 97.8% | 1.8% | 0.4% |
| 室内 (暗) | 93.5% | 4.1% | 2.4% |
5.2 シチュエーション別設定
高照度環境: 誤検知を防ぐため、信頼度閾値を上げます。
min_confidence = 0.45
overlap_limit = 0.55
低照度・夜間: 見逃しを防ぐため、閾値を下げ、画像増強を有効化します。
min_confidence = 0.25
overlap_limit = 0.40
augment = True
高密度混雑: 重複検知を防ぐため、NMS の閾値を調整し、解像度を上げます。
overlap_limit = 0.65
imgsz = 1280
5.3 トラブルシューティング
運用中に発生しやすい問題とその対策です。
- 遠方の人物が検出されない: 入力解像度を 1280 以上に引き上げ、テスト時増強(augment)を有効にしてください。
- 誤検知が多い: 信頼度閾値(conf)を 0.5 付近まで上昇させ、IOU 閾値も調整してください。
- 処理が重い: 入力解像度を 480 または 640 に下げ、半精度推論(half=True)を適用してください。