post-cover

本記事で紹介するプログラムは以下の GitHub リポジトリで公開しています

GitHub - face-mosaic

はじめに

お客様からこんなご相談をいただきました。

「監視カメラの映像を YouTube でライブ配信したい。でも、映り込む人のプライバシーは守りたいので顔にモザイクをかけたい。」

そこで監視カメラの RTSP ストリームから映像を取得し、プライバシー保護のために人物の頭部にリアルタイムでモザイクをかけるシステムを開発しました。

当初は OpenCV の従来的な検出手法を使用していましたが、精度が悪かったため、YOLOv8 による実装に移行することで大幅な精度向上を達成しました。

本記事では、その実装過程と技術的な知見を共有します。

システム要件

開発環境

  • Python 3.x
  • OpenCV (cv2)
  • NumPy
  • FFmpeg
  • Ultralytics YOLOv8

ハードウェア要件

  • CPU: Intel Core i5 以上推奨
  • RAM: 8GB 以上
  • GPU: NVIDIA GPU(オプション、処理速度向上のため)

第一段階:従来手法による実装(face-mosaic.py)

採用した検出手法

最初の実装では、以下の 3 つの検出器を組み合わせました:

  1. Haar Cascade(正面顔検出)
  2. Haar Cascade(横顔検出)
  3. HOG(Histogram of Oriented Gradients)+ SVM(人物全体検出)

実装の詳細

# 顔検出器の初期化
face_cascade = cv2.CascadeClassifier(
    cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
profile_cascade = cv2.CascadeClassifier(
    cv2.data.haarcascades + 'haarcascade_profileface.xml'
)

# HOG人物検出器
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())

# 検出処理
faces_front = face_cascade.detectMultiScale(
    gray,
    scaleFactor=1.2,
    minNeighbors=8,
    minSize=(50, 50)
)

people, _ = hog.detectMultiScale(
    frame,
    winStride=(16, 16),
    padding=(4, 4),
    scale=1.1
)

直面した課題

1. 誤検知の多発

従来手法では以下のような誤検知が頻繁に発生しました:

  • 建物や柱の検出: HOG 検出器が人の形に似た垂直構造を誤認識
  • 窓や影の検出: 横顔検出器が特定のパターンを顔と誤認識
  • 背景のテクスチャ: 複雑な背景が顔のような特徴として検出される

description-face-mosaic-001

2. 検出精度の限界

  • 正面顔のみの検出: Haar Cascade は角度に敏感
  • 照明条件への脆弱性: 明るさの変化で検出率が大きく変動
  • 遠距離・小サイズの人物: minSize パラメータを大きくすると検出漏れが増加

3. パラメータチューニングの困難さ

誤検知を減らすため以下のパラメータを調整しましたが、根本的な解決には至りませんでした:

# パラメータの厳格化
scaleFactor=1.2        # 1.1から変更(検出速度低下)
minNeighbors=8         # 5から変更(検出数減少)
minSize=(50, 50)       # (30, 30)から変更(小さい顔を見逃す)

# サイズフィルタリング
area_ratio = (w * h) / (OUTPUT_WIDTH * OUTPUT_HEIGHT)
if area_ratio < 0.005 or area_ratio > 0.3:
    continue

# アスペクト比チェック
aspect_ratio = w / h if h > 0 else 0
if aspect_ratio < 0.7 or aspect_ratio > 1.5:
    continue

これらの対策により誤検知は減少しましたが、同時に正しい検出も見逃すトレードオフが発生しました。

パフォーマンス

  • フレームレート: 約 20-25 FPS(1280x720)
  • 検出精度: 60-70%程度
  • 誤検知率: 高い(特に複雑な背景において)

第二段階:YOLOv8 による実装(face-mosaic-yolov8.py)

YOLOv8 を選択した理由

YOLOv8(You Only Look Once v8)は、Ultralytics が開発した最新の物体検出モデルで、以下の特徴があります:

  1. リアルタイム処理: 高速な推論速度
  2. 高精度: ディープラーニングベースの検出
  3. 汎用性: COCO データセットで学習済み(80 クラスの物体検出)
  4. 使いやすい API: Python からの簡単な実装

実装アーキテクチャ

from ultralytics import YOLO

# モデルの読み込み(初回は自動ダウンロード)
model = YOLO('yolov8n.pt')  # Nanoモデル(高速)

# 人物検出(クラス0が人物)
results = model(
    frame,
    classes=[0],                    # 人物クラスのみ
    conf=CONFIDENCE_THRESHOLD,      # 信頼度閾値0.5
    verbose=False                   # ログ抑制
)

# 検出結果の処理
for result in results:
    boxes = result.boxes
    for box in boxes:
        x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
        confidence = box.conf[0].cpu().numpy()

        # 頭部領域の計算(人物の上部25%)
        person_w = x2 - x1
        person_h = y2 - y1
        head_h = int(person_h * HEAD_HEIGHT_RATIO)

        # モザイク処理
        frame = apply_mosaic(frame, x1, y1, person_w, head_h)

YOLOv8 の利点

1. 圧倒的な検出精度

YOLOv8を導入したことで、OpenCV(Haar Cascade)を用いた従来の検出と比較して誤検知は本検証中には一度も発生しませんでした。人物を非常に高速かつ正確に認識し、検出後ただちに顔へモザイク処理が適用されます。

  • 人物の正確な認識: ディープラーニングによる高精度な特徴抽出
  • 様々な角度に対応: 正面、横向き、後ろ向きでも検出可能
  • 照明変化に強い: 学習データの多様性により頑健

description-face-mosaic-002

2. 誤検知の劇的な削減

YOLOv8 は文脈を理解して検出するため、以下のような誤検知がほぼ消失しました:

  • 建物や柱の誤検出 → 解消
  • 窓や影の誤検出 → 解消
  • 複雑な背景のノイズ → 大幅に削減

3. シンプルな実装

# Haar Cascade: 複雑なパラメータチューニングが必要
faces = face_cascade.detectMultiScale(
    gray,
    scaleFactor=1.2,      # 要調整
    minNeighbors=8,       # 要調整
    minSize=(50, 50),     # 要調整
    maxSize=(500, 500)    # 要調整
)

# YOLOv8: 信頼度のみで制御可能
results = model(frame, classes=[0], conf=0.5)

モデルの選択肢

YOLOv8 には複数のモデルサイズがあり、用途に応じて選択できます:

モデル パラメータ数 推論速度 精度 用途
yolov8n.pt 3.2M 最速 良好 リアルタイム処理
yolov8s.pt 11.2M 速い 高い バランス型
yolov8m.pt 25.9M 中程度 非常に高い 高精度が必要な場合
yolov8l.pt 43.7M やや遅い 最高 オフライン処理

本プロジェクトではリアルタイム性を重視し、yolov8n.pt(Nano) を採用しました。

技術的な実装ポイント

1. 頭部領域の計算

YOLOv8 は人物全体のバウンディングボックスを返すため、頭部領域を計算する必要があります:

# 人物検出結果から頭部を計算
person_h = y2 - y1
head_h = int(person_h * HEAD_HEIGHT_RATIO)  # 上部25%

# マージンを追加(より確実にカバー)
margin_w = int(head_w * 0.1)
margin_h = int(head_h * 0.1)

head_x = max(0, head_x - margin_w)
head_y = max(0, head_y - margin_h)
head_w = min(OUTPUT_WIDTH - head_x, head_w + margin_w * 2)
head_h = min(OUTPUT_HEIGHT - head_y, head_h + margin_h * 2)

2. モザイク処理の最適化

def apply_mosaic(image, x, y, w, h, ratio=0.05):
    """
    効率的なモザイク処理

    Args:
        ratio: 小さいほど粗いモザイク(0.05推奨)
    """
    # 境界チェック
    x = max(0, x)
    y = max(0, y)
    w = min(w, image.shape[1] - x)
    h = min(h, image.shape[0] - y)

    # 領域抽出
    face_img = image[y:y+h, x:x+w]

    # 縮小→拡大でモザイク効果
    small = cv2.resize(face_img, None, fx=ratio, fy=ratio,
                      interpolation=cv2.INTER_NEAREST)
    mosaic = cv2.resize(small, (w, h),
                       interpolation=cv2.INTER_NEAREST)

    # 適用
    image[y:y+h, x:x+w] = mosaic
    return image

3. FFmpeg によるストリーミング配信

検出・モザイク処理後の映像を UDP 経由でストリーミング配信:

ffmpeg_cmd = [
    'ffmpeg',
    '-y',
    '-f', 'rawvideo',
    '-vcodec', 'rawvideo',
    '-pix_fmt', 'bgr24',
    '-s', f'{OUTPUT_WIDTH}x{OUTPUT_HEIGHT}',
    '-r', str(FPS),
    '-i', '-',              # 標準入力から読み込み
    '-f', 'mpegts',
    '-codec:v', 'mpeg1video',
    '-b:v', '2000k',
    '-bf', '0',
    OUTPUT_URL,             # udp://127.0.0.1:8080
]

ffmpeg_process = subprocess.Popen(
    ffmpeg_cmd,
    stdin=subprocess.PIPE,
    stderr=subprocess.PIPE
)

# フレームを送信
ffmpeg_process.stdin.write(frame.tobytes())

VLC での視聴:

vlc udp://@127.0.0.1:8080

GPU 活用による高速化

YOLOv8 は GPU をサポートしており、CUDA が利用可能な環境では大幅な高速化が可能です:

# PyTorch with CUDA
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# Ultralytics
pip install ultralytics

実測パフォーマンス

実際の環境で測定した結果(1280x720、YOLOv8n モデル):

デバイス 平均 FPS 最小 FPS 最大 FPS 処理時間 備考
AMD Ryzen 9 9950X (CPU) 81.6 56.3 92.5 12.5 ms 16 コア/32 スレッド
NVIDIA RTX 4080 Super (GPU) 110.5 28.9 211.8 11.8 ms VRAM: 16GB、GPU 利用率: 17%

パフォーマンスの考察

CPU・GPU いずれの環境でも十分な性能を確認できました。
特に CPU(Ryzen 9 9950X)でも 80 FPS を超える実用的な速度が得られ、GPU を使用しなくても多くの用途で十分に対応可能です。

CUDA 環境のセットアップ

GPU を利用するには、CUDA 対応の PyTorch をインストールする必要があります。

クイックセットアップ

# 既存の PyTorch をアンインストール
pip uninstall torch torchvision torchaudio -y

# CUDA 11.8 版をインストール
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# 確認
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"

詳細な手順

  1. GPU ドライバーの確認

    nvidia-smi
    

    NVIDIA GPU が認識されていることを確認します。

  2. CUDA 診断

    プロジェクトに含まれる診断スクリプトで環境を確認:

    python check_cuda.py
    
  3. ベンチマーク実行

    GPU 環境が整ったら、以下のコマンドでパフォーマンスを測定:

    python benchmark-yolov8.py "rtsp://your-camera-url" --device cuda
    

詳細なセットアップ手順やトラブルシューティングは、プロジェクトの CUDA_SETUP.md を参照してください

実装上の注意点

1. メモリ管理

YOLOv8 モデルは比較的大きなメモリを使用します:

  • yolov8n.pt: 約 6MB(推論時は約 500MB RAM)
  • yolov8s.pt: 約 22MB(推論時は約 1GB RAM)

長時間稼働時はメモリリークに注意が必要です。

2. 信頼度閾値の調整

CONFIDENCE_THRESHOLD = 0.5  # デフォルト

# 誤検知を減らしたい場合
CONFIDENCE_THRESHOLD = 0.6  # より厳格

# 検出漏れを減らしたい場合
CONFIDENCE_THRESHOLD = 0.4  # より緩和

3. プロセスの適切な終了処理

FFmpeg プロセスが残留しないよう、確実な終了処理を実装:

finally:
    cap.release()
    cv2.destroyAllWindows()

    if ffmpeg_process:
        try:
            ffmpeg_process.stdin.close()
            ffmpeg_process.terminate()
            ffmpeg_process.wait(timeout=3)
        except subprocess.TimeoutExpired:
            ffmpeg_process.kill()
            ffmpeg_process.wait()

まとめ

監視カメラ映像のリアルタイム顔モザイク処理において、従来の Haar Cascade + HOG から YOLOv8 に移行することで、以下の成果を達成しました:

  1. 検出精度: 60-70% → 90-95%
  2. 誤検知: 大幅に削減
  3. 実装の複雑さ: 複雑 → シンプル
  4. 保守性: 困難 → 容易

YOLOv8 はやや処理が重くなるものの、GPU の活用により実用的なフレームレートを維持できます。プライバシー保護が重要な監視システムにおいて、ディープラーニングベースの検出手法は従来手法を大きく上回る性能を発揮することが実証されました。

最終的な推奨事項

  • プロトタイプ開発: Haar Cascade + HOG で素早く実装
  • 本番環境: YOLOv8 で高精度を確保
  • リソース制約が厳しい環境: パラメータ調整した Haar Cascade も選択肢
  • 高精度が必須: YOLOv8(Medium モデル以上)+ GPU 環境

実装コードの使用方法

本記事で紹介した技術を実際に試すことができるサンプルコードを用意しました。コマンドライン引数で柔軟に設定を変更できるため、様々な環境で簡単に動作確認できます。

従来手法版(Haar Cascade + HOG)

# 基本的な使用方法
python face-mosaic.py "rtsp://admin:password@192.168.1.100:554/stream"

# パラメータをカスタマイズ
python face-mosaic.py "rtsp://camera/stream" \
    --output udp://127.0.0.1:9000 \
    --width 1920 \
    --height 1080 \
    --fps 30 \
    --confidence 10 \
    --min-size 60

# プレビューなしで実行
python face-mosaic.py "rtsp://camera/stream" --no-preview

利用可能なオプション:

  • --output, -o: 出力ストリーム URL(デフォルト: udp://127.0.0.1:8080)
  • --width, -W: 出力映像の幅(デフォルト: 1280)
  • --height, -H: 出力映像の高さ(デフォルト: 720)
  • --fps, -f: フレームレート(デフォルト: 25)
  • --confidence, -c: 検出信頼度 minNeighbors(デフォルト: 8)
  • --min-size, -m: 最小検出サイズ(デフォルト: 50)
  • --no-preview: プレビューウィンドウを表示しない

YOLOv8 版

# 基本的な使用方法(Nanoモデル)
python face-mosaic-yolov8.py "rtsp://admin:password@192.168.1.100:554/stream"

# より高精度なモデルを使用
python face-mosaic-yolov8.py "rtsp://camera/stream" \
    --model yolov8s.pt \
    --confidence 0.6 \
    --head-ratio 0.3

# 高解像度で処理
python face-mosaic-yolov8.py "rtsp://camera/stream" \
    --width 1920 \
    --height 1080 \
    --fps 30 \
    --output udp://127.0.0.1:9000

利用可能なオプション:

  • --output, -o: 出力ストリーム URL(デフォルト: udp://127.0.0.1:8080)
  • --width, -W: 出力映像の幅(デフォルト: 1280)
  • --height, -H: 出力映像の高さ(デフォルト: 720)
  • --fps, -f: フレームレート(デフォルト: 25)
  • --model, -m: YOLOv8 モデル(yolov8n.pt, yolov8s.pt, yolov8m.pt, yolov8l.pt)
  • --confidence, -c: 検出信頼度閾値 0.0-1.0(デフォルト: 0.5)
  • --head-ratio, -r: 頭部領域の割合 0.1-0.5(デフォルト: 0.25)
  • --no-preview: プレビューウィンドウを表示しない

VLC での視聴

ストリーミング出力を VLC メディアプレイヤーで視聴:

# デフォルトの出力先の場合
vlc udp://@127.0.0.1:8080

# カスタム出力先の場合
vlc udp://@127.0.0.1:9000

参考情報

サンプルコード

本記事で紹介した実装のサンプルコードは以下のファイルで提供しています:

  • 従来手法版: face-mosaic.py

    • Haar Cascade + HOG による実装
    • コマンドライン引数で柔軟に設定変更可能
    • 技術検証や比較用途に最適
  • YOLOv8 版: face-mosaic-yolov8.py

    • YOLOv8 による高精度実装
    • 複数のモデルサイズから選択可能
    • 本番環境での使用に推奨
  • YouTube Live 配信対応版: face-mosaic-youtube.py

    • YOLOv8 + YouTube Live 配信機能
    • RTMP ストリーミングで YouTube に直接配信
    • 詳細な使用方法は README_YOUTUBE.md を参照
    • 使用例: python face-mosaic-youtube.py "rtsp://camera" --youtube-key YOUR_STREAM_KEY

関連技術

インストール方法

# 従来版の依存パッケージ
pip install opencv-python numpy

# YOLOv8版の依存パッケージ
pip install opencv-python numpy ultralytics

# GPU環境(オプション、YOLOv8の高速化)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

SNSでシェアしよう

この記事が役に立ったら、ぜひシェアしてください