集合写真のメガネの数をカウントする

こんな話がある。

実際、昨晩開催されたGlobal TokyoRの集合写真においてもメガネが目立つ(ゲストスピーカーのHenningさんの記事参照)。
https://henningsway.github.io/post/2017-04-01-tokyo-r/

ということで集合写真からメガネ着用率を算出したい。
今回はMicrosoft Face APIを用いて集合写真から顔検出&メガネ着用の有無を判定したいと思う。
以下のステップで進める。

  • ローカルの画像を画像サーバ(imgur)にアップロードする
  • 画像をMicrosoft FACE APIにPOSTして結果を取得する
  • 結果を集計する

ローカルの画像を画像サーバ(imgur)にアップロードする

上記サイトの集合写真をFace APIにそのまま送ると、一つ一つの顔が小さすぎて顔検出に失敗する。
したがってローカルにいったんダウンロードし、引き延ばした画像を用いることにする。
ただし、Face APIはウェブ上の画像を対象としているため、ローカルの画像についてはいったんどこかの画像サーバにアップロードする必要がある(追記)指定を変えることで画像サーバにアップロードする必要はないとのこと。詳しくはuriboさんの記事を参照ください。
今回は一時的にimgurにアップロードしてメガネ着用率を算出後に消去することにする。
imgurにはimguRパッケージを用いてアップロードする。
結果のlinkにアップロード先のURLが格納されている。

# ローカルの画像を画像サーバ(imgur)にアップロードする
library("imguR")
tmp <- "oretachinoglobalr.png" # 引き延ばした画像
res_upload <- upload_image(tmp) 
url_image <- res_upload$link

画像をMicrosoft FACE APIにPOSTして結果を取得する

先の画像URLをMicrosoft FACE APIにPOSTして、結果を取得する。
この際、Subscribe Keyが必要なので取得しておいてほしい。
このあたりの記事を参照のこと。
POSTにはhttrパッケージを用いる。

# 画像をMicrosoft FACE APIにPOSTして結果を取得する
library("httr")
MS_FACE_KEY <- "取得したSubscribe Key"
url_request <- "https://westus.api.cognitive.microsoft.com/face/v1.0/detect?returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion"
body <- list(url=url_image)
res <- POST(url=url_request,
            encode="json",
            body=body,
            add_headers(`Ocp-Apim-Subscription-Key`=MS_FACE_KEY),
            content_type_json()
)
res <- content(res)

結果を集計する

結果はcontent()でJSONからRのリストに変換されている。
この結果を集計する。
集計後はアップロードした画像を消去する。
この際、imguRパッケージのdelete_image()にdeletehashを指定する。

# リストで返ってくる結果を集計する
count_megane <- table(unlist(lapply(res,function(x)x$faceAttributes$glasses)))
# アップロードした画像を消去する
delete_image(res_upload$deletehash)

結果は以下の通り。
Face APIではメガネとして noGlasses、readingGlasses、sunglasses、swimmingGoggles の4つを判定可能である。
メガネ着用率は43.8%という結果になった。
この数字が高いか低いかわからないので、外国の集合写真などと比較してみる必要があるだろう。がんばってほしい。

> count_megane

     NoGlasses ReadingGlasses 
            18             14 
> round(prop.table(count_megane) * 100, 1)

     NoGlasses ReadingGlasses 
          56.2           43.8

まとめると、以下のようなコードになる。

# ローカルの画像を画像サーバ(imgur)にアップロードする
library("imguR")
tmp <- "oretachinoglobalr.png" # 引き延ばした画像
res_upload <- upload_image(tmp) 
url_image <- res_upload$link

# 画像をMicrosoft FACE APIにPOSTして結果を取得する
MS_FACE_KEY <- "取得したSubscribe Key"
url_request <- "https://westus.api.cognitive.microsoft.com/face/v1.0/detect?returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion"
body <- list(url=url_image)
res <- POST(url=url_request,
            encode="json",
            body=body,
            add_headers(`Ocp-Apim-Subscription-Key`=MS_FACE_KEY),
            content_type_json()
)
res <- content(res)
count_megane <- table(unlist(lapply(res,function(x)x$faceAttributes$glasses)))

# アップロードした画像を消去する
delete_image(res_upload$deletehash)

count_megane
round(prop.table(count_megane) * 100, 1)

余談だが、当初はGoogle Cloud Vision APIでやろうかと思っていた。
しかしメガネの着用有無が判定できないのでやむなくMicrosoft FACE APIを用いた。

Enjoy!