前の日記で、dlibの顔検出を試したが、dlibには目、鼻、口、輪郭といった顔のパーツを検出する機能も実装されている。
英語では「Facial Landmark Detection」という用語が使われている。
日本語では「顔器官検出」と訳すようだ。
ここでは、サンプルを試す手順について記載する。
その後、検出位置を編集する方法についても記載する。
前回、Windows上でMSYS2とAnaconda4(64bit)でインストールしたPythonでdlibを動かす方法について書いたが、JPEGライブラリがうまくリンクされずサンプルが動かせなかったのでBash on Windows環境で試した。(後日追記:JPEGライブラリを有効にする方法はこちらの日記参照)
学習済みモデルを使って検出
dlibでは顔器官検出の学習済みモデルが配布されている。
まずはこれを使って試してみる。
dlibのサイトからソースコードをダウンロードして展開し、サンプルディレクトリに移動する。
wget https://github.com/davisking/dlib/archive/v19.1.zip unzip v19.1.zip cd dlib-19.1/python_examples
学習済みモデルをダウンロードし、展開する。
URLはface_landmark_detection.pyのコメントに記載されている。
wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2 bzip2 -d shape_predictor_68_face_landmarks.dat.bz2
サンプルを実行する。
./face_landmark_detection.py shape_predictor_68_face_landmarks.dat ../examples/faces
以下のように検出結果が表示される。
拡大すると、このような感じになっている。
サンプルでは顔画像の68個の位置を検出するようになっている。
学習から行う
dlibには学習データも用意されているので、学習から試してみる。
サンプルの学習データは、dlib-19.1/examples/facesに格納されている。
training_with_face_landmarks.xmlが学習データ、testing_with_face_landmarks.xmlがテストデータを記述したXMLとなっている。
XMLをブラウザで表示すると、スタイルシートで加工されて見やすい形で確認できる。
学習用のスクリプトは、train_shape_predictor.pyである。
以下のコマンドで実行する。
./train_shape_predictor.py ../examples/faces
学習に1分くらいかかる。
学習が終わると、学習データでの検出結果が表示される。
検出位置を編集する
サンプルでは68個の位置を学習するようになっているが、位置は68個でなくても学習できる。
サンプルのxmlを加工して、位置の数を60個に減らして学習してみる。
imglabコマンド(前の日記参照)で、学習データのXMLを表示すると、各位置に付けられたラベルが確認できる。
Ctrlを押しながらマウスホイールで拡大すると、00から67のラベルが付けられていることが確認できる。
特徴の位置は、ダブルクリックすると選択でき、Deleteキーで削除できる。
位置を追加するには、追加したいラベルを引数で与えてimglabコマンドを実行する。
imglab --parts "00 01 02" training_with_face_landmarks.xml
顔の領域の四角い枠をダブルクリックで選択した状態で、追加したい位置で右クリックすると、付与するラベルを選択して追加できる。
ここでは、直接XMLを加工して、口の内側の点(60から67)を削除する。
dlib-19.1/examples/facesディレクトリを別の場所にコピーする。
コピーした先のディレクトリの、training_with_face_landmarks.xmlとtesting_with_face_landmarks.xmlの
<part name='60' x='292' y='217'/>
という行の、name='60'の個所が60以上の行を削除する。
テキストエディタの正規表現で置換するか、sedコマンドで以下のように編集する。
sed -i -e "s/^.*name='6.*$//g" training_with_face_landmarks.xml sed -i -e "s/^.*name='6.*$//g" testing_with_face_landmarks.xml
学習のスクリプトをコピー先のディレクトリを指定して実行する。
例) R:\sample\facesにコピーした場合
./train_shape_predictor.py /mnt/r/sample/faces
学習はできるが、結果表示時にエラーが表示される。
Traceback (most recent call last): File "./train_shape_predictor.py", line 131, in <module> win.add_overlay(shape) RuntimeError: Error detected at line 25. Error detected in file /mnt/r/dlib-19.1/dlib/../dlib/image_processing/render_face_detections.h. Error detected in function std::vector<dlib::image_display::overlay_line> dlib::render_face_detections(const std::vector<dlib::full_object_detection>&, dlib::rgb_pixel). Failing expression was dets[i].num_parts() == 68. std::vector<image_window::overlay_line> render_face_detections() Invalid inputs were given to this function. dets[0].num_parts(): 60
これは、表示する位置の数が68個固定になっているためである。
そこで、dlibのソースを修正して、68個以外の場合にも表示できるようにする。
エラーメッセージに表示されているdlib/image_processing/render_face_detections.hを修正する。
21行目から25行目をコメントアウトする。
/*DLIB_CASSERT(dets[i].num_parts() == 68, "\t std::vector<image_window::overlay_line> render_face_detections()" << "\n\t Invalid inputs were given to this function. " << "\n\t dets["<<i<<"].num_parts(): " << dets[i].num_parts() );*/
64行目から66行目をコメントアウトする。
/*for (unsigned long i = 61; i <= 67; ++i) lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); lines.push_back(image_window::overlay_line(d.part(60), d.part(67), color));*/
ソースをビルドしてインストールする。dlibを解凍したディレクトリで、以下のコマンドを実行する。
sudo python setup.py install
ビルド/インストールが完了したら、もう一度、学習用スクリプトで位置の数を編集したデータの学習を行う。
./train_shape_predictor.py /mnt/r/sample/faces
今度は、エラーとならず結果が表示される。
結果を拡大すると、口の内側の線がなくなっていることが確認できる。
同様の方法で、検出する位置を自由に編集して学習することができる。