YOLOv11-Face 顔検出(ソースコードと実行結果)

事前準備
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 transformers opencv-python numpy pillow
YOLOv11顔検出プログラム
概要
本プログラムは、カメラや動画ファイルから取得した映像フレームを解析し、顔の位置を特定してバウンディングボックスで表示する。検出の信頼度も算出し、閾値以上の検出結果のみを採用することで誤検出を抑制する。
主要技術
1. YOLOv11(You Only Look Once version 11)
物体検出アルゴリズムの最新版である。単一のニューラルネットワークで画像全体を一度に処理し、物体の位置とクラスを同時に予測する。C3k2ブロックとC2PSA注意機構の導入により、従来版と比較して少ないパラメータ数で検出を実現する [1]。本プログラムでは顔検出に特化したサードパーティのモデルを使用する。
参考文献
- [1] Jocher, G., Qiu, J., & Chaurasia, A. (2024). Ultralytics YOLO11. GitHub. https://github.com/ultralytics/ultralytics
ソースコード
# プログラム名: 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: リアルタイム物体検出、C3k2ブロックとC2PSA注意機構搭載、従来版より22%少ないパラメータで高精度検出を実現
# - OpenCV: 画像処理、カメラ制御、描画処理
# - 入力と出力: 入力: 動画(ユーザは「0:動画ファイル,1:カメラ,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.aviを使用)、出力: OpenCV画面でリアルタイム表示(検出した顔をバウンディングボックスで表示)、1秒間隔でprint()による処理結果表示、プログラム終了時にresult.txtファイルに保存
# - 処理手順: 1.YOLOv11で顔検出、2.検出結果の表示
# - 前処理、後処理: 前処理:バッファクリア処理(最新フレーム取得のためgrab()とretrieve()を分離)
# - 追加処理: 信頼度閾値によるフィルタリング処理(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
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
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)
# 表示設定
PRINT_INTERVAL = 1.0 # 結果出力間隔(秒)
# 顔の表示色(BGR形式)
FACE_COLOR = (0, 255, 0) # 緑(バウンディングボックス用)
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: {MODEL_URL}')
exit()
else:
print(f'YOLOv11{MODEL_SIZE}モデルが既に存在します: {MODEL_PATH}')
# プログラム概要表示
print('=== YOLOv11顔検出プログラム ===')
print('概要: リアルタイムで顔を検出し、バウンディングボックスで表示します')
print('機能: YOLOv11による顔検出')
print('操作: qキーで終了')
print('出力: 1秒間隔での処理結果表示、終了時に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_str = 'cuda' if torch.cuda.is_available() else 'cpu'
print(f'{device_str.upper()}使用モード')
print('初期化完了')
print()
# グローバル変数
frame_count = 0
last_print_time = time.time()
results_log = []
def extract_face_info(box):
"""顔情報の抽出"""
x1, y1, x2, y2 = map(int, box)
return {
'box': (x1, y1, x2, y2)
}
def video_processing(frame):
"""フレーム処理メイン関数"""
global frame_count, last_print_time, results_log
frame_count += 1
# 顔検出実行(デバイス指定)
results = face_model(frame, device=device_str, 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)
# 1秒間隔での出力
current_time = time.time()
if current_time - last_print_time >= PRINT_INTERVAL and faces:
output = f'フレーム {frame_count}: {len(faces)}顔検出'
for i, f in enumerate(faces):
output += f" | 顔{i+1}: 信頼度{f['detection_conf']:.0%}"
print(output)
results_log.append(output)
last_print_time = current_time
# 描画処理
for i, f in enumerate(faces):
x1, y1, x2, y2 = f['box']
color = FACE_COLOR
# バウンディングボックス
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
# ラベル表示
label1 = f'Face {i+1}'
label2 = f"Conf:{f['detection_conf']:.1%}"
cv2.putText(frame, label1, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
cv2.putText(frame, label2, (x1, y2+15), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1)
# システム情報表示
info1 = f'YOLOv11 | Frame: {frame_count} | Faces: {len(faces)}'
info2 = 'Press: q=Quit'
cv2.putText(frame, info1, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.putText(frame, info2, (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 1)
return frame
# 入力選択
print('0: 動画ファイル')
print('1: カメラ')
print('2: サンプル動画')
choice = input('選択: ')
temp_file = None
if choice == '0':
root = tk.Tk()
root.withdraw()
path = filedialog.askopenfilename()
if not path:
exit()
cap = cv2.VideoCapture(path)
elif choice == '1':
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WINDOW_WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, WINDOW_HEIGHT)
cap.set(cv2.CAP_PROP_FPS, FPS)
elif choice == '2':
# サンプル動画ダウンロード・処理
try:
urllib.request.urlretrieve(SAMPLE_VIDEO_URL, SAMPLE_VIDEO_NAME)
temp_file = SAMPLE_VIDEO_NAME
cap = cv2.VideoCapture(SAMPLE_VIDEO_NAME)
print('サンプル動画のダウンロードが完了しました')
except Exception as e:
print(f'動画のダウンロードに失敗しました: {SAMPLE_VIDEO_URL}')
print(f'エラー: {e}')
exit()
else:
print('無効な選択です')
exit()
# 動画処理開始メッセージ
print('\n=== 動画処理開始 ===')
print('操作方法:')
print(' q キー: プログラム終了')
print()
# メイン処理
try:
while True:
cap.grab()
ret, frame = cap.retrieve()
if not ret:
break
processed_frame = video_processing(frame)
cv2.imshow('YOLOv11 Face Detection', processed_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
finally:
cap.release()
cv2.destroyAllWindows()
# 結果保存
if results_log:
with open(RESULT_FILE, 'w', encoding='utf-8') as f:
f.write('=== YOLOv11顔検出結果 ===\n')
f.write(f'処理フレーム数: {frame_count}\n\n')
f.write('\n'.join(results_log))
print(f'\n処理結果を{RESULT_FILE}に保存しました')
if temp_file and os.path.exists(temp_file):
os.remove(temp_file)
print('\n=== プログラム終了 ===')