Raspberry Pi 深層学習でリアルタイム顔認識（Keras・Open CV）

愛用のRaspberryPiが「赤りんご」と「青りんご」を見分けることができたので、同じ方法で「顔も見分けられるんじゃないだろうか？」と思い試してみました。

## こんな感じ

![2017-01-14 14_01_46.gif](https://qiita-image-store.s3.amazonaws.com/0/47128/91a13b33-2499-40e6-f00d-81632a1c94f6.gif)


まずは「サミュエル・L・ジャクソン（のフィギュア）」から。確率90%以上で本人と判定させてみました。

![2017-01-14 14_02_58.gif](https://qiita-image-store.s3.amazonaws.com/0/47128/636e9274-d2d9-a4f3-b29a-b6c4a8799732.gif)

続いて「ジョン・トラボルタ（のフィギュア）」。同じく確率90%以上で本人と判定させています。

顔の切り出しはOpenCVで行いました。

## 環境

![DSC_0070.JPG](https://qiita-image-store.s3.amazonaws.com/0/47128/f41ca7c8-53fc-d4d1-facc-d4f601e9b4b1.jpeg)

- [パルプ・フィクション/ サミュエル・L・ジャクソン ジュールス・ウィンフィールド 13インチ トーキングフィギュア](http://amzn.to/2iuJhoU)
- [パルプ・フィクション/ ジョン・トラボルタ ビンセント・ベガ 13インチ トーキングフィギュア](http://amzn.to/2imNzk5)

あとは[前々回](http://qiita.com/PonDad/items/c5419c164b4f2efee368)と同じです。


## 学習の流れ

学習方法は[リンゴを見分けさせた方法](http://qiita.com/PonDad/items/9e1dc2752a089b753fe5)と同じです。

1. Web上から画像をダウンロードし、OpenCVで顔を切り出す。
2. 切り出した画像を`NumPy`配列にし、訓練データとテストデータに分ける
3. 畳み込みニューラルネットワークで学習する
4. OpenCVで切り出した顔の画像を`NumPy`配列にし推測データとして使用する

顔の切り出しにはOpenCVのカスケード分類器を利用しました。

### 1. Web上から画像をダウンロードし、OpenCVで顔を切り出す。

リンゴのスクレイピングでも利用させて頂きました、[TomoProgの技術書](http://tomoprog.hatenablog.com/entry/2016/02/13/024004)さんのクローリングコードを利用しました。（ありがとうございます）

[TomoProg/HatenaBlog/python/web_crawler.py - GitHub](https://github.com/TomoProg/HatenaBlog/blob/master/python/web_crawler.py)

OpenCVで顔を切り出すのは、[長生村本郷Engineers'Blog](http://kenzo0107.hatenablog.com/entry/2016/08/04/143742)さんのこちらのコードをそのまま利用しました。（ありがとうございます）

[kenzo0107/collect_face_samples.py - Gist](https://gist.github.com/kenzo0107/517258ab06715f73c4a3457e87fd25a5)

こちらはファイルを指定すれば自動で顔を切り出せるのですが、更に嬉しいことに反転画像や回転画像も自動的に出力することが出来ます。

`Keras`のメソッドで画像の水増しをすることも出来るようなのですが、今回はこちらをそのまま利用させて頂きました。

![travolta 2017-01-14 14-43-34.png](https://qiita-image-store.s3.amazonaws.com/0/47128/77d9eecc-fee3-197a-803b-fc19e210f535.png)

200枚ほどの顔画像をゲットしました。

最初「サミュエル・L・ジャクソン」「ジョン・トラボルタ」と私の３人で学習し、３人の分類は上手くいきましたが、サンプルが少なすぎて、顔画像であればなんでも99%と認識してしまいました。

![madsen 2017-01-14 14-44-06.png](https://qiita-image-store.s3.amazonaws.com/0/47128/373509f1-3a9a-ae37-0707-2cf36c3d8717.png)

そこで学習用のラベルを増やしてみることにしました。「ブラック・スプロイテーションの女王」こと「パム・グリア」さんと、タランティーノの「レザボア・ドッグス」でミスターブロンドを演じた「マイケル・マドセン」の画像も合わせて抽出してみました。

私の認識精度を上げるために、**昔似ていると言われたことのある**俳優の**三上博史**さんの画像を一緒に抽出しました。

## 2. 切り出した画像を`NumPy`配列にし、訓練データとテストデータに分ける

リンゴと比べると顔の構造はちょっと複雑になるので、画像の大きさをどうしようか迷ったのですが、今回は32×32ピクセルのまま試してみました。

[face_makedata.py - Gist](https://gist.github.com/PonDad/c128fbd3bcc94bafa1de5627898a2794#file-face_makedata-py)

ラベルは「サミュエル・L・ジャクソン」「ジョン・トラボルタ」「私」「パム・グリア」「マイケル・マドセン」**「三上博史」**の6名で分けました。

### 3. 畳み込みニューラルネットワークで学習する

学習方法はラベルが増えたことを除きリンゴと一緒です。

[face_keras.py - Gist](https://gist.github.com/PonDad/c128fbd3bcc94bafa1de5627898a2794#file-face_keras-py)

![figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/47128/bc24acc4-86b1-9fdf-2999-8b3209f594e5.png)

![figure_2.png](https://qiita-image-store.s3.amazonaws.com/0/47128/cb66488e-69a4-d252-f390-3038bb731a86.png)

`nb_epoc=30`で学習させてみました。10エポック位で終了した方が良いのかもしれませんが、今回はこれで。

### 4. OpenCVで切り出した顔の画像を`NumPy`配列にし推測データとして使用する

リンゴの画像をデータ化する際は、キーボードsキー押下で写真を撮ったのですが、今回は認識したものをリアルタイムで表示させてみました。

iMacで実行した際は0.2秒間隔で画像認識させても比較的スムーズに表示されたのですが、RaspPiだと少し厳しいです。0.4秒間隔で画像認証をさせていますが結構遅延が起きてしまいます。

[face_checker_cv_notalk.py - Gist](https://gist.github.com/PonDad/c128fbd3bcc94bafa1de5627898a2794#file-face_checker_cv_notalk-py)

OpenCVは`cv2.putText()`というメソッドを使うと文字も画像に書き込めるようです。顔認識の正方形の上に`Keras`の`Predict()`で推測したラベル名と推測の割合を画像に表示させて完成です。

## まとめ

私の画像で試すとこんなレスポンスが返ってきます。

```bash
$ python3 face_checker_cv_notalk2.py
Using TensorFlow backend.
[[  7.23991604e-08   1.06343272e-07   9.99999404e-01   1.25359421e-07
    1.08549557e-07   1.90402147e-07]]
PonDad
```
3番目が私のラベル、6番目のラベルが「三上博史」さんです。

似てねえ。