かれ4

かれこれ4個目のブログ

Azure Advent Calendar - 三倉姉妹(マナカナ)をAzureを使って見分ける

Microsoft Azure Advent Calendar 2015 の20日目の記事です。


今回はProject Oxfordを使って三倉姉妹(マナカナ)の判別を行いたいと思います。

三倉姉妹とは?

三倉姉妹とは、三倉茉奈三倉佳奈の双子の女優・タレント・歌手です。
通称マナカナと呼ばれている人たちです。

「左がマナで、右がカナ。」という言葉が出来るほどに判別は難しく、人類がこれまで幾度と無く挑戦し失敗し諦めてきた大きな課題です。



準備としては、
まずBing Search APIを利用してマナカナの画像を集め、
blog.tottokug.com
Project OxfordのFace APIを使ってかおの画像を切り出しました。
blog.tottokug.com

今日はついにマナカナを判別する所を実装していきます。

実装するは言い過ぎました。実装は特にしません。

Project Oxfordの機能を使って、

といった感じに、Face APIに全てを任せます。

マナカナ判別用教師データの作成。

今回使うのもProject OxfordのFace APIです。
Face APIを使いはじめるところまでは、前回のマナカナの画像からProejctOxfordとimagemagickで顔を切り出す。 - かれ4で書いた通りで、
今回はここからさらにマナカナをマナとカナに分類することをしていきます。

今回は顔を切り出す必要はないので、ImageMagickは使わずにただBounding Boxを一覧化するところまでをおこえば良いのかなと。
気をつけないと行けないのはfaceAPIは秒間1回くらいの利用しか認めておらず、それを超えるとエラーが帰ってくるので要注意です。
なので、sleep 1などを入れて1秒待機させる事にすると回避出来るので、スリープはぜひ入れましょう。

#!/bin/bash
IFS='
'
APIKey=***************************************
[ -d images/detected ] || mkdir -p images/detected
for f in $(find ./images/manakana -type f);
do
  curl -X POST  -H "Content-Type: application/octet-stream" --data-binary @${f} \
  "https://api.projectoxford.ai/face/v0/detections?subscription-key=${APIKey}"  \
  |jq -r ".[]  | [\"$f\",.faceId,.faceRectangle.width,.faceRectangle.height,.faceRectangle.left,.faceRectangle.top] | @csv"  >> faceindex.csv
  mv "${f}" images/detected/
 sleep 1
done

これで faceindex.csvに下記のような

画像ファイル名,faceId,幅,高,x,y

という形式でのCSVファイルが吐き出せました。

"./images/manakana/00011738_02A.jpg","a6415064-2720-4c84-8dff-7701f006f36d",81,81,123,93
"./images/manakana/00011738_02A.jpg","3d957436-a206-4d78-839a-bc0174345f77",77,77,546,144
"./images/manakana/00011738_02A.jpg","2bf5f7dd-c9c5-45e5-acab-6a58b13da0ad",75,75,415,136
"./images/manakana/000504.jpg","0913d773-c52f-45f4-8dce-16ba86b26d42",115,115,28,75
"./images/manakana/001-199x300.jpg","94f18b64-1faf-425f-a064-1a203b8c4140",42,42,87,26
"./images/manakana/001-199x300.jpg","fc8407f4-4722-4e58-ad10-f5e1d1efb733",39,39,34,54
"./images/manakana/001.jpg","87de0b21-ee19-4072-bf7d-b6d14895578c",76,76,96,104
"./images/manakana/0014d0d9.jpg","ca4d66a1-2243-44ac-b084-c1703d419ff6",133,133,145,368
"./images/manakana/0014d0d9.jpg","7a71404c-81b3-4562-8f24-3d78e455b480",122,122,419,370
"./images/manakana/001l.jpg","a967b8e8-a50d-43be-beb7-5d718e0577bd",90,90,199,89

この処理はスリープが入っているので、時間がかかります。
待っている間に、先にPersonGroupの作成とPersonの作成をしてしまいます。
どちらも、繰り返し行う動作ではないのでブラウザでさくっとやってしまいます。
API Referenceから実行出来るようになっているので、そこから実行します。
最近API Referenceから実行出来るようなのが増えていますね。


Person Groupの作成

f:id:tottokug:20151220231830p:plain

f:id:tottokug:20151220231834p:plain

Person の作成

f:id:tottokug:20151220231418p:plain
f:id:tottokug:20151220231421p:plain
f:id:tottokug:20151220231436p:plain

Personができていることの確認

f:id:tottokug:20151220231438p:plain
f:id:tottokug:20151220231442p:plain


学習させる

ここまでで準備は整ったので、ついに学習させていくことになります。
学習させるためには、Face APIのPersonにあるAdd Faceを利用してまずは顔を登録していきます。
今回は顔を検出した結果、2人で写っているものだけを学習用に使い、1人もしくは3人以上で写っている画像を検証用に使います。

2人で写っているものを使う理由として、マナカナには「左:マナ、右:カナ」というルールがあるためです。
ここが今回一番大切な所です。
他にもカナの左目の下にほくろがあるとか、鼻の穴の角度が違うとかそんな見分け方も有りますが、それは今回は使いません。

大切な事なので、もう一度。
「左がマナで、右がカナです。」

言い換えると、Bounding BoxのLeftの値が小さい方がマナ、大きい方がカナです。
というわけで、2人で写っている画像を探し出してきてその画像と一緒に、顔の位置の情報を送ります。


#!/bin/bash
IFS='
'
APIKey=**************************************
personGroupId="manakana"
mana="4314b829-559c-4350-81d5-7bb24b4041e7"
kana="6eb1744b-a7e6-4782-acb4-6a35ec74a8a1"

for file in $(cat faceindex.csv|cut -d',' -f1  |sort |uniq -c  |grep "^\s*2"|perl -pe "s|.*images/manakana(.*?)\"|images/detected\1|g ");
do
  personId=$mana
  for bb in $(cat faceindex.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: ${APIKey}" \
      --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.csv
      break;
    done
    personId=$kana
    sleep ${eretry}
  done
done

ここで指定している

mana="4314b829-559c-4350-81d5-7bb24b4041e7"
kana="6eb1744b-a7e6-4782-acb4-6a35ec74a8a1"

はpersonを作った時に付与されたPersonIdになっています。
また、このAPIは1秒のSleepを入れても、RateLimitExceededが出てしまうので、出てしまった場合は1秒、2秒、4秒と増やしながらリトライする処理が入っています。
ひとまずこれで顔の登録が完了しました。

学習の開始

学習の開始は非常に簡単です。
これも繰り返し行う動作ではないのでブラウザ上で行ってしまいます。
https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395249/console
こちらから
personGroupIdを指定してsendで完了です。
f:id:tottokug:20151221005302p:plain
Queueに登録するだけなので、202 Acceptedが帰ってきていれば成功です。
f:id:tottokug:20151221005733p:plain

学習の結果確認

こちらも繰り返し行うものではないので、ブラウザ上で確認します。
f:id:tottokug:20151221005736p:plain

f:id:tottokug:20151221005739p:plain

無事に成功しているようです。
今回顔画像をそれぞれ250枚ほど登録していますが、
約1分程度でステータスはSucceededになっていました。

検証

それではドキドキのマナカナが見分けられるかどうかのテストになります。

テストにはファイルを指定して、そのままどっちなのか判定出来るように以下のスクリプトを使います。

#!/bin/bash
IFS='
'
APIKey=****************************************

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: ${APIKey}" \
--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: ${APIKey}" \
--data-ascii "{\"personGroupId\":\"manakana\",\"faceIds\":[\"${faceId}\"],\"maxNumOfCandidatesReturned\":1 }" \
| jq -r '.[].candidates[] |[.personId,.confidence] | @csv' \
|perl -pe "s/4314b829-559c-4350-81d5-7bb24b4041e7/mana/g; s/6eb1744b-a7e6-4782-acb4-6a35ec74a8a1/kana/g"

マナの判定

ではまずは、こちらの画像から
f:id:tottokug:20151221012106j:plain

$ ./identify.sh images/detected/mikuramana.jpg
FACE ID = efd9608a-b6ff-47a9-84cc-4107f9789d2d
"mana",0.6302

無事にmanaと判定されました。

カナの判定

次に,この画像から、kanaと判別されれば成功です。

f:id:tottokug:20081227164536j:plain

$ ./identify.sh images/detected/kana.jpg
FACE ID = 6ff3601d-a2f6-4ba5-81e0-0e6a39df2a16
"kana",0.73804


無事に認識されました。


これで、マナカナを見分ける事が出来るようになりました。