【Python】簡単にリアルタイム顔認識をする！

## はじめに

Pythonのライブラリ、cv2を使ってリアルタイム顔認識を作ることができます。
Pythonでリアルタイム顔認識をしてみたい！という方に読んでいただきたいです。

## 実行環境

- Python 3.11
- Windows 10

### 使用ライブラリ

#### 標準ライブラリ

- os

#### 外部ライブラリ

- cv2
画像処理のライブラリです。
ver
- face_recognition
顔検出と顔認識のライブラリです。
- numpy
数値データの処理などのライブラリです。
- tqdm
プログレスバーのライブラリです。

## ライブラリのインストール

今回のプログラムでは「cv2」「face_recognition」「numpy」「tqdm」と5つの外部ライブラリを使用します。以下のコマンドでインストールしましょう。どちらのコマンドを使っても大丈夫です。

```:ライブラリのインストール
pip install opencv-python
pip install face_recognition
pip install numpy
pip install tqdm

又は

pip install opencv-python face_recognition numpy tqdm
```

## 実装の準備

まず、適当な名前のフォルダを作ってPythonのプログラムを記述するface.pyを作成します。次にimagesという名前のフォルダを作成してください。最後にimagesフォルダの配下に自分の名前のフォルダを作成して中に自分の顔写真を三枚ほど入れてください。

:::note info
顔認識時に、フォルダ名がそのまま人物名として表示されます。
:::

```:フォルダ構造
適当な名前のフォルダ
├──images
│   └──自分の名前
│       ├──自分の顔写真１
│       ├──自分の顔写真２
│       └──自分の顔写真３
└──face.py
```

```:フォルダ構造の例
facial_recognition
├──images
│   └──tanaka
│       ├──FacePhoto1
│       ├──FacePhoto2
│       └──FacePhoto3
└──face.py
```

## 実装

以下のコードをface.pyに貼り付けて実行することでリアルタイム顔認識をすることができます。
コードを実行すると画像の処理が始まります。進行状況はプログレスバーで表示されます。画像の処理が終わるとカメラの画面が表示され顔検出と顔認識が始まります。終了はqキーです。
face.py内7行目の変数`tolerance`の値が小さくほど顔認識が厳しくなり、精度は上がりますが、正しく認識されにくくなります。

```python:コード全文（face.py）
import cv2
import face_recognition
import numpy as np
import os
from tqdm import tqdm  # プログレスバー表示ライブラリ

tolerance = 0.4

# 画像フォルダのパス
image_folder = 'images/'

# 画像を読み込み、顔の特徴を記録する
known_face_encodings = []
known_face_names = []

# フォルダごとに画像を処理
folder_list = [folder for folder in os.listdir(image_folder) if os.path.isdir(os.path.join(image_folder, folder))]

# tqdm を使ってフォルダの処理状況を表示
for foldername in tqdm(folder_list, desc="Processing Folders"):
    folder_path = os.path.join(image_folder, foldername)
    
    # フォルダ内の画像ファイルを処理
    image_files = [f for f in os.listdir(folder_path) if f.endswith(".jpg")]
    
    # tqdm を使ってフォルダ内の画像ファイルの処理状況を表示
    for filename in tqdm(image_files, desc=f"Processing Images in {foldername}", leave=False):
        image_path = os.path.join(folder_path, filename)
        image = face_recognition.load_image_file(image_path)
        encoding = face_recognition.face_encodings(image)
        
        if encoding:
            # 複数の画像から同じ人物の特徴を追加
            known_face_encodings.append(encoding[0])
            known_face_names.append(foldername)  # フォルダ名を表示名として取得

print("All complete.")

# カメラを初期化
video_capture = cv2.VideoCapture(0)

process_this_frame = True

while True:
    ret, frame = video_capture.read()

    if process_this_frame:
        # ここで顔認識処理
        small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
        rgb_small_frame = np.ascontiguousarray(small_frame[:, :, ::-1])
        
        # 顔検出と顔認識
        face_locations = face_recognition.face_locations(rgb_small_frame)
        face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
        
        # 顔の座標を拡大して元のフレームに戻す
        face_locations = [(top * 4, right * 4, bottom * 4, left * 4) for (top, right, bottom, left) in face_locations]

    # 毎フレーム処理を行わないようにする
    process_this_frame = not process_this_frame
    
    # 各顔に対して認識
    for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
        matches = face_recognition.compare_faces(known_face_encodings, face_encoding, tolerance=tolerance) # 厳しくするならtoleranceを小さく
        name = "Unknown"
        
        # マッチした顔があれば名前を取得
        if True in matches:
            first_match_index = matches.index(True)
            name = known_face_names[first_match_index]
        
        # 顔の周りにボックスを描画
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom - 6), font, 0.5, (255, 255, 255), 1)
    
    # フレームを表示
    cv2.imshow('Video', frame)
    
    # 'q'キーが押されたらループを終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# カメラを解放し、ウィンドウを閉じる
video_capture.release()
cv2.destroyAllWindows()

```

## おわりに

今回はOpenCVとface_recognitionを使ってリアルタイム顔認識を実装してみました。
こちらの記事が顔検出や顔認識を実装する際の参考になれば嬉しいです。

## 追記

毎回顔データを処理すると時間がかかるため、処理時間を短縮できるようにファイルに保存する仕組みを作りました。
良ければご覧ください！

https://qiita.com/mikannohako/items/eb457ec55bc3522373f8

## 参考文献

> [Pythonで簡単に顔認識実装！ ~face-recognition~](https://engineer-koh.com/face-recognition/#toc8)
> [Face Recognition](https://github.com/ageitgey/face_recognition/blob/master/README_Japanese.md)
> [tqdmでプログレスバーを表示させる](https://qiita.com/pontyo4/items/76145cb10e030ad8186a)