Azure Face API で感情認識

最近流行りの AI を試してみました！（遅い

めっちゃ難しそう。。。と、思っていましたが、、、

難しいのは学習モデルとかを自分で構築する事で、
今はいろんな API やらがあるので
試してみる分にはハードルが多少下がりますね？

中でも Microsoft が提供している __Cognitive Services__ の中に
写真の中の顔からその人がどういった感情なのかを検出してくれる API があります。
ので、少し試してみました🤔


## What`s Cognitive Services??

Microsoft が提供している AI の機能が簡単に使えるサービス。
音声とか言語とかいろんなジャンルの AI サービスを利用できる。
SDK もちゃんと用意されているので予備知識とかもなく API をたたくだけで AI が利用できる。
素敵やん...

今回使用するのは Cognitive Services の中でも顔の検出をする __Face API__ です。


### Face API

画像認識の１つ。
画像中のどの範囲が顔で、どんな年齢や性別の人で、今どんな感情なのか、、、みたいな事を検出/数値化してくれる。


- Emotion API
 - 今回試す感情認識はもともと Emotion API として別 API だった物が Face API に統合されたものらしいです。


## システムフロー

1. Android で写真撮影
2. Azure Face API にリクエスト
3. レスポンスをレーダーチャートで表示してみる

的な感じの事をやってみようかと思いました。


## 実装

### Azure アカウントを用意

まずは Azure のアカウントを用意しましょう。

- [Microsoft Azure Portal | Microsoft Azure](https://azure.microsoft.com/ja-jp/features/azure-portal/)

からポータルにサインイン。


### Cognitive Service セットアップ

`追加` から Cognitive Service のリソースを作成します。

![2977e591.png](https://qiita-image-store.s3.amazonaws.com/0/308397/47157d24-7164-c63a-b539-a4933da09fb1.png)

Face API を探し出しましょう。
`作成` って出てきますのでクリック。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/308397/8b50c3d2-3f83-df33-fe68-911218356b34.png)


リソース作成画面が出てきます。

Name は作成する Cognitive Service のリソース名です。
無料試用版で 20 transaction / min まで使えるのでお試しで動かす分には十分でしょう。
リソースグループはお試しなので適当に作成。

設定できたら作成をクリック！
しばらくするとデプロイされるので待ちましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/308397/ca4caa1b-c837-7674-c37b-640de069a6d4.png)

これで Face API を使用する準備が整いました。


### Android から Face API にリクエスト

ここから、Android からリクエストを送る準備です。

Microsoft から SDK が提供されてるのでそれを使います。

```
// for Azure Face API
implementation 'com.microsoft.projectoxford:face:1.4.3'
```

#### クライアント作成

まずはクライアントのインスタンスを用意します。

さっき作ったリソースの `OverView` を表示するとこんな感じ。
ここから `Endpoint` をコピーしておきましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/308397/5cbf28b4-d8f4-d677-bb8d-4e6cb89f8ce7.png)


続いて `Keys` を選択。
右側に作成したリソースのサブスクリプションキーが表示されるのでどっちかをコピー。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/308397/8f39cb5e-4e98-4327-3e0e-be74aa3d65ea.png)


コピーした値を元に Face API のクライアントを作成します。

```
const val API_ENDPOINT = "https://japaneast.api.cognitive.microsoft.com/face/v1.0"
const val SUBSCRIPTION_KEY = "<Your Key>"

// Face API Client
val client = FaceServiceRestClient(API_ENDPOINT, SUBSCRIPTION_KEY)
```

#### リクエスト実行

作成したクライアントに検出用の画像データを渡して検出してもらいます。
検出してほしいパラメータは `AttributeType` で指定しまう。
`Age` とか `Gendar` とか指定すると年齢とか性別とか識別してくれる！すごい！
今回は感情認識試してみたなので `Emotion` をアトリビュートに。

さっき作ったクライアントに対して `detect` ってやると画像から検出してくれます。

```
fun requestEmotions(input: InputStream): Single<Face> {
  // Request Attribute for Emotion
  val attribute = arrayListOf(FaceServiceClient.FaceAttributeType.Emotion)

  val client = FaceServiceRestClient(API_ENDPOINT, SUBSCRIPTION_KEY)

  return Single.just(client)
          .subscribeOn(Schedulers.newThread())

          // detect に画像データを渡すと Face インスタンスの配列が返ってくる
          .map{ it.detect(
              input, // 画像データ(InputStream)
              true, // Request ID
              false, // Landmarks????
              attribute // Request Attribute
          ) }

          // 結果は List で返ってくる
          .map{ it[0] }
          .doOnSuccess { dumpEmotion(it) }
}
```

返ってきた Face インスタンスの中にさっき Attribute で指定したパラメータが入ってます。

全 8 パラメータが返って来ます。
割合になってるので、全パラメータの値を合計すると 1 になります。

```
fun dumpEmotion(result: Face) {
  Log.d("Face API", "-------------- Emotion API --------------")

  // 第二引数を true にしてたら ID が返ってくる
  Log.d("Face API", "ID : " + result.faceId)

  result.faceAttributes.emotion.apply {
      Log.d("Face API", "anger : $anger") // 怒気
      Log.d("Face API", "contempt : $contempt") // 軽蔑
      Log.d("Face API", "disgust : $disgust") // 嫌悪感
      Log.d("Face API", "fear : $fear") // 恐怖
      Log.d("Face API", "happiness : $happiness") // 幸福
      Log.d("Face API", "neutral : $neutral") // 真顔
      Log.d("Face API", "sadness : $sadness") // 悲壮感
      Log.d("Face API", "surprise : $surprise") // 驚き
  }

  Log.d("Face API", "-----------------------------------------")
}
```

一応 `faceRectangle` から顔の範囲も取得できます。


後は画像を撮影してこのリクエストに繋いで結果を表示！！

・・・する予定ですが長くなるので割愛します😋
べ、べつにめんどくさくなったとかじゃないんだかr(

誰かこのパラメータの素敵な使い方教えてください。。。


試しにこんな画像送ってみたらこんな感じでレスポンスが来ました。

<img width="768" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/308397/7d06ce8e-96a6-a8e4-06a4-a7a63f5c1550.png">


```
 -------------- Emotion API --------------
ID : be5cb8c1-fac0-4cb3-9f9a-2821dae86bed
anger : 0.0
contempt : 0.0
disgust : 0.0
fear : 0.0
happiness : 1.0
neutral : 0.0
sadness : 0.0
surprise : 0.0
```

めっちゃ笑顔ですね！！すてき！！


## 感想

色々試してみた感じバランスよくパラメータが返って来ることがなさそう。
パラメータどうしで相関関係がありそう。
複数人の顔があってもちゃんと検出してくれるのすごいなぁって思いました。


以上、 Android からの Face API の感情認識の使い方になります。
Let's 変顔！！


## 参考

[チュートリアル: Android SDK を使用して画像内の顔を検出し、フレームに収める - Azure Cognitive Services | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/tutorials/faceapiinjavaforandroidtutorial)