YOLOv11-Face 顔検出(ソースコードと実行結果)
ツール利用ガイド
1. このプログラムの利用シーン
動画ファイルやウェブカメラからリアルタイムで顔を検出するソフトウェアである。セキュリティシステム、来場者カウント、動画解析、プライバシー保護システムの構築において利用できる。初回実行時にYOLOv11学習済みモデルを自動ダウンロードし、即座に検出作業を開始できる。
2. 主な機能
- リアルタイム顔検出:動画フレーム内の顔を緑色のバウンディングボックスで表示する
- 多様な入力対応:動画ファイル選択、ウェブカメラ入力、サンプル動画の3つの入力方式に対応する
- 信頼度フィルタリング:検出閾値を設定することで誤検出を抑制する
- 画像前処理:CLAHE処理により暗部領域での検出性能を改善する
- 検出結果保存:全フレームの検出結果をテキストファイルに記録する
3. 基本的な使い方
- プログラム起動:必要なライブラリをインストール後、プログラムを実行する
- 入力源選択:「0:動画ファイル」「1:カメラ」「2:サンプル動画」から選択する
- 検出開始:選択した入力源から顔検出が自動的に開始される
- 終了操作:キーボードのqキーまたはESCキーでプログラムを終了する
4. 便利な機能
- 自動モデル管理:初回実行時にYOLOv11モデルを自動ダウンロードし、Documents フォルダに保存する
- GPU自動検出:CUDA対応GPUが利用可能な場合は自動的にGPU処理に切り替わる
- 検出情報表示:フレームごとに検出した顔の数と信頼度をコンソールに出力する
- 日本語表示対応:検出結果の表示において日本語フォントを使用する
事前準備
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
)
必要なライブラリのインストール
コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する:
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126 pip install ultralytics opencv-python numpy pillow
YOLOv11顔検出プログラム
概要
このプログラムは、YOLOv11アルゴリズムを使用してカメラや動画ファイルから顔をリアルタイムで検出するシステムである。検出された顔は緑色のバウンディングボックスで表示され、信頼度閾値による誤検出抑制機能を備える。動画ファイル、ウェブカメラ、サンプル動画の3つの入力源に対応し、検出結果をログファイルとして保存する機能を持つ。
主要技術
YOLOv11(You Only Look Once version 11)
物体検出アルゴリズムの最新版である。単一のニューラルネットワークで画像全体を処理し、物体の位置とクラスを同時に予測する[1]。従来のR-CNNベースの二段階検出手法と比較して、リアルタイム処理に適した一段階検出を実現する。
C2PSA(Convolutional block with Parallel Spatial Attention)
並列空間注意機構を備えた畳み込みブロックである[1]。画像内の重要な領域に選択的に注意を向けることで、小さな物体や部分的に隠れた物体の検出精度を向上させる。
技術的特徴
- 空間注意機構:C2PSAブロックにより画像内の重要領域に集中し、検出精度を向上させる[1]
- マルチスケール特徴融合:SPPFブロックによる空間ピラミッドプーリングで異なるスケールの特徴を統合する[1]
- CLAHE前処理:適応的ヒストグラム均等化により画像の局所的なコントラストを改善する[2]
実装の特色
動画のリアルタイム処理に対応し、以下の機能を備える:
- 多様な入力源対応:動画ファイル、ウェブカメラ、サンプル動画の3つの入力方式をサポートする
- 信頼度フィルタリング:設定可能な閾値(デフォルト0.5)により誤検出を抑制する
- 前処理機能:CLAHE処理により暗部領域での検出性能を改善する
- 処理結果の保存:検出結果をテキストファイルとして自動保存する
参考文献
[1] Khanam, R., & Hussain, M. (2024). YOLOv11: An Overview of the Key Architectural Enhancements. arXiv preprint arXiv:2410.17725. https://arxiv.org/abs/2410.17725
[2] PyImageSearch. (2021). OpenCV Histogram Equalization and Adaptive Histogram Equalization (CLAHE). https://pyimagesearch.com/2021/02/01/opencv-histogram-equalization-and-adaptive-histogram-equalization-clahe/
ソースコード
# プログラム名: YOLOv11顔検出プログラム
# 特徴技術名: YOLOv11
# 出典: Ultralytics YOLOv11
# 特徴機能: リアルタイム顔検出。顔のバウンディングボックスを検出
# 学習済みモデル: YOLOv11顔検出用モデル
# モデルサイズ選択可能(デフォルト:n):
# n (nano): https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11n-face.pt
# s (small): https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11s-face.pt
# m (medium): https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11m-face.pt
# l (large): https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11l-face.pt
# 方式設計:
# - 関連利用技術:
# - YOLOv11: リアルタイム物体検出、C2kブロックとC2PSA(Partial Self-Attention)モジュール搭載
# - OpenCV: 画像処理、カメラ制御、描画処理
# - Pillow: 日本語テキスト描画
# - 入力と出力: 入力: 動画(ユーザは「0:動画ファイル,1:カメラ,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.aviを使用)、出力: OpenCV画面でリアルタイム表示(検出した顔をバウンディングボックスで表示)、各フレームごとにprint()による処理結果を表示(検出0件時も含む)、プログラム終了時にresult.txtファイルを作成して保存
# - 処理手順: 1.YOLOv11で顔検出、2.検出結果の表示
# - 前処理、後処理: 前処理:カメラ使用時のバッファサイズ設定
# - 追加処理: 信頼度閾値によるフィルタリング処理(FACE_CONFIDENCE_THRESHOLD以上の検出結果のみ採用)
# - 調整を必要とする設定値: FACE_CONFIDENCE_THRESHOLD(顔検出閾値、デフォルト0.5)、MODEL_SIZE(YOLOモデルサイズ、デフォルト'n'、選択可能:'n', 's', 'm', 'l')
# 将来方策: FACE_CONFIDENCE_THRESHOLDの自動調整機能。フレーム内の顔検出数が極端に多い/少ない場合に閾値を動的に調整し、適切な検出数を維持する機能の実装
# その他の重要事項: Windows環境専用、CUDA対応GPU推奨、初回実行時は学習済みモデルのダウンロードに時間がかかる
# 前準備:
# - 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 torch
import numpy as np
from ultralytics import YOLO
import warnings
import time
import urllib.request
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime
warnings.filterwarnings('ignore')
# ===== 設定・定数管理 =====
# YOLOv11モデル設定(デフォルト:n、変更可能:n, s, m, l)
MODEL_SIZE = 'n' # 使用するモデルサイズ(n=nano, s=small, m=medium, l=large)
MODEL_PATH = os.path.join(os.path.expanduser('~'), 'Documents', f'yolov11{MODEL_SIZE}-face.pt')
MODEL_URL = f'https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11{MODEL_SIZE}-face.pt'
SAMPLE_VIDEO_URL = 'https://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.avi'
SAMPLE_VIDEO_NAME = 'vtest.avi'
RESULT_FILE = 'result.txt'
# カメラ設定
WINDOW_WIDTH = 1280 # カメラ解像度幅
WINDOW_HEIGHT = 720 # カメラ解像度高さ
FPS = 30 # フレームレート
# 検出パラメータ(調整可能)
FACE_CONFIDENCE_THRESHOLD = 0.5 # 顔検出信頼度閾値(0.0-1.0)
# 顔の表示色(BGR形式)
FACE_COLOR = (0, 255, 0) # 緑(バウンディングボックス用)
# 日本語フォント設定
FONT_PATH = 'C:/Windows/Fonts/meiryo.ttc'
FONT_SIZE_LARGE = 24
FONT_SIZE_MEDIUM = 20
FONT_SIZE_SMALL = 16
def download_yolo_model():
"""YOLOv11モデルダウンロード処理"""
if not os.path.exists(MODEL_PATH):
print(f'YOLOv11{MODEL_SIZE}モデルをダウンロードしています...')
print(f'モデルサイズ: {MODEL_SIZE} (nano=最軽量, small=軽量, medium=中程度, large=高精度)')
try:
os.makedirs(os.path.dirname(MODEL_PATH), exist_ok=True)
urllib.request.urlretrieve(MODEL_URL, MODEL_PATH)
print(f'YOLOv11{MODEL_SIZE}モデルのダウンロードが完了しました')
except Exception as e:
print(f'YOLOv11{MODEL_SIZE}モデルのダウンロードに失敗しました')
print(f'エラー: {e}')
print(f'URL: {URL}')
exit()
else:
print(f'YOLOv11{MODEL_SIZE}モデルが既に存在します: {MODEL_PATH}')
def draw_japanese_text(img, text, position, font_size, color):
"""日本語テキストを画像に描画"""
try:
font = ImageFont.truetype(FONT_PATH, font_size)
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
draw.text(position, text, font=font, fill=color[::-1]) # BGRからRGBに変換
return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
except:
# フォントが見つからない場合は英語で表示
cv2.putText(img, text, position, cv2.FONT_HERSHEY_SIMPLEX, font_size/30, color, 2)
return img
def extract_face_info(box):
"""顔情報の抽出"""
x1, y1, x2, y2 = map(int, box)
return {
'box': (x1, y1, x2, y2)
}
# プログラム概要表示
print('=== YOLOv11顔検出プログラム ===')
print('【概要説明】')
print(' 本プログラムは、YOLOv11を使用してリアルタイムで顔検出を行います。')
print(' 検出された顔は緑色のバウンディングボックスで表示されます。')
print()
print('【操作方法】')
print(' 1. 起動時に入力ソースを選択(0:動画ファイル, 1:カメラ, 2:サンプル動画)')
print(' 2. 検出画面表示中:')
print(' - qキー: プログラム終了')
print(' - ESCキー: 緊急終了')
print()
print('【注意事項】')
print(' - 初回実行時はモデルのダウンロードに時間がかかります(約100-500MB)')
print(' - GPU使用時は処理速度が向上します')
print(' - カメラ使用時はプライバシーに慮してください')
print()
print('【出力ファイル】')
print(' - result.txt: 検出結果のログファイル(プログラム終了時に自動保存)')
print()
# システム初期化
print('システム初期化中...')
start_time = time.time()
# YOLOv11モデルダウンロード
download_yolo_model()
# YOLOv11モデル初期化
try:
face_model = YOLO(MODEL_PATH)
print(f'YOLOv11{MODEL_SIZE}モデルの初期化が完了しました')
except Exception as e:
print(f'YOLOv11{MODEL_SIZE}モデルの初期化に失敗しました')
print(f'エラー: {e}')
exit()
# 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
# CLAHEオブジェクトを一度だけ生成
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
print('初期化完了')
print()
# グローバル変数
frame_count = 0
results_log = []
cap = None # capを初期化
def video_frame_processing(frame):
"""フレーム処理メイン関数"""
global frame_count
current_time = time.time()
frame_count += 1
# ===== CLAHE処理を追加 =====
# 1. BGRからYUVカラー空間に変換
yuv_img = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV)
# 2. 明度チャンネル(Y)にCLAHEを適用
yuv_img[:,:,0] = clahe.apply(yuv_img[:,:,0])
# 3. BGRカラー空間に再変換
clahe_frame = cv2.cvtColor(yuv_img, cv2.COLOR_YUV2BGR)
# ==========================
# 顔検出実行(デバイス指定) - 入力画像をCLAHE適用後のフレームに変更
results = face_model(clahe_frame, device=device, verbose=False)
faces = []
if results[0].boxes is not None:
boxes = results[0].boxes.xyxy.cpu().numpy()
confs = results[0].boxes.conf.cpu().numpy()
# 信頼度でソート(降順)
if len(boxes) > 0:
sorted_indices = np.argsort(confs)[::-1]
boxes = boxes[sorted_indices]
confs = confs[sorted_indices]
# 各顔の処理
for i, (box, conf) in enumerate(zip(boxes, confs)):
if conf >= FACE_CONFIDENCE_THRESHOLD: # 以上(>=)
face_data = extract_face_info(box)
if face_data:
face_data['detection_conf'] = conf
faces.append(face_data)
# 結果文字列の作成
result = f'{len(faces)}顔検出'
for i, f in enumerate(faces):
result += f" | 顔{i+1}: 信頼度{f['detection_conf']:.0%}"
# 描画処理 (描画対象は元の'frame'のまま)
processed_frame = frame.copy() # 元のフレームをコピーして描画する
for i, f in enumerate(faces):
x1, y1, x2, y2 = f['box']
color = FACE_COLOR
# バウンディングボックス
cv2.rectangle(processed_frame, (x1, y1), (x2, y2), color, 2)
# ラベル表示(日本語)
label1 = f'顔 {i+1}'
label2 = f"信頼度:{f['detection_conf']:.1%}"
processed_frame = draw_japanese_text(processed_frame, label1, (x1, y1-10), FONT_SIZE_MEDIUM, color)
processed_frame = draw_japanese_text(processed_frame, label2, (x1, y2+15), FONT_SIZE_SMALL, (255, 255, 255))
# システム情報表示(日本語)
info1 = f'YOLOv11 | フレーム: {frame_count} | 検出顔数: {len(faces)}'
info2 = '操作: q=終了, ESC=緊急終了'
processed_frame = draw_japanese_text(processed_frame, info1, (10, 30), FONT_SIZE_MEDIUM, (255, 255, 255))
processed_frame = draw_japanese_text(processed_frame, info2, (10, 60), FONT_SIZE_SMALL, (255, 255, 0))
return processed_frame, result, current_time # 描画済みのフレームを返す
# 入力選択
print('入力ソースを選択してください:')
print('0: 動画ファイル')
print('1: カメラ')
print('2: サンプル動画')
choice = input('選択: ')
if choice == '0':
root = tk.Tk()
root.withdraw()
path = filedialog.askopenfilename()
if path:
cap = cv2.VideoCapture(path)
elif choice == '1':
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
if not cap.isOpened():
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
elif choice == '2':
# サンプル動画ダウンロード・処理
urllib.request.urlretrieve(SAMPLE_VIDEO_URL, SAMPLE_VIDEO_NAME)
cap = cv2.VideoCapture(SAMPLE_VIDEO_NAME)
if not cap or not cap.isOpened():
print('動画ファイル・カメラを開けませんでした')
exit()
# メイン処理
print('\n=== 動画処理開始 ===')
print('操作方法:')
print(' q キー: プログラム終了')
try:
while True:
ret, frame = cap.read()
if not ret:
break
MAIN_FUNC_DESC = "YOLOv11顔検出"
processed_frame, result, current_time = video_frame_processing(frame)
cv2.imshow(MAIN_FUNC_DESC, processed_frame)
if choice == '1': # カメラの場合
print(datetime.fromtimestamp(current_time).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3], result)
else: # 動画ファイルの場合
print(frame_count, result)
results_log.append(result)
key = cv2.waitKey(1) & 0xFF
if key == ord('q') or key == 27: # 27はESCキー
break
finally:
print('\n=== プログラム終了 ===')
if cap:
cap.release()
cv2.destroyAllWindows()
if results_log:
with open(RESULT_FILE, 'w', encoding='utf-8') as f:
f.write('=== 結果 ===\n')
f.write(f'処理フレーム数: {frame_count}\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('\n')
f.write('\n'.join(results_log))
print(f'\n処理結果を{RESULT_FILE}に保存しました')