Microsofrt AzureのFace APIを使って笑顔をAIに判断してもらおう

MS Azure の Cognitive Services の一つ、Emotion API を利用して笑顔をAIに判定してもらう記事があったので
実際にやってみようと思ったのですがEmotion API が一般提供の Face API に感情認識機能が統合されたようなのでFace APIで同じように笑顔を判定してみました。
そのときのメモです。

#Face APIとは
Face APIとは画像に映っている人物の顔を認識して、年齢、性別、表情、髭の有無などの特徴を出すもの(Face Detection)です。他にも2つの顔が同一人物の物である確率を検証すること(Face Recongnition)ができます。

Face API - 顔認識 | Microsoft Azure
https://azure.microsoft.com/ja-jp/services/cognitive-services/face/

# Face APIを使えるようにしよう

Face APIはMS AzureのCognitive Servicesの一つなのでAzureのアカウントを作成します。

作成できたらログイン後にAzureのダッシュボードから[リソースの作成]を選び
検索から"Face"と入力。[Face API]を選択。

<img src="https://qiita-image-store.s3.amazonaws.com/0/255352/34b38d91-aca4-862b-7ee5-fb2b14c357b9.png" width=40%>

<img src="https://qiita-image-store.s3.amazonaws.com/0/255352/7310c411-47fa-67c8-71ae-d51379f506c2.png" width=80%>

<img src="https://qiita-image-store.s3.amazonaws.com/0/255352/4e75aeec-2fa3-fd8a-7a05-ca1b996ba4c8.png" width=80%>

<img src="https://qiita-image-store.s3.amazonaws.com/0/255352/096a778d-02d6-0257-bb39-63775a2ad3ba.png" width=40%>
[作成]ボタンをクリック。

<img src="https://qiita-image-store.s3.amazonaws.com/0/255352/db7b4160-180e-75d8-1674-bd13a977ff66.png" width=30%>
各設定項目を入力、選択して[作成]
※価格レベルは、サンプルデモ用なのでF0を選択

<img src="https://qiita-image-store.s3.amazonaws.com/0/255352/3aa6fcce-6356-a0dd-5f66-7e83c5848d71.png" width=40%>
Face APIがデプロイされるので、[Keys]よりAPIキーを取得します。

#Face APIを使ってみる
アプリを作る前に手っ取り早くcURLを使って実行してみます。

```
$ curl -v -X POST "https://westcentralus.api.cognitive.microsoft.com/face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise" \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: {subscription key}" \
--data-ascii '{"url":"{人間の表情が写っている写真のURL}"}'

```
※{subscription key} の部分は取得したキー

ターミナルから下記のような結果が返ってきます。

```
* About to connect() to eastasia.api.cognitive.microsoft.com port 443 (#0)
*   Trying 13.94.26.39...
* Connected to eastasia.api.cognitive.microsoft.com (13.94.26.39) port 443 (#0)
・・・（略）

* Connection #0 to host eastasia.api.cognitive.microsoft.com left intact
[{"faceId":"c2e62fe6-6692-4d85-9672-0bc07cc64525","faceRectangle":{"top":45,"left":138,"width":173,"height":173},"faceAttributes":{"smile":0.734,"headPose":{"pitch":0.0,"roll":2.7,"yaw":3.8},"gender":"female","age":2.0,"facialHair":{"moustache":0.0,"beard":0.0,"sideburns":0.0},"glasses":"NoGlasses","emotion":{"anger":0.061,"contempt":0.0,"disgust":0.0,"fear":0.008,"happiness":0.734,"neutral":0.0,"sadness":0.12,"surprise":0.077},"blur":{"blurLevel":"low","value":0.0},"exposure":{"exposureLevel":"goodExposure","value":0.72},"noise":{"noiseLevel":"low","value":0.0},"makeup":{"eyeMakeup":false,"lipMakeup":false},"accessories":[],"occlusion":{"foreheadOccluded":false,"eyeOccluded":false,"mouthOccluded":false},"hair":{"bald":0.85,"invisible":false,"hairColor":[]}}}]

```
JSONの中身は下記のような情報です。

|JSON項目|値|説明|
|:----|:----|:----|
|faceId|c2e62fe6-6692-4d85-9672-0bc07cc64525|Face Recongnition など認識結果を別のAPIで使用するためのID。解析してから24時間有効|
|faceRectangle|{"top":131,"left":177,"width":162,"height":162}|検出した顔の座標|
|faceAttributes|{"smile":0.0,"headPose":{"pitch":0.0,"roll":0.1,"yaw":-32.9}|笑顔のスコア、顔の傾き|
|gender|female|性別|
|age|22.9|年齢|
|facialHair|{"moustache":0.0,"beard":0.0,"sideburns":0.0}|顔の髪(口ひげ、あごひげ、ほおひげ)|
|glasses|NoGlasses|眼鏡をかけているか|
|emotion|{"anger":0.0,"contempt":0.0,"disgust":0.0,"fear":0.0,"happiness":0.0,"neutral":0.986,"sadness":0.009,"surprise":0.005}|感情(怒り、恥ずかしい、うんざり、恐怖、幸せ、無表情、悲しみ、驚き)|
|blur|{"blurLevel":"low","value":0.06}|霞み具合|
|exposure|{"exposureLevel":"goodExposure","value":0.67}|露出度|
|noise|{"noiseLevel":"low","value":0.0}|ノイズレベル|
|makeup|{"eyeMakeup":true,"lipMakeup":true}|化粧をしているか(アイメイク、唇)|
|accessories|[]|アクセサリを付けているか|
|occlusion|{"foreheadOccluded":false,"eyeOccluded":false,"mouthOccluded":false}|顔を塞いでいるか(額、目、口)|
|hair|{"bald":0.0,"invisible":false,"hairColor":[{"color":"brown","confidence":1.0},{"color":"black","confidence":0.87},{"color":"other","confidence":0.51},{"color":"blond","confidence":0.08},{"color":"red","confidence":0.08},{"color":"gray","confidence":0.02}]}|髪の毛(ハゲ度合、見えないか？、髪の色・茶/黒/他/金/赤/灰の各信頼度)|

#アプリを作ってみる
MSの[Code samples](https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/quickstarts/javascript)よりJavaScriptで作成

Azure への画層送信やサムネイルの表示など、画像の各種処理には jQueryを使用
**※サンプルということで、APIキーを直接html内に書く形にしていますが、APIキーが視認できる状態は危険です。実際にはやらないでください。第三者に勝手に使われる可能性があります 。**

```
<!DOCTYPE html>
<html lang="ja">
<head>
  <title>Detect Faces Sample</title>
  <meta charset="utf-8">
  <meta content="width=device-width, initial-scale=1" name="viewport">
</head>
<body>
  <div class="container" id="container">
    <h2>Detect Faces:</h2>
    <div id="message"></div>
    <div id="content">
      <p><input id="fileToUpload" name="upload" type="file"></p>
      <textarea id="responseTextArea" class="UIInput" style="width:580px; height:400px;"></textarea>
    </div>
  </div>
  <script src="https://code.jquery.com/jquery-2.1.4.min.js">
  </script> 
  <script>

    var html = '';

    $(function() {

       $('input[type=file]').after('<span id=\"image\"><\/span>');

       $('input[type=file]').change(function() {

         var subscriptionKey = "{subscription key}";

         var uriBase = "https://eastasia.api.cognitive.microsoft.com/face/v1.0/detect";

         var params = {
             "returnFaceId": "true",
             "returnFaceLandmarks": "false",
             "returnFaceAttributes": "age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise",
         };

         var file = $(this).prop('files')[0];

         if (!file.type.match('image.*')) {
           $(this).val('');
           $('span').html('');
           return;
         }

         var reader = new FileReader();

         reader.onload = function() {
           var img_src = $('<br><img height=\"300\">').attr('src', reader.result);
           $('span').html(img_src);
         }
         reader.readAsDataURL(file);

         $.ajax({
             url: uriBase + "?" + $.param(params),
             beforeSend: function(xhrObj){
                 // Request headers
                 xhrObj.setRequestHeader("Content-Type","application/octet-stream");
                 xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key",subscriptionKey);
             },
             type: "POST",
             data: file,
             processData: false,
         })
         .done(function(data) {

         $("#responseTextArea").val(JSON.stringify(data, null, 2));

       })
       .fail(function() {
           alert("error");
       });
     });
    });
  </script>
</body>
</html>

```

#スマホアプリ化する
上記のコードを元に、[Monaca](https://ja.monaca.io/)でスマホアプリ化します。
[Monaca](https://ja.monaca.io/)は、スマートフォンアプリ開発のフレームワークです。
HTML5とJavaScriptを用いることで、スマホアプリが開発できます。

また、結果については幸せな笑顔なのかチェックできるようにちょっと変更。
返り値のJSONから「hapiness」の値を抽出。hapiness値が高い= 幸せ笑顔、として判断。

```
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsaf
e-eval'">
  <script src="components/loader.js"></script>
  <script src="lib/onsenui/js/onsenui.min.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
  <div class="container" id="container">
    <h2>笑顔判定</h2>
    <div id="message"></div>
    <div id="content">
      <p><input id="fileToUpload" name="upload" type="file"></p>
    </div>
  </div>
  <script src="https://code.jquery.com/jquery-2.1.4.min.js">
  </script>
  <script>
    var html = '';

    $(function() {

      $('input[type=file]').after('<span id=\"image\"><\/span>');

      $('input[type=file]').change(function() {

        var subscriptionKey = "{subscription key}";
        var uriBase = "https://eastasia.api.cognitive.microsoft.com/face/v1.0/detect";

        var params = {
             "returnFaceId": "true",
             "returnFaceLandmarks": "false",
             "returnFaceAttributes": "age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise",
         };

        var file = $(this).prop('files')[0];

        if (!file.type.match('image.*')) {
          $(this).val('');
          $('span').html('');
          return;
        }

        var reader = new FileReader();

        reader.onload = function() {
          var img_src = $('<br><img height=\"300\">').attr('src', reader.result);
          $('span').html(img_src);
        }
        reader.readAsDataURL(file);

        $.ajax({
          url: uriBase + "?" + $.param(params),
          beforeSend: function(xhrObj){
            // Request headers
            xhrObj.setRequestHeader("Content-Type","application/octet-stream");
            xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key",subscriptionKey);
          },
          type: "POST",
          data: file,
          processData: false,
        })
        .done(function(data) {
          var smileScore = data["0"].faceAttributes.emotion.happiness;

          if(smileScore > 0.9) {
            var message = "笑顔度１００％！　最高の笑顔です";
          }

          if(0.8 <= smileScore && smileScore <= 0.9) {
            var message = "笑顔度８０％！　もう少し！";
          }

          if(smileScore < 0.8) {
            var message = "笑顔かな・・・笑顔ですね";
          }

          alert(message);

        })
        .fail(function() {
          alert("error");
        });

      });
    });
  </script>
</body>
</html>

```

#触ってみて
非常に簡単にAIを使って感情認識ができることがわかったのでメガネ(AR)なのでリアルタイムに感情がわかると
接客などに使えるのではないかと思ったり思わなかったり。

Azureには他にもAIを使った画像判定するAPIがあるので面白いアイデアが思いついたらまた試作してみたいと思います(笑)