家庭用見守りロボットを作る（Raspberry Pi2+Windows10 IoT Core+Azure）第3回：ProjectOxford FaceAPIで家族の顔写真を学習させる

家庭用見守りロボットを作る（Raspberry Pi2+Windows10 IoT Core+Azure）第3回です。

#今回のテーマ
[前回](http://qiita.com/ma-watanabe/items/c1bf739f1613506d65b9)に引き続き、
Microsoft ProjectOxford FaceAPIを用いて、家族の写真を学習させて、家族の認識ができるようにします。
あまり伝わってませんが、APIだけで、しかも無料で家族の写真を判別できた事に、本人はいたく感動しましたので、喜びを共感いただければ幸いです 笑。

#参考になったサイト

・FaceAPIの概要理解
[空気を読んで年齢を答えてくれる例のあれの裏側にあるAPIがAzure Marketplaceに登場してきました。](http://hatsune.hatenablog.jp/entry/2015/05/02/143055)
・FaceAPIの仕様詳細
[ProjectOxford API Reference](https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395249/console)
・FaceAPIの顔写真データの教師データの作成や学習方法（Mac向け）
[三倉姉妹をAzureを使って見分ける](http://blog.tottokug.com/entry/2015/12/21/012419)

# 準備するもの
####ProjectOxfordのFaceAPIKey
[前回](http://qiita.com/ma-watanabe/items/c1bf739f1613506d65b9)取得したFaceAPIのKeyが必要です。
まだOxfordの登録を済ませてない方は、前回を参考にAPI Keyの取得をお願いします。

####Mac
※写真データを一括登録をしたい点と、参考にしたサイトやスクリプトを実行するのにMacを使い慣れている関係で、今回はMacを使います。
WindowsだったりMacだったりコロコロ使ってすみませんが、ご容赦くださいませ＾＾；。
####大量の写真
4人家族で1000枚ぐらいの写真を準備します。
溜めどりした家族の写真を使う時が来ましたので、思う存分使いましょう！
運動会とかは抽出した後の振り分けが大変になるので、極力少ない人数で取った写真を使うことをお勧めします。

# 作業の流れ
今回は下記の流れで作業を進めます。
DeepLearningの基本的な流れになりますが、DeepLearningについて不明な方がいましたら[こちら](http://qiita.com/ma-watanabe/items/c1ce03e6a621fe0a92a4)をご参考ください。

1.FaceAPIとimagemagickで家族の顔写真を切り出す

2.FaceAPIを使って家族判別用教師データを作成する

3.API ReferenceでPerson GroupとPersonの作成をする

4.教師データを送信する

5.学習を開始する

6.検証する

#FaceAPIとimagemagickで家族の顔写真を切り出す
顔認識の精度を上げるため、写真から画像の顔を切り出します。

1.[jq](https://stedolan.github.io/jq/)と[imagemagick](http://d.hatena.ne.jp/keyword/imagemagick)をインストールします。
　Ⅰ.HomebrewのサイトからHomebrewをインストールします。
>    $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

　Ⅱ.jqをインストールします。
>$ brew install jq
　

　Ⅲ.imagemagickをインストールします。
>$ brew install imagemagick

2.カレントディレクトリに写真があるように移動し、フォルダ「face」と「error」、シェルスクリプト「face_cut.sh」も作成し、実行します。
![face_cut.png.png](https://qiita-image-store.s3.amazonaws.com/0/33021/25939e4d-479e-6102-6fe8-2f479b974582.png)

作成するシェルスクリプトは以下となります。
※FaceAPIKeyには[前回](http://qiita.com/ma-watanabe/items/c1bf739f1613506d65b9)取得したFaceAPIのKeyが入りますのでご注意ください。

```shell-session:face_cut.sh
FS='
'
FaceAPIKey=XXXXXXXXXXXXXXXXXXXXX
[ -d face ] && mkdir face
for f in $(find ./ -type f);
do
  curl -X POST  -H "Content-Type: application/octet-stream" --data-binary @${f} \
  "https://api.projectoxford.ai/face/v0/detections?subscription-key=${FaceAPIKey}"   \ | jq '.[].faceRectangle | "\(.width)x\(.height)+\(.left)+\(.top)"' | xargs -I{}  convert -crop  {} ${f} face/$(uuidgen)-{}-${f##*/};
done
```
実行中は以下の様なログが表示されます。
実行完了まで私のPCでは3～4時間程度かかりましたので、気長にお待ちください。
![face_cut_excute.png](https://qiita-image-store.s3.amazonaws.com/0/33021/2de65694-9e51-bca2-21a2-489708d99d24.png)

3.実行完了、faceディレクトリに顔を切り出した画像が作成されています。
集団で写っている場合は関係ない人も抜き出されてしまいますので、
精度を上げるため、削除します。

#FaceAPIを使って家族判別用教師データを作成する。
1.切り出しされた画像はそれぞれの家族の名前で振り分けて登録するため、
それぞれの家族の名前のフォルダをアルファベットで作成し、画像を振り分けます。
我が家では1000枚の写真のうち、1人あたり200枚前後の画像で振り分けできました。
※私はFinder上でファイルを開いては画像にタグを付けて、後からフォルダに振り分けました。
不要な画像の削除と振り分けで手間をかけてしまいましたが、Picasaなど顔認識で振り分け可能なアプリをうまく使えば、振り分けを簡単にできるかもしれません。
簡単な方法を編み出した方いましたら教えて下さい。
![furiwake.png](https://qiita-image-store.s3.amazonaws.com/0/33021/b06295e5-d0c9-d869-986a-65f0890c9fcd.png)

2.切り出した顔写真を家族の名前で分類するため、Bounding Boxのデータをcsvへ吐き出すスクリプトを作成し、実行します。
Bounding Boxとは、認識した顔の画像上の位置を指すそうです。
[こちら](http://oshiete.goo.ne.jp/qa/505244.html)がイメージしやすかったです。
FaceAPIを使用して、画像データをPOST送信し、顔認識結果をcsvへ吐き出します。
Bounding Boxのデータは「faceRectangle」を用いて取得します。
FaceAPIは秒間1回くらいの利用しか認めていないようで、1秒を超えるとエラーが返ってくるようですので、sleep 1を入れて1秒待機させます。

スクリプトは以下になります。
後からやり直しということもありそうでしたので、念のため検出済のデータもそれぞれの名前で保管するようにしました。

```shell-session:images_detect.sh
FS='
'
FaceAPIKey=XXXXXXXXXXXXXXXXXXX
[ -d images/$1_detected ] || mkdir -p images/$1_detected
for f in $(find ./images/$1 -type f);
do
  curl -X POST  -H "Content-Type: application/octet-stream" --data-binary @${f} \
  "https://api.projectoxford.ai/face/v0/detections?subscription-key=${FaceAPIKey}"  \
  |jq -r ".[]  | [\"$f\",.faceId,.faceRectangle.width,.faceRectangle.height,.faceRectangle.left,.faceRectangle.top] | @csv"  >> $faceindex_1.csv
  mv "${f}" images/$1_detected/
 sleep 1
done

```
スクリプト実行は以下のように振り分けた家族のディレクトリ名で実行できるようにしました。
>sh images_detect.sh <ディレクトリ名>

実行すると下記のようなログが出力されます。
![images_detect_excute.png](https://qiita-image-store.s3.amazonaws.com/0/33021/36736b77-9cd2-9c7e-5c69-c93daa91deda.png)

# Person GroupとPersonの作成をする
1.[ProjectOxford API Reference](https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395249/console)にアクセスして、Person Groupの作成をします。
Person Group-Create a Person Groupを開いて、下記を入力してSendボタンをクリックします。

personGroupId：＜家族姓（アルファベット）例）watanabe-family＞
Ocp-Apim-Subscription-Key：＜FaceAPIKey＞

200が返っていたら成功です。
![CreateAPersonGroup.png](https://qiita-image-store.s3.amazonaws.com/0/33021/7c7c5e5d-0d91-8f77-8079-645fce696cd9.png)
![CreateAPersonGroup2.png](https://qiita-image-store.s3.amazonaws.com/0/33021/b8a577fe-0164-98df-9e85-1676787f979b.png)

2.[ProjectOxford API Reference](https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395249/console)でPerson の作成を家族の人数分します。
Person-Create a Personを開き、下記を入力してSendボタンをクリックします。
家族の名前は作成したフォルダ名に合わせます。

personGroupId：＜家族姓（アルファベット）＞
Ocp-Apim-Subscription-Key：＜FaceAPIKey＞
Request body内の"name"：＜家族の名前（アルファベット）＞
成功すると、personIdが発行されます。
![CreateAPerson1.png](https://qiita-image-store.s3.amazonaws.com/0/33021/c0fd2655-5b64-3d67-1a0e-c4c7893b695e.png)
![CreateAPerson2.png.png](https://qiita-image-store.s3.amazonaws.com/0/33021/08651b50-d218-9791-26d0-7461f90bf68d.png)

3.[ProjectOxford API Reference](https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395249/console)でPersonができていることの確認をします。
Person - List Persons in a Person Groupを開き、下記を入力してSendボタンをクリックします。
personGroupId：＜家族姓（アルファベット）＞
Ocp-Apim-Subscription-Key：＜FaceAPIkey＞
![ListPerson1.png](https://qiita-image-store.s3.amazonaws.com/0/33021/eb240613-370c-3cc7-072e-d95f86eb4acb.png)
![ListPerson2.png](https://qiita-image-store.s3.amazonaws.com/0/33021/5f80967c-f2b5-ab57-d5bc-02f1d913e35f.png)

# 教師データを送信する
家族の写真を学習させるため、教師データを送信します。
スクリプトは以下になります。
家族の名前を引数に入れてスクリプトを実行し、それぞれのpersonIdで実行できるようにしています。

```shell-session:images_detect.sh
#!/bin/bash
FS='
'
FaceAPIKey=XXXXXXXXXXXXXXXXXXX
personGroupId="watanabe-family"
if [ $1 = "aimi" ]
then
personId=4407ed98-1c5f-4fbd-88cb-1607d747b9df
elif [ $1 = "masatoshi" ]
then
personId=3ba0b015-eb28-4562-b13d-5a271532226f
elif [ $1 = "hisako" ]
then
personId=15836868-943f-4ea4-9aa4-da438eaf2d5d
elif [ $1 = "yushin" ]
then
personId=6e03f5ec-838b-4378-9884-a497bbfe125f
fi

echo "==personId=${personId}======"

for file in $(cat faceindex_$1.csv|cut -d',' -f1  |sort |uniq -c  |grep "^\s*"|perl -pe "s|.*images/$1(.*?)\"|images/$1_detected\1|g ");
do
  for bb in $(cat faceindex_$1.csv |grep  "${file##*/}" |perl -pe "s|.*,(\d+),(\d+),(\d+),(\d+)|\3,\4,\2,\1|g")
  do
    echo "========="
    target=$bb
    eretry=1
    while :
    do
      URL="https://api.projectoxford.ai/face/v1.0/persongroups/${personGroupId}/persons/${personId}/persistedFaces?targetFace=${target}"
      faceId=$(curl -X POST "$URL" \
      -H "Content-Type: application/octet-stream" \
      -H "Ocp-Apim-Subscription-Key: ${FaceAPIKey}" \
      --data-binary @./${file} \
      )
      if [ ! -z "$(echo $faceId |grep RateLimitExceeded)"  ]
      then
        eretry=$(expr "$eretry" + "$eretry" )
        echo "retry ${eretry} sec ago"
        sleep ${eretry}
        continue
      fi
      echo "$file,$faceId,$bb" >> registIndex_$1.csv
      break;
    done
    sleep ${eretry}
  done
done

```

実行すると下記のようなログが出力されます。
![images_learn.png](https://qiita-image-store.s3.amazonaws.com/0/33021/86840749-9d26-5552-8608-333998105f6c.png)

# 学習を開始する
1.画像の学習を開始させます。
[ProjectOxford API Reference](https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395249/console)でPersonGroup-TrainPersonGroupを開き、
「personGroupId」と「Ocp-Apim-Subscription-Key」とを入力してSendをクリックします。
202 Acceptedが帰ってきていれば成功です。
![TrainPersonGroup1.png](https://qiita-image-store.s3.amazonaws.com/0/33021/f6d2e148-5706-abef-464a-43b8841c25fc.png)
![TrainPersonGroup2.png.png](https://qiita-image-store.s3.amazonaws.com/0/33021/aa391ba3-dc92-85ed-7e4b-2ccfc6fbd290.png)

2.学習の結果を確認します。
同じく[ProjectOxford API Reference](https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395249/console)でPeronGroup-GetPersonGroupTrainingStatusを開き「personGroupId」と「Ocp-Apim-Subscription-Key」を入力してSendをクリックします。

![GetPersonGroupTrainingStatus1.png](https://qiita-image-store.s3.amazonaws.com/0/33021/ca90df4e-e7df-4f08-85ae-1fc5eb8bcab2.png)
![GetPersonGroupTrainingStatus2.png.png](https://qiita-image-store.s3.amazonaws.com/0/33021/132646dd-dc76-e5b9-caec-c32ad728133f.png)

家族の写真を全部で600枚（子供は200枚、大人は100枚）ほど登録していますが、
約1分程度でステータスはSucceededになりました！

# 検証する
家族を見分けられるかのテストをします。
家族の名前を引数にしたスクリプトを使います。

```lang:filename
#!/bin/bash
IFS='
'
FaceAPIKey=XXXXXXXXXXXXXXXXXXXXXXX
personGroupId=watanabe-family
personName1="aimi"
personId1=4407ed98-1c5f-4fbd-88cb-1607d747b9df
personName2="masatoshi"
personId2=3ba0b015-eb28-4562-b13d-5a271532226f
personName3="hisako"
personId3=15836868-943f-4ea4-9aa4-da438eaf2d5d
personName4="yushin"
personId4=6e03f5ec-838b-4378-9884-a497bbfe125f

faceId=$(curl -s -X POST "https://api.projectoxford.ai/face/v1.0/detect?returnFaceId=true" \
-H "Content-Type: application/octet-stream" \
-H "Ocp-Apim-Subscription-Key: ${FaceAPIKey}" \
--data-binary @${1} \
| jq -r  .[].faceId)

echo "FACE ID = $faceId"
curl -s -X POST "https://api.projectoxford.ai/face/v1.0/identify" \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: ${FaceAPIKey}" \
--data-ascii "{\"personGroupId\":\"${personGroupId}\",\"faceIds\":[\"${faceId}\"],\"maxNumOfCandidatesReturned\":1 }" \
| jq -r '.[].candidates[] |[.personId,.confidence] | @csv' \
|perl -pe "s/${personId1}/${personName1}/g; s/${personId2}/${personName2}/g; s/${personId3}/${personName3}/g; s/${personId4}/${personName4}/g;"

```

実行結果です。それぞれの家族の顔を認証できるようになりました！

```lang:実行結果
Watanabe-Masatoshi-no-MacBook-Pro:Pictures undercurrent$ sh identify.sh images/test/masatoshi.png 
FACE ID = 5c85041a-cca0-4af5-8045-d2eca9989440
"masatoshi",0.83698
Watanabe-Masatoshi-no-MacBook-Pro:Pictures undercurrent$ sh identify.sh images/test/hisako.png
FACE ID = c2d22ce0-1c92-4b80-9dcc-6d63e7928a0e
"hisako",0.83176
Watanabe-Masatoshi-no-MacBook-Pro:Pictures undercurrent$ sh identify.sh images/test/aimi.png
FACE ID = 0684edb7-f2c2-4cc6-9c93-7fd9d97ef4e3
"aimi",0.878
Watanabe-Masatoshi-no-MacBook-Pro:Pictures undercurrent$ sh identify.sh images/test/yushin.png
FACE ID = 600ce343-e76c-4143-a1db-4b25deff5592
"yushin",0.75136

```

以上で、家族の顔写真を認識できるようになりました！
次回はWebカメラで取った写真をProjectOxford FaceAPIに連携して家族と認識させるWindowsアプリを作成します！