ベイジアン研究所

プログラミング言語(アルゴリズム的な話が中心)やガジェットの紹介をしています。時々心理学の話も。

【opencv-python】顔検出ができない時の対処法

1. 記事の目的
参考文献[1]のHaar Cascadeを使った顔検出において上手く顔が検出されなかった際の対処法を紹介する。

2. 実行確認済み環境
Mac OS Catalina 10.15.7
Python 3.8.5
opencv-python 4.4.0.46
numpy 1.19.1

3.入力画像
次の画像を"sachin.png"と言う名前で以下の実装コードと同じフォルダに配置する(やる気を出すために美女を選ぶ)。

f:id:camelsan:20201230165037j:plain
図1 入力画像
3. 実装コードと実行方法
図1を保存した上で、次の二つのファイルを図1と同じ場所に保存する。

  • haarcascade_frontalface_default.xml

  • haarcascade_eye.xml

これらは参考文献[2]の場所から手に入る。

実装コードを記す。

import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('./haarcascade_eye.xml')

img = cv2.imread('./sachin.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray,1.3,5)
for (x,y,w,h) in faces:
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    roi_gray = gray[y:y+h,x:x+h]
    roi_color = img[y:y+h,x:x+h]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex,ey,ew,eh) in eyes:
        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

pythonファイルを"cascade.py"と言う名前にした場合、次のコマンドで実行が可能である。

python3 cascade.py

4. 実行結果
顔が検出された画像が表示されるはずだが、本環境では、入力画像と全く同じ以下の画像が表示されてしまう。

f:id:camelsan:20201230165037j:plain
図2 実行結果(失敗)

5. 対処法
上記実装コードの、10行目に次のようなコードがある。

faces = face_cascade.detectMultiScale(gray,1.3,5)

detectMultiScale関数の第2引数と第3引数を次のように変更すると顔を検出できるようになった。

# 第2引数を1.3から1.21に、第3引数を5から3に変更。
faces = face_cascade.detectMultiScale(gray,1.21,3)

これらの引数は次のような意味がある(参考文献[3]参照)。

  • 第2引数:検出を行う四角形の縮小率(1より大きい数で指定する必要がある。)数が小さいほど細かく検出するので、見落としが少なくなるが、処理時間が多くなる。

  • 第3引数:様々なスケールで検出した結果、同じエリアで重複して検出される。その時いくつ重複した場合に真とみなすかを定義するのがこの引数。小さいと少ない領域が重なっても検出するので、見落としは少ないが誤検出が多くなる。

以上のような意味を考えながら、微調整を行うと上手く対処できると考えられる(画像に対して顔の領域が少ないときは、見落としがないように、これらの引数を小さめにすると良いと思われる。)

6.対処後の結果
対処後の結果を実装コードとともに示す。まずは、実装コードから示す。

import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('./haarcascade_eye.xml')

img = cv2.imread('./sachin.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 次の一行を変更した。
faces = face_cascade.detectMultiScale(gray,1.21,3)
for (x,y,w,h) in faces:
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    roi_gray = gray[y:y+h,x:x+h]
    roi_color = img[y:y+h,x:x+h]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex,ey,ew,eh) in eyes:
        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

実行結果としては、次の画像が出力される。

f:id:camelsan:20201230171759j:plain
図3 実行結果(成功)
これでも、一部誤った検出をしており(図3下部)、より微調整を行う必要があると思われる。

7. 参考文献
[1] OpenCV-Pythonチュートリアル
k近傍法を使った手書き文字認識 — OpenCV-Python Tutorials 1 documentation
[2] OpenCV github
opencv/data/haarcascades at master · opencv/opencv · GitHub
[3] Python, OpenCVで顔検出と瞳検出(顔認識、瞳認識)
Python, OpenCVで顔検出と瞳検出(顔認識、瞳認識) | note.nkmk.me