夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

Unityで顔認識を行う Unityで動かす

今回はUnity調査枠です。

ここのところAzureを触っていますが今回は別の視点でAPIを学んでいきます。

〇顔認識

顔認識は近年セキュリティー上だけではなく、スマートフォンの写真撮影アプリなど様々な場面で使用されている解析になります。

今回は[ユーザーローカル]の[顔認識AI]をUnityで動かしました。

APIキーの取得

ユーザーローカルのページに飛び開発者登録を行います。

face-ai.userlocal.jp

f:id:Holomoto-Sumire:20201002100040j:plain

f:id:Holomoto-Sumire:20201002100113j:plain

[APIキー確認]からユーザーごとのページに飛ぶので書いてあるAPIキーを使用します。

f:id:Holomoto-Sumire:20201002100309j:plain

スクリプト

今回次のようなスクリプトを書きました。

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

public class FacialRecognition : MonoBehaviour
{
    [SerializeField]
    GameObject image;
    [System.Serializable]
    public class MyJson
    {
        public string image_base64;
        public string api_key;
    }

    void Start()
    {
        var texture = ReadTexture(Application.persistentDataPath+"\\Test.jpg");
        Debug.Log(texture);
        // string enc = System.Convert.ToBase64String(texture.EncodeToJPG());
        string enc = System.Convert.ToBase64String(texture.EncodeToJPG());

        MyJson myObject = new MyJson();
        myObject.api_key = "APIキー";
        myObject.image_base64 = enc;
        string myjson = JsonUtility.ToJson(myObject);

        StartCoroutine("PostData",myjson);
    }

    IEnumerator PostData(string myjson)
    {
        byte[] postData = System.Text.Encoding.UTF8.GetBytes(myjson);
        var request = new UnityWebRequest("https://face-ai.userlocal.jp/api/detect", "POST");
        request.uploadHandler = (UploadHandler)new UploadHandlerRaw(postData);
        request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
        
        request.SetRequestHeader("Content-Type", "application/json");
        
        yield return request.Send();
        Debug.Log(request.error);
        Debug.Log(request.downloadHandler.text);

    }

 
    Texture2D ReadTexture(string path)
    {
        byte[] readBinary = ReadFile(path);

        Texture2D texture = new Texture2D(1, 1);
        texture.LoadImage(readBinary);

        return texture;
    }

    byte[] ReadFile(string path)
    {
        FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
        BinaryReader bin = new BinaryReader(fileStream);
        byte[] values = bin.ReadBytes((int)bin.BaseStream.Length);

        bin.Close();

        return values;
    }
}

スクリプトの解説

今回は画像をアップロードすることでJSON形式のデータが返ってきます。

まずは型をそろえるためにJSONを用意します。

  [System.Serializable]
    public class MyJson
    {
        public string image_base64;
        public string api_key;
    }

今回はbase64の画像とAPIキーの二つの情報を含ませます。

   void Start()
    {
        var texture = ReadTexture(Application.persistentDataPath+"\\Test.jpg");
        Debug.Log(texture);
        string enc = System.Convert.ToBase64String(texture.EncodeToJPG());

        MyJson myObject = new MyJson();
        myObject.api_key = "APIキー";
        myObject.image_base64 = enc;
        string myjson = JsonUtility.ToJson(myObject);

        StartCoroutine("PostData",myjson);
    }

Start関数ではApplication.persistentDataPathから[Test]という名前のJpeg画像を読み込みConvert.ToBase64StringメソッドでBase64形式に変換します。

docs.microsoft.com

Base64に変換した画像と開発者ごとのAPIキーをHson形式に格納し、コルーチンでPostData()に渡しています。

   IEnumerator PostData(string myjson)
    {
        byte[] postData = System.Text.Encoding.UTF8.GetBytes(myjson);
        var request = new UnityWebRequest("https://face-ai.userlocal.jp/api/detect", "POST");
        request.uploadHandler = (UploadHandler)new UploadHandlerRaw(postData);
        request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
        
        request.SetRequestHeader("Content-Type", "application/json");
        
        yield return request.Send();
        Debug.Log(request.error);
        Debug.Log(request.downloadHandler.text);

    }

PostDataではJsonをByte形式に変換します。

requestには送り先(顔認識AIのエンドポイント)を代入し[uploadHandler]でbyteに変換したデータを送信(アップロード)しています。

docs.unity3d.com

[downloadHandler]では返されたデータが代入され、それをDebug.Logで表示させます。

Texture2D ReadTexture(string path)に関しては参考に記載した記事で紹介されていたものを使用しました。

 エンコードする際にTexture形式ではなくTexture2D形式で行う必要があるようでTexture2D形式で画像を読み込むために使用しています。

〇Unityで実行

①適当な空オブジェクトを作成しスクリプトをアタッチします。

f:id:Holomoto-Sumire:20201002102452j:plain

②適当なスクリプトで以下の処理を実行してApplication.persistentDataPathのフォルダを確認します。

Debug.Log(Application.persistentDataPath);

Application.persistentDataPathのフォルダに[Test]の名前のJpg画像ファイルを配置します。

f:id:Holomoto-Sumire:20201002103154j:plain

今回は筆者の顔写真を使用しました。

f:id:Holomoto-Sumire:20201002103529j:plain

④Unityを実行するとコンソールウィンドウに結果が表示されます。

f:id:Holomoto-Sumire:20201002103636j:plain

・結果
"status":200,"error_type":"",
"result":[{
"accuracy":0.81,
"age":"20-29",
"emotion":"surprise",
"emotions":{"angry":0,"joy":0,"sadness":0,"surprise":1},"gender":"female","location":{"x1":0,"x2":457,"y1":34,"y2":511,"width":457,"height":477},"precise_age":21}]}

・statusは処理が成功したかを示す値で200は成功を表します。

・error_typeはエラーの形式で今回は成功しているので表示されていません。

Result以降に画像の解析結果が表示されます。

・accuracyは認識の精度で0.0 〜 1.0の値で表示されます。今回0.81なのでかなり精度がいいといえる画像です。

・ageは年齢です。今回20代と表示されています。筆者は20代なので正しい結果です。

・emotionは表情です。今回の画像ではsurprise(驚き)と表示されました。

・emotionsでさらに詳しい表情の内容が表示されます。どうやらangry(怒り)、joy(喜び)、sadness(悲しみ)、surprise(驚き)のパターンで表示されるようです。

・precise_ageには正確な年齢が表示されます。 この写真時の筆者は22歳であったためほぼ正しい結果と言えます。

以上がユーザーローカルの顔認識AIをUnityで使用した結果でした。

〇参考

www.google.com

〇謝辞

今回初めてのAPIを触るにあたって師であり熊本のHoloLensコミュニティーを運営されているガチ本さんにわからない点など細かく教えていただきました。

kumamcn.connpass.com

twitter.com

HoloLensを最初に触って右も左もわからないときから教えていただきこのように筆者が技術に毎日触れ情報発信を行えるようになったのもガチ本さんのおかげです。

本当にありがとうございます。