TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

dlibで顔のパーツ検出を行う

前の日記で、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

以下のように検出結果が表示される。
f:id:TadaoYamaoka:20160923094400p:plain

拡大すると、このような感じになっている。
f:id:TadaoYamaoka:20160923094433p:plain

サンプルでは顔画像の68個の位置を検出するようになっている。

学習から行う

dlibには学習データも用意されているので、学習から試してみる。
サンプルの学習データは、dlib-19.1/examples/facesに格納されている。
training_with_face_landmarks.xmlが学習データ、testing_with_face_landmarks.xmlがテストデータを記述したXMLとなっている。
XMLをブラウザで表示すると、スタイルシートで加工されて見やすい形で確認できる。

f:id:TadaoYamaoka:20160923091705p:plain


学習用のスクリプトは、train_shape_predictor.pyである。
以下のコマンドで実行する。

./train_shape_predictor.py ../examples/faces

学習に1分くらいかかる。

学習が終わると、学習データでの検出結果が表示される。

検出位置を編集する

サンプルでは68個の位置を学習するようになっているが、位置は68個でなくても学習できる。
サンプルのxmlを加工して、位置の数を60個に減らして学習してみる。

imglabコマンド(前の日記参照)で、学習データのXMLを表示すると、各位置に付けられたラベルが確認できる。
Ctrlを押しながらマウスホイールで拡大すると、00から67のラベルが付けられていることが確認できる。
f:id:TadaoYamaoka:20160923100927p:plain

特徴の位置は、ダブルクリックすると選択でき、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

今度は、エラーとならず結果が表示される。
結果を拡大すると、口の内側の線がなくなっていることが確認できる。

f:id:TadaoYamaoka:20160923105438p:plain

同様の方法で、検出する位置を自由に編集して学習することができる。