はじめに
第3回の投稿となる今回は、顔検証の機能を作っていきたいと思います。なお、この記事は第2回:顔認証システム開発の環境構築の続きとなっているので、そちらをまず見ることを推奨します。
今回のゴール
タイトルにもある通り、今回は顔検出のシステムを作っていきたいと思います。そして顔検出のシステムを作るだけではなく、解説も詳しくやって、いきたいと思うので、顔検出についてしっかり理解してもらえれば幸いです。
早速ですが、今回のゴールを決めていきたいと思います!何かを作るにあたって理解するためには、自ら手を動かすことが一番手っ取り早いと思うので、ちゃんと成果物と呼べるようなものを作ることを目標にします。また、作っていくものは顔検出のシステと前述したのですが、漠然としすぎているので具体的にシステムの内容を説明していきます。以下が内容です。
- Webカメラを起動する
- 映像を入力として受け付ける
- 映像を表示する
- 受け取った映像に関して顔検出を行う
- 顔を検出した場合、顔領域を四角で囲む
- ESCキーを押して顔検出終了
↑↑こんな感じです。
文字列だけでみると、うわっ難しそう!って思うかもしれませんが、実はこの程度の実装なら案外簡単にできるので安心してください!また今回を経て、このブログを読んでくれた皆さんが顔検出マスターになれるように、解説もできるだけ丁寧に行なっていくので、最後までお付き合いください!
顔検出の実装
PyDevプロジェクトとPythonファイルを作成する
早速ですが、顔検出システムの実装の第一歩としてプロジェクトとファイルを作成していきたいと思います。これらの説明に関しては前回やったので、もちろん皆さんわかりますよね!?!? 忘れてしまっていたら、前回に戻って確認してみましょう!(第2回:顔認証システム開発の環境構築)
今回は顔検出を実装していくので、 プロジェクト名はFaceRecognition ファイル名はfaceRecognitionにします。
うまくいくとこんな感じです。↓↓
見ての通り、FaceRecognitionプロジェクトの中にfaceRecognitionファイルがあるのがわかります。このようになっていればPyDevプロジェクトとPythonファイルの作成は完了です。
画像から顔検出を行ってみる
プロジェクトとファイルを作成することができたら次のステップに進みましょう! 今回の最終目標はwebカメラから映像を入力し顔検出をするシステムを作ることですが、最初は手始めに1枚の画像から顔検出を行うシステムを作っていきたいと思います。 このシステムの中には
入力で受け取った画像を表示するためのウィンドウの準備
Cascadeパスの設定
顔検出を行う
などの、webカメラからの顔検出と重なる部分があるのでこれを拡張していき、最終的にwebカメラから映像を受け取る実装にします。
ここで「Cascadeってなんぞや???」と思った方もいるかもしれませんが安心してください。全ての項目について説明していきますが、Cascadeについては特に詳しく説明していきたいと思います!
実装
以下コードになります。
実装の解説
コードをコピペしただけでも動作しますが、しっかり内容を理解することも大事です! ですので、ここからコードの解説を書きます。以降もコードを追加するたびに詳しく解説を載せていきます。
最初の6行分を説明していきたいと思います。まず import cv2 で、OpenCVをインポートします。第2回の環境設定でOpenCVをインストールしましたが、ただインストールした状態では使うことができません。インポートをすることで初めてOpenCVを使用することができます。
次に face_casxade_pathについて説明します。これが例のカスケードになります!カスケードとはOpenCVの中にもともと入っているファイルで、画像ファイルから顔や鼻や瞳などといった領域を見つけ出すために使われます。今の実装でhaarcascade_frontalface_default.xmlをカスケードパスとして読み込んでいます。これは顔領域の抽出に使われるファイルです。他にもhaarcascade_eye.xmlやhaarcascade_mcs_nose.xmlがあり、これらは 目領域と鼻領域をそれぞれ抽出します。
より詳しく知りたい場合はこちら→OpenCVを使った顔認識(Haar-like特徴分類器)
- IMAGE_PATHは顔認証を行う対象となる画像のパスです。ここは自分が顔認証を行いたいと思う画像のパスに書き換えてください!
例をあげると、Desktopのkao.jpgという画像ファイルを顔認証させたい場合パスは"/Users/{your name}/Desktop/kao.jpg"といった具合です。
続いてface_cascadeの説明をします。勘の良い人は気づいたかもしれませんが、ここで初めてcv2が出てきましたね!このように cv2.CascadeClassifierと書くことで、cv2の中にあるCascadeClassierの機能を使うよ!ということをpythonに教えています。そしてカッコの中にface_cascade_pathが入っていますね。これは先ほど定義したhaarcascade_frontalface_default.xmlを示しています。このように記述することで、今から画像中の顔領域に対する認証を行うということを教えているというわけです!また、顔領域以外の認証を行いたいときは、face_cascade_path の中身を変更するだけで切り替えることができます。簡単ですね!
続いては10行目のsrcについてです。ここではcv2.imread()を使用して画像を読み込みます。IMAGE_PATHによって指定された画像がsrcとして読みこまれます。
11行目では前行で読み込んだ画像をグレースケールします。グレースケールするということは、分かりやすく説明すると、カラー画像を白黒画像に変更するイメージです。グレースケールする理由はいくつかありますが、最も大きな理由は計算がしやすくなるからです。カスケードを使用して顔検出する場合にもグレースケールした画像を適用する必要があります。(通常のカラー画像では顔検出できません))
グレースケールに関する詳しい説明は省きますが、
もっと知りたい方はこちら→【画像処理】グレースケールの原理・特徴・計算式
- そして13行目でいよいよ顔認証を行います!このface_cascade.detectMultiScale(src_gray)と記述することで、グレースケールした画像であるsrc_grayから写っている顔を見つけ出します。そして、見つけ出した顔領域の画像上の座標をfacesというリストの形で変数にします。
続いて最後のまとまりの説明に入ります。まずfor文に関してですが、ここでは先ほどのfacesから一つずつ顔領域を取り出し、その領域の座標をx, y, w, h(それぞれx座標, y座標, 横幅, 縦幅を表す)という変数に入れます。
そしてcv2.rectangle()を使用して、検出した顔領域を四角で囲みます。cv2.rectangle()の引数についてですが、cv2.rectangle(顔検出の対象となる画像, 顔領域の左下の角を示すx座標とy座標, 顔領域の右上の角を表すx座標とy座標, 四角の色, 線の太さ)といった具合です。今の実装では「srcという画像の座標(x ~ x+w, y ~ y+h)に顔領域が存在し、その領域をRGBカラー(255, 0, 0)の太さ2の四角で囲む」といった操作になります。
最後に顔領域を四角で囲った画像を指定したPATHに画像ファイルとして保存します。ここも自分が保存したいと思う場所のPATHを書いてください!例を挙げると、Desctopにkao_kekka.jpgという名前で保存したい場合、"/Users/{your name}/Desktop/kao_kekka.jpg"といった感じです。
実行結果
コードの解説も終わったので、いよいよこれを実行していきましょう!
実行結果が以下になります。
見事顔を検出することができました!!!
これであなたも顔検出マスターに一歩近づけましたね!
続いてはこのコードを拡張して、今回のブログのゴールであるwebカメラを使った顔認証を作成していくので、もう少しお付き合いください!
webカメラから顔検出を行ってみる
いよいよwebカメラからの顔検出を行う時が来ました!前述した通り、先ほどのコードを拡張して作っていきたいと思います。
実装
以下コードになります。
実装の解説
それでは解説してきたいと思います。
最初の5行目までは、前章でも解説したカスケードパスの設定なので、そちらを参考にしてください。
ESC_KEYとINTERVALはそれぞれ定数を表しています。この定数はESCキーが押された時に終了するという処理を作る際に必要なものです。
全体のコードを見ても分かる通り、32~34行目あたりでその処理を行うので、詳しくはそこで解説したいと思います。
次にcap = cv2.VideoCapture(0)について解説していきます。メモ書き(#に続くpythonコメント)を見ても分かる通り、ここでは映像をwebカメラから取得するということを指定しています。どこから映像を取得するかは、VideoCapture()の引数によって決まります。今回は0を決め打ちしていますが、引数に0を取ることでwebカメラを指定しているというわけです。また、PCにラズベリーパイなどの別のデバイスを接続している場合は、引数を変更することで切り替えることができます。今回はwebカメラを使用するので、引数は0でオーケーです。
end_flagとc_frameに関して解説します。まずend_flagですが、これはカメラから正常に映像を読み込めてるかどうかの状態を表します。正常に読み込めていればTrueです。c_frameはpythonコメントにもある通り初期フレームを読み込んでいます。
- 続いては、このプログラムのメインとなる部分の解説に入ります。まず、while end_flag == True:ですが、先ほど取得した end_flag がTrueで有る限り、つまりカメラが起動している限りこのループを実行し続けるということです。
C言語やJAVAなどでは、ループの範囲を{}で囲ったりしますが、Pythonはこの範囲をインデント(TABキー)によって区別します。ですので、このwhileループの範囲は18 ~ 37行目の範囲ということになります。
20 ~ 25行目では顔検出を行なっていますが、前章のコードとほぼ同じなので詳しい説明は省きます。唯一違ってるところは、src を c_frameから読み込んでるというところです。前章では画像ファイルをそのまま読み込みましたが、今回はwebカメラから映像を読み込むので先ほど定義したc_frame にしてあります。
cv2.imshow("src", src)に関して説明します。imshow()は画像をウィンドウに表示するための関数で、引数にはウィンドウ名と表示する画像を指定します。引数に入っているsrcはwebカメラからの映像を顔検出した画像なので、その画像を"src"という名前のウィンドウに表示します。
ここで、「表示するのは映像ではないの?」と思った方もいるかもしれませんが、大丈夫です。ループの中身には画像を表示する操作しかありませんが、そもそもこのループが高速に動作するので、画像が連続で表示され映像として見ることができるのです。
次にcv2.waitKey(INTERVAL)について解説します。waitKey()はキーボード入力を処理する関数で、引数は入力を待つ時間を指定します。今引数になっているINTERVALは33なので、ここでは33ミリ秒間キーボード入力を待ちます。そしてif key == ESC_KEYでは、先ほどの入力待ち時間の間にESCキーが押されたかを判定します。さらに、押された場合にはbreakによってループを抜け、顔認証を終了します。これらの処理が1ループの中に存在するので、実際の動作では、いつESCキーが押されても顔認証を終了することができるというわけです。
ここのend_flag, c_frameはループに入る前の処理と全く同じです。1ループごとにカメラが正常に読み込めているかどうかを確かめ、同時に次のフレームを読み込みループの最初に戻ります。
最後に残りの2行分の解説をしていきます。cv2.destroyAllWindows()は文字通り、開いてたウィンドウをすべて正常に終了します。
cap.release()は使用していたカメラを正常に終了します。
ウィンドウに関してもwebカメラに関しても、このように記述しなくてもプログラムを終了したタイミングで終了することもできます。しかし、正常に終了する処理を書くことで可読性も上がり、また予期せぬエラーも出にくくなるので、一見無駄に見える処理もしっかり書くことを心がけましょう。
実行結果
いよいよ実行する時がきました!ここまで長かったですねw
それでは実行してみましょう!!
↑↑こんな感じになりました!!(顔の部分の丸は顔を隠すために載せています。実際は顔の周りに青い四角が描画されていれば正常です)
これであなたも顔検出マスターですね!!
最後に
お疲れ様でした!!長かったと思いますが、ここまで読んでもらって本当にありがとうございます!今回は顔認証システムの中の顔検出に絞って
解説していきましたが、いかがだったでしょうか?少しづつ顔認証というものがどんなものか分かってもらえれていたら幸いです!
また、次回は特徴点の抽出機能についての解説をしていきます。次回もお楽しみに!!