Face APIを使って怒りアラートを作った #FaceAPI #感情分析

##WEB会議で怒っているように思われる
もしかして怒ってます？
最近、言われたショックな言葉です。
コロナ禍が始まり、在宅勤務が多くなってきたので社内の会議はWEB会議がほとんどです。わが社ではカメラオンにする人が少なく、基本的には全員アイコンの状態で喋っています。
そんな中で言われたのがこの一言でした。

自分ではあまり怒ることはなく、たまに”イラっ”としても表に出ていると思っていなかったのですが、
残念ながら声にでてしまっているようなのです。もしかしたら表情にも出ているかもしれません。。。。

意識していないところで実は感情があらわになっていることが今回のことでわかりました。
対面なら相手の表情から気づくこともできるかもしれませんが、WEB会議＆カメラオフだとなかなか気づくことができません。

というわけで、**客観的に自分の表情を観測して怒りを感じ取ったらアラートを上げる仕組み**を作って、**人に言われる前に自分で気づける状態を目指しました。**


##完成品
WEBアプリとして作成しました。
携帯のインカメで顔の画像を取得してFace APIに送ってスコアを取得します。
<font color="Red">**"anger"の値が一定値を越えたら、背景を赤くしてアラートを上げる**</font>ことにしました。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143015/8db2c360-d400-6bfe-db6e-65d3225aa239.png)



##利用シーン
こんな感じです。アプリを起動した状態の携帯を置いてWEB会議に参加して、<font color="Red">**画面が赤くなったら注意。**</font>という使い方です。
思ったより目立つのでアラートが出たらすぐに気づくことができそうです。
**これで相手に不快感を与える前に取り繕うことができるはず！**
![IMG_6129.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143015/4fcb6d5e-ad10-67c4-baf3-ea9efea94ed3.jpeg)


##チャート機能もある
せっかくスコアをリアルタイムで取得するので、チャートもリアルタイムで作成されるようにしました。
Face APIで取得できる情報は８種類（怒り・軽蔑・嫌悪・恐れ・喜び・中性・悲しみ・驚き）あるのですが、その中から怒り・喜び・悲しみの３つをピックアップしてチャート化しています。
どの時間にどんな気持ちだったかを振り返ることができるので、
**ライフログならぬメンタルログとしてココロのケアに使えるのでは？**と思います。
ビッグデータ化して何かに活用できないだろうか。。。



![cha.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143015/f1dd2195-17d1-40d2-3ab3-5d7c328f19eb.png)

チャートの表示にはchart.jsを使用しています。こちらの記事を参考にさせていただきました。

https://qiita.com/Haruka-Ogawa/items/59facd24f2a8bdb6d369


##ソース
CODEPENで作成したのでソース置いておきます。
Face APIのキーとエンドポイントを入力すればそのまま使えると思います。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="WNXEpqp" data-user="tishiyama" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/tishiyama/pen/WNXEpqp">
  faceAPI</a> by tishiyama (<a href="https://codepen.io/tishiyama">@tishiyama</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


##嵌ったところ

・画像データをFace APIに送るところで嵌りました。データ形式を変換するところが今もよくわかりません。
以下の記事を見て何とか動かすことができました。

https://qiita.com/hidao/items/8797cae9bf1e1a2a376e


```01.js

    const canvas = document.getElementById("mycanvas");
    // canvasへ描画するための「コンテキスト」を取得
    const context = canvas.getContext("2d");
    // コンテキストに対してvideoのデータを書き込むことで、canvasへ反映
    context.drawImage(video, 0, 0);
    // imgタグを取得
    const img = document.getElementById("myimg");
    // imgのsrc属性に、canvasの中身から変換したデータURL（URLっぽいが実体は生データ）をセット
    img.src = canvas.toDataURL();

    // DataURL形式の画像データをバイナリを扱えるデータ形式blobに変換する
    // この辺はコピペなので詳しくは調べてね
    const type = img.src.slice(5, img.src.indexOf(";")); // DataURLからファイルタイプを取得
    const bin = atob(img.src.split(",")[1]);
    const buffer = new Uint8Array(bin.length);
    for (var i = 0; i < bin.length; i++) {
      buffer[i] = bin.charCodeAt(i);
    }
    const blob = new Blob([buffer.buffer], { type: type });

    //取得したデータをfaceapiに送る
    const subscriptionKey = "";
    const uriBase = "";
    // APIの引数をGETパラメータで渡す
    // いらない情報はもらわない
    const params =
      "returnFaceId=false" +
      "&returnFaceLandmarks=false" +
      "&returnFaceAttributes=emotion";
    //"age,gender,headPose,smile,facialHair,glasses,emotion," +
    //"hair,makeup,occlusion,accessories,blur,exposure,noise";

    fetch(uriBase + "?" + params, {
      headers: {
        "Content-Type": "application/octet-stream",
        "Ocp-Apim-Subscription-Key": subscriptionKey
      },
      method: "POST",
      body: blob
    })

```



・チャートの更新で次に嵌りました。
Face APIのスコアが配列にたまっていくのでチャートボタンを押したら随時更新ができるようにしました。
最初は、以下のような既に描画済みの場合は削除して作り直すようにしていたのですがうまくいかず、
if(myLineChart){
   myLineChart.destroy();
}
new Chartを何度も実行するのがよろしくないようだったので、
myLineChart.update();
を使うことで解決しました。

```02.js

//チャート作成
var ctx = document.getElementById("myLineChart").getContext("2d");
var myLineChart = new Chart(ctx, {
  type: "line",
  data: {
    labels: date,
    datasets: [
      {
        label: "怒り",
        data: anger,
        borderColor: "rgba(255,0,0,1)"
      },
      {
        label: "幸福",
        data: happiness,
        borderColor: "rgba(0,200,0,1)"
      },
      {
        label: "悲しみ",
        data: sadness,
        borderColor: "rgba(0,0,255,1)"
      }
    ]
  },
  options: {
    title: {
      display: true,
      text: "メンタルログ"
    }
  }
});
//チャート描画
function chart() {
  myLineChart.update();
}

```


##Face API
このアプリは会議中は使用し続けることになり、怒りなどの瞬間的な表情を評価することになるので、実行頻度は細かく設定しないいけません。
Cognitive Servicesの価格レベルは「Free」を使用しているので、
１分あたり２０回前＝３秒に１回までとなります。５秒で設定しましたが問題なさそうでした。
更に１か月3万回までという制限があります。30000×5秒＝2500分＝41時間までになります。
”怒りアラート”として会議中に使う分には問題なさそうですが、メンタルログの取得で使うには取得間隔を伸ばしたりする必要がありそうです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143015/9afcd612-3e7e-2452-2db7-a4bc472c44f2.png)



##使ってみた
実際に、仕事のＭＴで使ってみました。
その結果のチャートが次の通りです。カウンターはFace APIで判定した回数です。
![Screenshot_20220214-172525_Internet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143015/4d0fe668-6d59-5297-299e-4f1f14187d7f.jpeg)

普通の表情だと、中性（neutral）として判定され、基本的にこの数値が大きい状態になります。
微妙な表情の動きがさほど数字として表れず、「怒り・幸福・悲しみ」はほぼ0.1以下の数字で推移します。

今回は特に“イラっ”とすることもなかったので怒りの数字は小さい結果となりました。途中笑ったりしたときは、幸福の値が上がっていますが、数字としては0.5未満となっています。**私の顔だと、自然の笑顔だと0.5未満になるようでした。**

別の人で試したら、普通の笑顔で1.0近いスコアになったりもしたので、
**人によって数値の出方が違うので、判定する場合はその人向けにカスタマイズが必要そうです。**

今回の”怒りアラート”は怒りが0.5以上でアラートを出すことにしています。
実際に0.5以上の数字を出そうとすると、**露骨に怒っている顔をしなければならず、ＭＴ中に流石にこの顔には何らない。**と思いました。

今後、継続的に使っていくには継続的に計測して妥当な値に設定を変更していく必要がありそうです。
引き続きＭＴ中に試用、調整を繰り返し、”温厚なtishiyamaさん”と言われるように精進していこうと思います。