【Python】OpenCVによる顔検出 (Haar Cascade)


はじめに

今回はOpenCVを用いて、顔か検出をやってみたいと思います。顔検出の手法は色々あるのですが、今回はHaar cascadeを用います。

環境

MacOS Mojave
Python 3.7

Haar Casecade?

顔っぽさを表す特徴量 (Haar特徴量) から、これは顔であるかないかを判断する分類器のことです。この分類器は、高速化の為に複数の分類器が結合してできていることから、Cascade (結合) 分類器と呼ばれます。Haar特徴量は以下のような白黒の特徴量が用いられます。

図. Haar特徴量
(画像引用元:http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_objdetect/py_face_detection/py_face_detection.html)

なんだこの白黒は、、、と思ったんじゃないでしょうか。少し人間の顔がどうなっているのかを考えてみましょう。

人間の顔って高度に抽象化すると、大体は以下のようになるのではないでしょうか (ならないか...w)

図. 高度に抽象化された顔

上図から、例えば目元は左から"黒白黒"の色の配置になっていると思いませんか。

図. 高度に抽象化された顔の白と黒の配置

この高度に抽象化された顔っぽい白と黒の配置を表したのがHaar特徴量です。
入力画像から任意の領域を切り出し、この特徴量がたくさん存在すれば、顔だと判断します。

図. 顔だと判断された画像 (目元など、Haar特徴量がたくさん存在する)
(画像引用元:http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_objdetect/py_face_detection/py_face_detection.html)

ここではざっくりとしたイメージの解説だけなので、詳細を知りたい方は以下の論文を読んでみてください。
https://www.cs.cmu.edu/~efros/courses/LBMV07/Papers/viola-cvpr-01.pdf

顔検出

では、haar cascadeを用いて人の顔を認識してみたいと思います。画像は以下の画像 (woman.jpg) を使用しました。

実行したコードは以下のようになります。

import cv2
import matplotlib.pyplot as plt

#画像の読み込み (画像1066x1600)
img = cv2.imread("woman.jpg")
#顔のカスケード分類器を読み込む
face_cascade = cv2.CascadeClassifier("haarcascades/haarcascade_frontalface_default.xml")
#画像をグレースケールにする
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#顔検出を実行!
faces = face_cascade.detectMultiScale(gray)
#facesに顔の位置が入っているので、for文で読み取る
for (x,y,w,h) in faces:
    #矩形を顔の位置に矩形を描画する
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),10)
#色の順番を変更する
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#出力
plt.imshow(img)
plt.show()

結果

ちゃんと認識されてますね!
次にコードの中のポイントだけ解説していきます。

カスケード分類器の読み込み

#顔のカスケード分類器を読み込む
face_cascade = cv2.CascadeClassifier("haarcascades/haarcascade_frontalface_default.xml")

この部分では、上記で述べた顔を分類するためのcascade分類器を読み込んでいます。もし

OpenCV(4.2.0) /Users/travis/build/skvark/opencv-python/opencv/modules/objdetect/src/cascadedetect.cpp:1689: error: (-215:Assertion failed) !empty() in function 'detectMultiScale'

のようなメッセージが出てきたら、多分カスケード分類器のxmlファイルががないので、以下からダウンロード (もしくはclone) してください。
https://github.com/opencv/opencv

ダウンロードしたら、data/haarcascadesのフォルダを自分のpythonファイル(またはipynb)と同じフォルダ内にいれて実行してください。

矩形描画

for (x,y,w,h) in faces:
    #矩形を顔の位置に矩形を描画する
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),10)

顔の位置は(x,y,幅,高さ)で出力されます。これは以下のようになります。

cv2.reactangleの引数は以下のようになります。
cv2.reactangle(画像,(左上x,左上y),(右下x,右下y),(色),線の太さ)

終わりに

カスケード分類器は顔だけでなく胴体や下半身、猫なども検出できます。近々その記事も執筆したいと思います。もし、記事に対してのご意見、誤りなどがあればコメントください。

Twitter

Twitterでも発信をしてます。もしよければフォローお願いします、、、!
https://twitter.com/ryuji33722052