UnityからRekognitionを使ってみた

##R&D成果発表会Vol.2
こんにちは。ノベルワークスR＆Dチームのともやんです。
今回はUnityと表情分析でうにゃうにゃした際の報告です。
この記事がVol.100くらいになるころには、なにかおもしろいものがお目見えしているかもしれません。
それでは早速！

##Amazon Rekognitionとは
Amazon　Rekognitionとは、AWSのサービスの一つで、画像や動画を投げると、顔比較や感情分析など高度なことを、簡単に行える便利なものです。今回はこのサービスを使って、感情分析を行っていきます。

##AWS SDK for .Netについて
unityでのAWSSDK導入方法については基本ここ参照。
https://qiita.com/nshinya/items/0a71d4658e7f4a650844

Rekognitionを使いたいので、AWS SDK.Rekognition.dllを入れてください

##やりかた
やり方として
####1.unityでwebカメラを使う
####2.Rekognitionにwebカメラの画像を投げる
####3.返ってきたJson風データから感情値を取り出す
の三つで説明していきます

##完成コード(雑です)

```
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Amazon.Rekognition;
using Amazon.Rekognition.Model;




public class DetectFaces : MonoBehaviour
{
    public RawImage rawImage;

    WebCamTexture webCamTexture;


    //textureをtexture2dにする関数
    public Texture2D ToTexture2D(Texture self)
    {
        var sw = self.width;
        var sh = self.height;
        var format = TextureFormat.RGBA32;
        var result = new Texture2D(sw, sh, format, false);
        var currentRT = RenderTexture.active;
        var rt = new RenderTexture(sw, sh, 32);
        Graphics.Blit(self, rt);
        RenderTexture.active = rt;
        var source = new Rect(0, 0, rt.width, rt.height);
        result.ReadPixels(source, 0, 0);
        result.Apply();
        RenderTexture.active = currentRT;
        return result;
    }





    //Amazon Rekognition
    public async Task Example(Amazon.Rekognition.Model.DetectFacesRequest image)
    {
        //AmazonRekognitionClient
        AmazonRekognitionClient rekognitionClient = new AmazonRekognitionClient("AWSのアクセスキー", "AWSのシークレットキー");

        var response = await rekognitionClient.DetectFacesAsync(image);
        
        
        foreach(var i in response.FaceDetails[0].Emotions)
        {
            Debug.Log(i.Confidence);
            Debug.Log(i.Type);
        }
    }

    

    //start
    public void Start()
    {
        webCamTexture = new WebCamTexture();
        rawImage.texture = webCamTexture;
        webCamTexture.Play();
    }

    public async void UseReko()
    {
        var img2d = ToTexture2D(webCamTexture);
        var img = img2d.EncodeToJPG();
        var stream = new MemoryStream(img);
        List<string> att = new List<string>() { "ALL" };
        var rekoImg = new Amazon.Rekognition.Model.Image { Bytes = stream };
        var reqImg = new DetectFacesRequest {Attributes=att, Image = rekoImg };

        await Example(reqImg);
        
    }

```


##1.Webカメラ
RawImageにwebカメラで取得した画像をはっつけます。顔見たいからです。別に顔を画面で見たくねえよって人はrawImageなんていりません。


```

略

public RawImage rawImage;
WebCamTexture webCamTexture;

略


    public void Start(){
        webCamTexture=new WebCamTexture();
        rawImage.texture=webCamTexture;
        webCamTexture.Play()
    }
}

```

んで、webCamTextreなんですが、これをそのままImageとしてRekognitionに投げるわけにはいきません。
というのも、Amazon.Rekognition.Model.DetectFacesRequestクラスのImageを投げなきゃいけないのです。ということで、
WebCamTexture>Texture2D>JPG形式>MemoryStream>DetectFacesRequestという順序で変換していきます。

####WebCamTexture>Texture2D
WebCamTextureは一見Texture2Dなんですが、残念ながら違うんです。WebCamTextureというクラスなんです。だから、いったんToTexture2D()をつかって変換します。

```
var img2d = ToTexture2D(webCamTexture);
```

####Texture2D>JPG
これも関数一発ドーンってやつです

```
var img = img2d.EncodeToJPG();
```

####JPG>MemoryStream
DetectFacesRequestを作るには、Byte列としてMemoryStreamを作る必要があります。MemoryStreamがなんだかはよくわかっていません。これもドーンです。

```
var stream = new MemoryStream(img);
```
####MemoryStream>DetectFacesRequest
これはnewするときの引き数にMemoryStreamを入れるだけです。

```
var rekoImg = new Amazon.Rekognition.Model.Image { Bytes = stream };
```


これで投げる画像はOKです。あと、どんな情報が返ってくるかの指定として、ALLを指定しておきます。ALLじゃないと感情値とかは返ってきません。

```
List<string> att = new List<string>() { "ALL" };
```

んで最後に

```
var reqImg = new DetectFacesRequest {Attributes=att, Image = rekoImg };
```
というようにRekognitionに投げるものを作ってあげれば終了です。



##RekognitionにWebカメラの画像を投げる

```
AmazonRekognitionClient rekognitionClient = new AmazonRekognitionClient("AWSのアクセスキー", "AWSのシークレットキー");

        var response = await rekognitionClient.DetectFacesAsync(image);

```
ここで、DetectFacesAsync()をつかって投げています。ここで大事なのが、DetectFacesじゃなくてDetectFacesAsyncを使わなくちゃいけないということです。非同期なのでそこら辺のことも書き足さなきゃデス。

Asynchronous operations (methods ending with Async) in the table below are for .NET 4.5 or higher. For .NET 3.5 the SDK follows the standard naming convention of BeginMethodName and EndMethodName to indicate asynchronous operations - these method pairs are not shown in the table below.
（APIリファレンスにちっちゃく書いてある)

きちんとリファレンス読むべきですね。(Asyncないとerrorとしてinaccesible due to のやつが出てきます)




##返ってきたJson風データから感情値を取り出す
返ってくるデータはこんな形です。

```
{
   "FaceDetails": [ 
      { 
         "AgeRange": { 
            "High": number,
            "Low": number
         },
         "Beard": { 
            "Confidence": number,
            "Value": boolean
         },
         "BoundingBox": { 
            "Height": number,
            "Left": number,
            "Top": number,
            "Width": number
         },
         "Confidence": number,
         "Emotions": [ 
            { 
               "Confidence": number,
               "Type": "string"
            }
         ],
         "Eyeglasses": { 
            "Confidence": number,
            "Value": boolean
         },
         "EyesOpen": { 
            "Confidence": number,
            "Value": boolean
         },
         "Gender": { 
            "Confidence": number,
            "Value": "string"
         },
         "Landmarks": [ 
            { 
               "Type": "string",
               "X": number,
               "Y": number
            }
         ],
         "MouthOpen": { 
            "Confidence": number,
            "Value": boolean
         },
         "Mustache": { 
            "Confidence": number,
            "Value": boolean
         },
         "Pose": { 
            "Pitch": number,
            "Roll": number,
            "Yaw": number
         },
         "Quality": { 
            "Brightness": number,
            "Sharpness": number
         },
         "Smile": { 
            "Confidence": number,
            "Value": boolean
         },
         "Sunglasses": { 
            "Confidence": number,
            "Value": boolean
         }
      }
   ],
   "OrientationCorrection": "string"
}
```

さっき、返ってくるデータ指定したけれど、DefaultだとBoundingBox, Confidence, Pose, Quality, Landmarksだけ返ってきます。
foreachでちょちょいと出してあげればOKです。

以上、Rekognitionの簡単な使い方でした。感情値データを使えばいろいろなことができるので遊んでみてください。
あと、動くけれどここのやり方違うとかあるかもなので、そこんところは教えてくれると嬉しいです。