前回の記事のとおり、Anaconda環境でOpenCVを使えるようになったので、早速顔認識のプログラムを書いてみた。

結果、予想以上に簡単だったので、コードの解説を交えながら紹介しよう。

フリー素材サイトから写真を用意

「ぱくたそ」から人物写真をダウンロードした。

今回用意した写真は以下のリンクからダウンロードできる。

https://pakutaso.com/20140912244post-4510.html

画像の読み込み

まずはOpenCVをインポートし、用意した画像を読み込む。

今回はメインとなるPythonファイルと同じディレクトリに「sample_img.jpg」というファイル名で画像を保存した。

import cv2

image = cv2.imread('sample_img.jpg')

GitHubから顔検出用の学習済みモデルをダウンロード

次に、顔検出のために必要な学習済みモデルをGitHubからダウンロードする。

https://github.com/opencv/opencv/tree/master/data/haarcascades

たくさんのファイルが並んでいるが、今回は下記の赤枠で囲った「haarcascade_frontalface_alt2.xml」をダウンロードする。

ダウンロードは上記のリンクをクリックし、「Raw」ボタンをクリック。
そしてブラウザの「ファイルを保存」(Mac Chromeの場合Cmd + S)で、作業ディレクトリに保存すればOKだ。

分類器の用意

ダウンロードしたモデルを使って、次は分類器を用意する。

cascade_file = 'haarcascade_frontalface_alt2.xml'
cascade_face = cv2.CascadeClassifier(cascade_file)

CascadeClassifier関数でモデルファイルを読み込むだけだ。

顔検出処理を実行

先ほど用意した分類器cascade_faceのdetectMultiScale関数を実行すると、見つかった顔の位置(左上x, y座標)と、顔のサイズ(w, h)が配列として返される。

# 顔を探して配列で返す
face_list = cascade_face.detectMultiScale(image, minSize=(20, 20))

ここまでのコードを実行してみると、次の結果が返ってくる。

print(face_list)

# [[752 239 167 167]
#  [546 337 128 128]]

検出された顔に枠をつけて画像を保存する

いよいよ最終の処理に入る。

for (x, y, w, h) in face_list:
	border_color = (0, 0, 255)
	border_size = 2
	cv2.rectangle(image, (x, y), (x+w, y+h), border_color, thickness=border_size)

cv2.imwrite('out.jpg', image)

行っていることはそれほど難しくはない。

border_colorはBGR形式で色を指定している。
OpenCVはよくあるRGBと異なり、BGRとなっているので注意が必要だ。

border_sizeは枠線のサイズを指定。

rectangleの第一引数には画像を、第二引数に枠線の開始点(左上座標)、第三引数に終了点(右下座標)、第四引数に線色、thicknessに線の太さをそれぞれ指定している。

最後にimwrite関数で任意のファイル名で画像を保存すればプログラム完成だ。

早速ターミナルで完成したPythonファイルを実行してみよう。

作業ディレクトリに新しく「out.jpg」が生成され、見事に顔に赤い枠線が描かれているはずだ。

コード全文

import cv2

image = cv2.imread('sample_img.jpg')

cascade_file = 'haarcascade_frontalface_alt2.xml'
cascade_face = cv2.CascadeClassifier(cascade_file)

# 顔を探して配列で返す
face_list = cascade_face.detectMultiScale(image, minSize=(20, 20))

for (x, y, w, h) in face_list:
	border_color = (0, 0, 255)

	border_size = 2
	cv2.rectangle(image, (x, y), (x+w, y+h), border_color, thickness=border_size)

cv2.imwrite('out.jpg', image)