前回はある特定の人物1人の顔が、動画の中に映ったかどうかを判定するプログラムを紹介しました。今回は複数の人物を登録しておき、そのうち誰が映ったかを判定するプログラムを作ったので紹介します。

準備

必要なものは前回と同じです。Visual Studio Communityがインストールされている必要がありますし、Python側ではOpenCVとdlib、cmake、face_recognitionモジュールが必要となります。インストールしていないモジュールがあれば、以下のコマンドでインストールしてください。

実行した様子

プログラムのソースコードを解説する前に、実行した様子を示します。

プログラムを起動すると以下のように前回と全く同じウィンドウが表示されます。

「映像読み込み」ボタンを押して複数の人物が映った動画ファイルを選びます。ここではYoutubeの映像を読み込んでいます。

今回使った映像

ここまでは前回と同じですが、「顔写真読み込み」ボタンを押して選択するのは、特定の人物が映った1つの画像ファイルではなく、人物の名前がファイル名となった顔写真が複数枚入っているフォルダを選択するように変わっています。

今回使った画像(8枚)

映像には「Bill Gates」「Jack Dorsey」「Mark Cuban」「Mark Zuckerberg」「Steve Jobs」が映っていますが、「Elon Musk」「Jeff Bezos」「Larry Page」は映っていません。映像にない顔写真を入れたのは、プログラムが顔を誤検出しないかどうかを確かめるためです。また映像には「Ali Partovi」が映っていますが、画像フォルダに「Ali Partovi」の写真は入れていません。

「検出開始」というボタンを押すと処理が始まります。

動作結果

フォルダから読み込んだスティーブ・ジョブズの写真はかなり年齢が上のときのものですが、若いときの映像でもちゃんと認識できています。

他にもこのようにちゃんと認識できていますし、

また、読み込んだフォルダに含まれていない「Ali Partovi」は、顔が映っても判定されていません。

このように複数の人物であっても、うまく特定の人物を検出できていることが確認できました。それではプログラム中身を紹介していきます。

プログラムの内容

ソースコードはこちらです。

MyUtility.py

プログラムの解説

ソースコードの大半は前回と同様です。変更した部分に注目して解説していきます。

前回のプログラムでは1つの画像ファイルを読み込んでいましたが、今回はフォルダを指定するので、open_pictfileでMyUtility.pyに含まれるask_directoryという関数を呼び出しています。

次にメインの処理をしているdetect_face_in_movie関数で変更したところを見ていきましょう。

osモジュールのlistdir関数を用いて、フォルダに含まれるファイルのリストを取得し、forループでそれぞれの画像を読み込んでいます。ちなみに画像以外のファイルが含まれていた場合のエラー処理などは行っていません。

読み込んだ画像データをface_recognitionのface_encodings関数でエンコードし、encodeListKnownというリストに格納しています。これでフォルダに含まれていた画像の自分の顔の特徴点が計算できました。

映像から1フレームを読み込んで顔を検出したあと、さきほど計算した顔の特徴点のリスト(encodeListKnown)と映像で検出された顔の特徴点をface_recognition.compare_faces関数で比較しています。複数の顔で比較を行っているので、face_recognition.compare_faces関数とface_recognition.face_distance関数の戻り値matchesとfacedistも複数の要素(フォルダに含まれていた顔写真の数分)を含みます。
そして距離(facedist)が最小のもの、つまり顔の特徴点を表す空間(128次元)において最も近い位置にあると判定された顔のインデックスをnp.argmin関数で取り出し、その要素に該当するmatchesがTrueであるかどうか(同じ顔と判定されているか)をif文で判定しています。Trueであれば検出された顔の周りに緑色の矩形を描画して、その下に名前を表示する処理をしています。

以上が簡単な説明です。

さいごに

今回のプログラムを使えば、会社の出退勤や学校の出席などを自動化することができるかもしれないですね。