どこにでもいる30代SEの学習ブログ

主にプログラミング関連の学習内容。読んだ本の感想や株式投資についても書いてます。

【Python】OpenCVで顔検出

OpenCVはインストールも簡単で、ひとまず顔検出を試すにはもってこいです。

正面以外の検出精度は微妙ですが、正面の顔を検出するなら十分です。短時間かつ低精度で構わないの場面で用いるのが良いでしょう。

f:id:predora005:20210808094547j:plain

[1] OpenCVのインストール

pip3 install opencv-python --user

上記だけではインポートエラーが発生するため「mesa-libGL」をインストールします。

sudo yum -y install mesa-libGL

詳しくは以下の記事にまとめています。

predora005.hatenablog.com

[2] ソースコード

公式のDocumentationを元に作成しました。

OpenCV: Cascade Classifier

公式の例ではカメラから画像を取り込んでいますが、ここではダウンロード済みの画像を扱う例を紹介します。

import cv2
import os

# サンプルデータのパスを追加
homedir = os.path.expanduser('~')
cv2dir = '.local/lib/python3.7/site-packages/cv2/'
cv2path = os.path.join(homedir, cv2dir)
cv2.samples.addSamplesDataSearchPath(cv2path)

# サンプル分類器を取得
face_cascade_name = 'data/haarcascade_frontalface_alt.xml'
eyes_cascade_name = 'data/haarcascade_eye_tree_eyeglasses.xml'
face_cascade = cv2.CascadeClassifier()
eyes_cascade = cv2.CascadeClassifier()
face_cascade.load(cv2.samples.findFile(face_cascade_name))
eyes_cascade.load(cv2.samples.findFile(eyes_cascade_name))

# 画像を読み込み(imgディレクトリにsample.jpgを置く)
imgdir = 'img'
imgpath = os.path.join(imgdir, 'sample.jpg')
img = cv2.imread(imgpath)

# 画像をグレースケールに変換
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 顔検出
faces = face_cascade.detectMultiScale(img_gray)
for face in faces:

    # 顔検出した領域を赤枠で描画
    xf, yf, wf, hf = face
    cv2.rectangle(img, (xf, yf), (xf+wf, yf+hf), color=(0,0,255), thickness=4)
    
    # 顔検出した領域から、目を検出
    face_img = img[yf:yf+hf, xf:xf+wf]
    eyes = eyes_cascade.detectMultiScale(face_img)
    for eye in eyes:

        # 目を検出した領域を緑楕円で描画
        xe, ye, we, he = eye
        eye_center = (xf + xe + we//2, yf + ye + he//2)
        cv2.ellipse(img, eye_center, axes=(we//2, he//2), 
                    angle=0, startAngle=0, endAngle=360, 
                    color=(0, 255, 0), thickness=4)

# 検出領域を示した画像を表示
cv2.imshow('Capture - Face detection', img)

[3] 顔検出の結果

[3-1] 非常に上手くいった例

f:id:predora005:20210808094547j:plain

<ゆうせい モデルの紹介 - ぱくたそ>

赤枠が顔検出した領域緑枠が顔検出した領域内から目を検出した領域です。

これは非常に上手くいった例です。正面の顔であれば、このように高精度で検出してくれます。

[3-2] すこし微妙な例

f:id:predora005:20210808095514j:plain

<Werner HeiberによるPixabayからの画像>

6人中3人を顔検出できています。顔が正面以外の向きだと、検出精度が下がります。

[3-3] 上手くいかない例

f:id:predora005:20210808095621j:plain

<Sanu A SによるPixabayからの画像>

5人中1人しか顔検出できていません。顔が正面以外の向きだと、検出精度が下がります。

[4] 補足とトラブルシューティング

[4-1] 検出器の種類

検出器は、OpenCVで用意されたものを利用しています。

Amazon Linux2の環境では/home/{ユーザ名}/.local/lib/python3.7/site-packages/cv2/dataに格納されています。

顔検出以外にも様々な分類器が用意されています。

ls /home/{ユーザ名}/.local/lib/python3.7/site-packages/cv2/data
# haarcascade_eye_tree_eyeglasses.xml      haarcascade_licence_plate_rus_16stages.xml
# haarcascade_eye.xml                      haarcascade_lowerbody.xml
# haarcascade_frontalcatface_extended.xml  haarcascade_profileface.xml
# haarcascade_frontalcatface.xml           haarcascade_righteye_2splits.xml
# haarcascade_frontalface_alt2.xml         haarcascade_russian_plate_number.xml
# haarcascade_frontalface_alt_tree.xml     haarcascade_smile.xml
# haarcascade_frontalface_alt.xml          haarcascade_upperbody.xml
# haarcascade_frontalface_default.xml      __init__.py
# haarcascade_fullbody.xml                 __pycache__
# haarcascade_lefteye_2splits.xml

各ファイルの役割は下記サイトなど、いくつかのサイトがまとめてくれています。

【Python版OpenCV】Haar Cascadeで顔検出、アニメ顔検出、顔にモザイク処理 | 西住工房

[4-2] 検出器の読込失敗

用意された検出器を読み込もうとすると、ファイルが見つからないエラーが発生します。

face_cascade_name = 'data/haarcascade_frontalface_alt.xml'
face_cascade = cv.CascadeClassifier()
face_cascade.load(cv.samples.findFile(face_cascade_name))

# OpenCV(4.5.3) /tmp/pip-req-build-l1r0y34w/opencv/modules/core/src/utils/samples.cpp:64: error: (-2:Unspecified error) OpenCV samples: Can't find required data file: data/haarcascade_frontalface_alt.xml in function 'findFile'

cv2.samples.addSamplesDataSearchPath()で格納先のパスを検索するようにします。

import os

homedir = os.path.expanduser('~')
cv2dir = '.local/lib/python3.7/site-packages/cv2/'
cv2path = os.path.join(homedir, cvdir)

cv2.samples.addSamplesDataSearchPath(cv2path)

OpenCV: Utility functions for OpenCV samples

[4-3] 検出器のパラメータ

検出器のパラメータを調整すること精度を高めることができます。

CascadeClassifier.detectMultiScale()のパラメータを変更します。主なパラメータは次の通りです。

  • scaleFactor:各画像スケールにおいて、画像サイズをどれだけ縮小するかを指定するパラメータ。
  • minNeighbors:各候補の矩形が保持されるために必要な隣接数を指定するパラメータ。
  • minSize:可能なオブジェクトの最小サイズ.これよりも小さいオブジェクトは無視されます.

OpenCV: cv::CascadeClassifier Class Reference

詳細は以下のサイトなどが参考になります。

[4-4] 検出の仕組み

Haar特徴に基づくカスケード分類器で顔検出を行なっています。

公式のチュートリアルや以下のサイトが詳しいです。

終わりに

冒頭で述べた通り、OpenCVはインストールも比較的容易で簡単に顔検出ができました。しかし、精度は少々物足りません。

OpenCVよりも精度の良いライブラリを探してみることにします。

参考文献

画像の出典