HoloLens (第 1 世代) と Azure 304: 顔認識


Note

Mixed Reality Academy のチュートリアルは、HoloLens (第 1 世代) と Mixed Reality イマーシブ ヘッドセットを念頭に置いて編成されています。 そのため、それらのデバイスの開発に関するガイダンスを引き続き探している開発者のために、これらのチュートリアルをそのまま残しておくことが重要だと考えています。 これらのチュートリアルが、HoloLens 2 に使用されている最新のツールセットや操作に更新されることは "ありません"。 これらは、サポートされているデバイス上で継続して動作するように、保守されます。 今後、HoloLens 2 向けに開発する方法を示す新しいチュートリアル シリーズが投稿される予定です。 この通知は、それらのチュートリアルが投稿されたときにリンクと共に更新されます。


このコースを修了した結果

このコースでは、Microsoft Face API と共に Azure Cognitive Services を使用して、Mixed Reality アプリケーションに顔認識機能を追加する方法について説明します。

Azure Face API は Microsoft のサービスであり、開発者はクラウドから最も高度な顔アルゴリズムを利用できます。 Face API には、属性を使用した顔検出と顔認識の 2 つの主な機能があります。 これにより、開発者は、顔のグループのセットを設定し、その上でクエリ イメージを後からサービスに送信して、顔が属する人物を特定することができます。 詳細については、Azure 顔認識のページを参照してください。

このコースを修了すると、Mixed Reality HoloLens アプリケーションで次のことができるようになります。

  1. タップ ジェスチャで、オンボード HoloLens カメラを使用したイメージのキャプチャを開始します。
  2. キャプチャしたイメージを Azure Face API サービスに送信します。
  3. Face API アルゴリズムの結果を受け取ります。
  4. 単純なユーザー インターフェイスを使用して、一致する人物の名前を表示します。

ここでは、Face API サービスから Unity ベースの Mixed Reality アプリケーションに結果を取得する方法について説明します。

お客様のアプリケーションで、結果をどのようにデザインと統合するかは、お客様次第です。 このコースは、Azure のサービスを Unity プロジェクトに統合する方法を学べるよう設計されています。 このコースで得られた知識を使用して、ご自分の Mixed Reality アプリケーションを強化しましょう。

デバイス サポート

コース HoloLens イマーシブ ヘッドセット
MR と Azure 304:顔認識 ✔️ ✔️

注意

このコースでは主に HoloLens に焦点を当てていますが、このコースで学習した内容を Windows Mixed Reality イマーシブ (VR) ヘッドセットにも適用できます。 イマーシブ (VR) ヘッドセットにはアクセス可能なカメラがないため、外部カメラが PC に接続されている必要があります。 このコースの中では、イマーシブ (VR) ヘッドセットをサポートするために必要な変更がある場合に、その変更が注意事項として記載されています。

前提条件

Note

このチュートリアルは、Unity と C# の基本的な使用経験がある開発者を対象としています。 また、このドキュメント内の前提条件や文章による説明は、執筆時 (2018 年 5 月) にテストおよび検証された内容であることをご了承ください。 「ツールのインストール」の記事に記載されているように、お客様は最新のソフトウェアを自由に使用できます。ただし、このコースの情報は、以下に記載されているものよりも新しいソフトウェアで見つかったものと完全に一致するとは限りません。

このコースでは、次のハードウェアとソフトウェアをお勧めします。

開始する前に

  1. このプロジェクトをビルドする際の問題を避けるために、このチュートリアルで紹介するプロジェクトをルートまたはルートに近いフォルダーに作成することを強くお勧めします (フォルダー パスが長いと、ビルド時に問題が発生する可能性があります)。
  2. HoloLens を設定してテストします。 HoloLens の設定でサポートが必要な場合は、HoloLens セットアップに関する記事にアクセスしてください
  3. 新しい HoloLens アプリの開発を開始するときは、調整とセンサーのチューニングを実行することをお勧めします (ユーザーごとにこれらのタスクを実行すると役立つ場合があります)。

調整の詳細については、この HoloLens の調整に関する記事へのリンクを参照してください。

センサー チューニングの詳細については、HoloLens センサー チューニングに関する記事へのリンクを参照してください。

第 1 章 - Azure portal

Azure で Face API サービスを使用するには、サービスのインスタンスを構成してアプリケーションで使用できるようにする必要があります。

  1. 最初に、Azure portal にログインします。

    Note

    まだ Azure アカウントをお持ちでない方は、作成する必要があります。 このチュートリアルを教室やラボで受講している場合は、インストラクターや監督者に新しいアカウントの設定方法を質問してください。

  2. ログインしたら、左上の [新規作成] をクリックして、Face API を検索して Enter キーを押します。

    face api を検索する

    Note

    新しいポータルでは、[新規作成] という文字列が [リソースの作成] に置き換えられている場合があります。

  3. 新しいページに、Face API サービスの説明が表示されます。 このプロンプトの左下にある [作成] ボタンを選択すると、このサービスとの関連付けが作成されます。

    face api の情報

  4. [作成] をクリックしたら、以下の手順を実行します。

    1. このサービス インスタンスに必要な名前を入力します。

    2. サブスクリプションを選択します。

    3. 適切な価格レベルを選択します。これが初めて作成する Face API サービスの場合は、無料レベル (F0 という名前) を使用できるはずです。

    4. [リソース グループ] を選択するか、新規に作成します。 リソース グループは、Azure アセットのコレクションの監視、アクセス制御、プロビジョニング、課金管理を行う方法を提供します。 1 つのプロジェクト (これらのラボなど) に関連するすべての Azure サービスを共通のリソース グループの下に置くことをお勧めします。

      Azure リソース グループの詳細については、リソース グループに関する記事を参照してください。

    5. 後で使用する UWP アプリの Person Makerでは、場所として "米国西部" を使用する必要があります。

    6. またお客様は、本サービスに適用されるご契約条件を理解していることを確認する必要があります。

    7. [ 作成] を選択します*

      face api サービスを作成する

  5. [作成]* をクリックしたら、サービスが作成されるのを待つ必要があります。これには 1 分ほどかかります。

  6. サービスのインスタンスが作成されると、ポータルに通知が表示されます。

    サービス作成通知

  7. 通知をクリックして、新しいサービス インスタンスを確認します。

    リソース通知に移動する

  8. 準備ができたら、通知の [リソースに移動] ボタンをクリックすると、新しいサービス インスタンスを確認できます。

    顔 API キーにアクセスする

  9. このチュートリアルでは、アプリケーションがサービスの呼び出しを行う必要があります。これは、サービスのサブスクリプション 'キー' を使用して実行されます。 クイック スタート ページの、Face API サービスの最初のポイントは 1 で、ここでキーを取得します。

  10. サービス ページで、青い [キー] のハイパーリンク (クイック スタート ページの場合)、またはサービス ナビゲーション メニューの [キー] リンク (左側にある 'キー' と表示されたアイコン) のいずれかを選択して、キーを表示します。

    Note

    後で必要になるので、いずれかのキーを書き留めて保護しておきます。

第 2 章 - "Person Maker" UWP アプリケーションの使用

Person Maker というビルド済みの UWP アプリケーションをダウンロードしてください。 このアプリは、このコースの最終的な製品ではなく、これ以降のプロジェクトで利用される、Azure エントリの作成をサポートするためのツールです。

Person Maker では、人物および人物のグループに関連付けられている Azure エントリを作成できます。 このアプリケーションは、追加した人物の顔を認識するために必要なすべての情報を、後で FaceAPI が使用できる形式で保存します。

[重要] Person Maker は、いくつかの基本的な調整を使用して、無料サブスクリプション レベルの 1 分あたりのサービス呼び出し数を超過しないようにします。 調整が行われている間は、上部の緑色のテキストが赤に変わり、"ACTIVE" として更新されます。この場合は、アプリケーションを待機します (これは、次に Face サービスのアクセスが続行できるようになるまで待機し、再び使用できるようになると "IN-ACTIVE" として更新されます)。

このアプリケーションでは、Microsoft.ProjectOxford.Face ライブラリを使用します。これにより、Face API を最大限に活用することができます。 このライブラリは NuGet パッケージとして無料で利用できます。 この API について、またこれと同様の API の詳細については、API リファレンスの記事を参照してください

Note

これらの手順は、以降のドキュメントで手順を進めるために必要な方法のみを説明しています。 Person Maker アプリでは、次のことができます。

  • Person Group を作成します。これは、関連付ける複数の人物で構成されるグループです。 Azure アカウントを使用すると、複数の Person Group をホストできます。

  • Person を作成します。これは、Person Group のメンバーです。 各人物には、複数の Face イメージが関連付けられます。

  • 顔の画像Person に割り当てて、Azure Face API サービスで、対応するPerson を認識できるようにします。

  • Azure Face API サービストレーニングします

このアプリをトレーニングしてユーザーを認識できるようにするには、Person Group に追加する人物 1 人につき 10 枚のアップの写真が必要です。 Windows 10 のカメラ アプリを使用すると、これらを簡単に撮影できます。 各写真は、鮮明で (ぼかしや覆いを避け、主題から遠すぎない)、jpg または png ファイル形式で、画像ファイルのサイズが 4 MB より小さく、1 KB より大きくする必要があります。

Note

このチュートリアルに従う場合は、トレーニングに自分の顔を使用しないでください。HoloLens をオンにしたときに、自分を見ることができないためです。 同僚や他の受講生の顔を使用します。

Person Maker の実行:

  1. PersonMaker フォルダーを開いて、PersonMaker ソリューションをダブルクリックして、Visual Studio で開きます。

  2. PersonMaker ソリューションが開いたら、次のことを確認してください。

    1. ソリューション構成[デバッグ] に設定されています。

    2. ソリューション プラットフォームx86 に設定されています。

    3. ターゲット プラットフォーム[ローカル マシン] に設定されています。

    4. [NuGet パッケージの復元] ([ソリューション] を右クリックして [NuGet パッケージの復元] を選択) の選択も必要になる場合があります。

  3. [ローカル コンピューター] をクリックすると、アプリケーションが起動します。 小さい画面では、コンテンツの一部が表示されない場合があることに注意してください。ただし、下にスクロールして表示することもできます。

    person maker ユーザー インターフェイス

  4. Azure 内の Face API サービスから、Azure 認証キーを挿入します。

  5. 挿入:

    1. Person Group に割り当てる ID。 ID は小文字で指定する必要があります。スペースは使用できません。 この ID は、後で Unity プロジェクトで必要になるため、メモしておいてください。
    2. Person Group に割り当てる名前 (スペースを含めることができます)。
  6. [Create Person Group](Person Group の作成) ボタンをクリックします。 ボタンの下に確認メッセージが表示されます。

Note

"アクセス拒否" のエラーが発生した場合は、Azure サービス用に設定した場所を確認します。 前述のように、このアプリは "米国西部" 向けに設計されています。

重要

[Fetch a Known Group](既知のグループをフェッチ) ボタンもクリックできます。これは、Person Group を既に作成していて、新規作成はせずにそのグループを使用する場合に使用します。 ただし、既知のグループで [Create Person Group](Person Group の作成) をクリックした場合も、グループがフェッチされることに注意します。

  1. 作成するPerson名前を挿入します。

    1. [Create Person](Person の作成) ボタンをクリックします。

    2. ボタンの下に確認メッセージが表示されます。

    3. 以前に作成した人物を削除する場合は、名前をテキストボックスに入力し、[Delete Person](個人の削除) をクリックします

  2. グループに追加する人物の 10 枚の写真の場所がわかっていることを確認します。

  3. [Create and Open Folder](フォルダーを作成して開く) をクリックして Windows エクスプローラーを開き、その人物に関連付けられているフォルダーを開きます。 フォルダー内の 10 個のイメージを追加します。 これらは、JPG または PNG ファイル形式である必要があります。

  4. [Submit To Azure](Azure に送信) をクリックします。 カウンターに送信の状態が表示され、その後、完了時にメッセージが表示されます。

  5. カウンターが終了して確認メッセージが表示されたら、[Train](トレーニングする) をクリックしてサービスをトレーニングします。

プロセスが完了すると、Unity に移行できるようになります。

第 3 章 - Unity プロジェクトの設定

次の設定は、複合現実での開発のための一般的な設定であるため、他のプロジェクトのテンプレートとして利用できます。

  1. Unity を開き、[New] (新規) をクリックします。

    新しい Unity プロジェクトを開始します。

  2. ここで、Unity プロジェクト名を指定する必要があります。 MR_FaceRecognition を挿入します。 プロジェクトの種類が [3D] に設定されていることを確認します。 [Location] (場所) を適切な場所に設定します (ルート ディレクトリに近い方が適しています)。 次に、[プロジェクトの作成] をクリックします。

    新しい Unity プロジェクトの詳細を指定します。

  3. Unity を開いた状態で、既定のスクリプト エディターVisual Studio に設定されているかどうか確認することをお勧めします。 [編集] > [基本設定] に移動し、新しいウィンドウで [外部ツール] に移動します。 [外部スクリプト エディター][Visual Studio 2017] に変更します。 [環境設定] ウィンドウを閉じます。

    スクリプト エディターの基本設定を更新します。

  4. 次に、[ファイル] > [ビルド設定] で、[プラットフォームの切り替え] ボタンをクリックして、プラットフォームを [ユニバーサル Windows プラットフォーム] に切り替えます。

    [ビルド設定] ウィンドウで、プラットフォームを UWP に切り替えます。

  5. [ファイル] > [ビルド設定] に移動して、次を確認します。

    1. [ターゲット デバイス][HoloLens] に設定されている

      イマーシブ ヘッドセットの場合は、[ターゲット デバイス][任意のデバイス] に設定します。

    2. [Build Type] (ビルドの種類)[D3D] に設定されている

    3. [SDK][Latest installed] (最新のインストール) に設定されている

    4. [Visual Studio Version] (Visual Studio のバージョン)[Latest installed] (最新のインストール) に設定されている

    5. [Build and Run] (ビルドと実行)[Local Machine] (ローカル マシン) に設定されている

    6. シーンを保存し、ビルドに追加します。

      1. これを行うには、[Add Open Scenes] (開いているシーンを追加) を選択します。 保存ウィンドウが表示されます。

        [開いているシーンの追加] ボタンをクリックします

      2. [新しいフォルダー] ボタンを選択して新しいフォルダーを作成し、「Scenes」と名前を付けます。

        新しい scripts フォルダーを作成する

      3. 新しく作成した Scenes フォルダーを開き、[File name:](ファイル名) テキスト フィールドに「FaceRecScene」と入力して [Save](保存) をクリックします。

        新しいシーンに名前を付けます。

    7. [ビルド設定] の残りの設定は、ここでは既定値のままにしておきます。

  6. [ビルド設定] ウィンドウで、[プレーヤー設定] ボタンをクリックすると、[インスペクター] が配置されているスペースに関連パネルが表示されます。

    プレーヤーの設定を開きます。

  7. このパネルでは、いくつかの設定を確認する必要があります。

    1. [Other Settings](その他の設定) タブで、次の内容を確認します。

      1. [Scripting Runtime Version](スクリプト ランタイムのバージョン) が [Experimental](試験段階) (.NET 4.6 と同等) になっている。 これを変更すると、エディターを再起動する必要が生じます。

      2. [Scripting Backend](スクリプト バックエンド)[.NET] である。

      3. [API Compatibility Level] (API 互換性レベル)[.NET 4.6] である

        その他の設定を更新します。

    2. [公開設定] タブ内の [機能] で、次の内容を確認します。

      • InternetClient

      • Web カメラ

        発行設定の更新。

    3. さらに、パネルの下にある [XR 設定] ([公開設定] の下) で、[Virtual Reality サポート] をオンにし、Windows Mixed Reality SDK が追加されていることを確認します。

      X R 設定を更新します。

  8. [ビルド設定] に戻ると、"Unity C# プロジェクト" に適用されていた灰色表示が解除されています。その横にあるチェック ボックスをオンにします。

  9. [ビルド設定] ウィンドウを閉じます。

  10. シーンとプロジェクトを保存します ([FILE](ファイル) > [SAVE SCENE / FILE](シーン/ファイルの保存) > [SAVE PROJECT](プロジェクトの保存) を選択)。

第 4 章 - メイン カメラのセットアップ

重要

このコースで Unity のセットアップ コンポーネントをスキップして、そのままコードに進みたい場合は、この .unitypackage をダウンロードして、カスタム パッケージとしてプロジェクトにインポートしてください。 このパッケージには、第 5 章で説明されている Newtonsoft DLL のインポートも含まれていることに注意します。 これをインポートすると、第 6 章から続けられます。

  1. [Hierarchy](階層) パネルで [Main Camera](メイン カメラ) を選択します。

  2. 選択すると、[Main Camera](メイン カメラ) のすべてのコンポーネントを [Inspector](インスペクター) パネルに表示できるようになります。

    1. カメラ オブジェクトの名前Main Camera である必要があります (スペルに注意します)。

    2. Main Camera タグMainCamera に設定する必要があります (スペルに注意します)。

    3. [Transform](変換) の [Position](位置)0、0、0 に設定されていることを確認します。

    4. [Clear Flags](クリア フラグ)[Solid Color](単色) に設定します。

    5. カメラ コンポーネントの [Background Color](背景色)黒、アルファ 0 (16 進コード: #00000000) に設定します。

      カメラ コンポーネントを設定する

第 5 章 - Newtonsoft.Json ライブラリのインポート

重要

前の章で ".unitypackage" をインポートした場合は、この章をスキップできます。

Bot Service に対して受信および送信されたオブジェクトを逆シリアル化およびシリアル化するには、Newtonsoft.Json ライブラリをダウンロードする必要があります。 この Unity パッケージ ファイルには、適切な Unity フォルダー構造で既に整理されている互換性のあるバージョンが含まれます。

ライブラリをインポートするには、次の手順を実行します。

  1. Unity パッケージをダウンロードします。

  2. [Assets](資産)[Import Package](パッケージのインポート)[Custom Package](カスタム パッケージ) をクリックします。

    Newtonsoft.Json のインポート

  3. ダウンロードした Unity パッケージを探し、[Open](開く) をクリックします。

  4. パッケージのすべてのコンポーネントのチェック ボックスを選択したことを確認して、[Import](インポート) をクリックします。

    Newtonsoft.Json アセットをインポートする

第 6 章 - FaceAnalysis クラスの作成

FaceAnalysis クラスの目的は、Azure 顔認識サービスとの通信に必要なメソッドをホストすることです。

  • サービスに送信されたキャプチャ イメージは、分析されてその中の顔が識別され、既知の人物に属しているかどうかが判断されます。
  • 既知の人物が見つかった場合、このクラスは、その名前をシーン内の UI テキストとして表示します。

FaceAnalysis クラスを作成するには、次の手順を実行します。

  1. [Project](プロジェクト) パネルにある Assets フォルダーを右クリックし、[Create](作成)>[Folder](フォルダー) の順にクリックします。 フォルダーに「Scripts」という名前を付けます。

    FaceAnalysis クラスを作成します。

  2. 先ほど作成したフォルダーをダブルクリックして開きます。

  3. フォルダー内を右クリックし、[Create](作成)>[C# Script](C# スクリプト) の順にクリックします。 スクリプト名を FaceAnalysis にします。

  4. 新しい FaceAnalysis スクリプトをダブルクリックして、Visual Studio 2017 で開きます。

  5. FaceAnalysis クラスの上に次の名前空間を入力します。

        using Newtonsoft.Json;
        using System.Collections;
        using System.Collections.Generic;
        using System.IO;
        using System.Text;
        using UnityEngine;
        using UnityEngine.Networking;
    
  6. 次に、シリアル化解除に使用されるオブジェクトをすべて追加する必要があります。 これらのオブジェクトは、FaceAnalysis スクリプトの外部 (下部の中かっこの下) に追加する必要があります。

        /// <summary>
        /// The Person Group object
        /// </summary>
        public class Group_RootObject
        {
            public string personGroupId { get; set; }
            public string name { get; set; }
            public object userData { get; set; }
        }
    
        /// <summary>
        /// The Person Face object
        /// </summary>
        public class Face_RootObject
        {
            public string faceId { get; set; }
        }
    
        /// <summary>
        /// Collection of faces that needs to be identified
        /// </summary>
        public class FacesToIdentify_RootObject
        {
            public string personGroupId { get; set; }
            public List<string> faceIds { get; set; }
            public int maxNumOfCandidatesReturned { get; set; }
            public double confidenceThreshold { get; set; }
        }
    
        /// <summary>
        /// Collection of Candidates for the face
        /// </summary>
        public class Candidate_RootObject
        {
            public string faceId { get; set; }
            public List<Candidate> candidates { get; set; }
        }
    
        public class Candidate
        {
            public string personId { get; set; }
            public double confidence { get; set; }
        }
    
        /// <summary>
        /// Name and Id of the identified Person
        /// </summary>
        public class IdentifiedPerson_RootObject
        {
            public string personId { get; set; }
            public string name { get; set; }
        }
    
  7. Start() メソッドと Update() メソッドは使用されないので、ここで削除します。

  8. FaceAnalysis クラス内に以下の変数を追加します。

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static FaceAnalysis Instance;
    
        /// <summary>
        /// The analysis result text
        /// </summary>
        private TextMesh labelText;
    
        /// <summary>
        /// Bytes of the image captured with camera
        /// </summary>
        internal byte[] imageBytes;
    
        /// <summary>
        /// Path of the image captured with camera
        /// </summary>
        internal string imagePath;
    
        /// <summary>
        /// Base endpoint of Face Recognition Service
        /// </summary>
        const string baseEndpoint = "https://westus.api.cognitive.microsoft.com/face/v1.0/";
    
        /// <summary>
        /// Auth key of Face Recognition Service
        /// </summary>
        private const string key = "- Insert your key here -";
    
        /// <summary>
        /// Id (name) of the created person group 
        /// </summary>
        private const string personGroupId = "- Insert your group Id here -";
    

    Note

    キーpersonGroupId を、前に作成したグループのサービス キーと ID に置き換えます。

  9. クラスを初期化する Awake() メソッドを追加します。ImageCapture クラスを Main Camera に追加し、ラベル作成メソッドを呼び出します。

        /// <summary>
        /// Initialises this class
        /// </summary>
        private void Awake()
        {
            // Allows this instance to behave like a singleton
            Instance = this;
    
            // Add the ImageCapture Class to this Game Object
            gameObject.AddComponent<ImageCapture>();
    
            // Create the text label in the scene
            CreateLabel();
        }
    
  10. CreateLabel() メソッドを追加します。このメソッドは、分析結果を表示する Label オブジェクトを作成します。

        /// <summary>
        /// Spawns cursor for the Main Camera
        /// </summary>
        private void CreateLabel()
        {
            // Create a sphere as new cursor
            GameObject newLabel = new GameObject();
    
            // Attach the label to the Main Camera
            newLabel.transform.parent = gameObject.transform;
    
            // Resize and position the new cursor
            newLabel.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f);
            newLabel.transform.position = new Vector3(0f, 3f, 60f);
    
            // Creating the text of the Label
            labelText = newLabel.AddComponent<TextMesh>();
            labelText.anchor = TextAnchor.MiddleCenter;
            labelText.alignment = TextAlignment.Center;
            labelText.tabSize = 4;
            labelText.fontSize = 50;
            labelText.text = ".";       
        }
    
  11. DetectFacesFromImage() メソッドと GetImageAsByteArray() メソッドを追加します。 前者は、送信されたイメージ内の可能性のある顔を検出するために顔認識サービスを要求します。後者は、キャプチャされたイメージをバイト配列に変換するために必要です。

        /// <summary>
        /// Detect faces from a submitted image
        /// </summary>
        internal IEnumerator DetectFacesFromImage()
        {
            WWWForm webForm = new WWWForm();
            string detectFacesEndpoint = $"{baseEndpoint}detect";
    
            // Change the image into a bytes array
            imageBytes = GetImageAsByteArray(imagePath);
    
            using (UnityWebRequest www = 
                UnityWebRequest.Post(detectFacesEndpoint, webForm))
            {
                www.SetRequestHeader("Ocp-Apim-Subscription-Key", key);
                www.SetRequestHeader("Content-Type", "application/octet-stream");
                www.uploadHandler.contentType = "application/octet-stream";
                www.uploadHandler = new UploadHandlerRaw(imageBytes);
                www.downloadHandler = new DownloadHandlerBuffer();
    
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
                Face_RootObject[] face_RootObject = 
                    JsonConvert.DeserializeObject<Face_RootObject[]>(jsonResponse);
    
                List<string> facesIdList = new List<string>();
                // Create a list with the face Ids of faces detected in image
                foreach (Face_RootObject faceRO in face_RootObject)
                {
                    facesIdList.Add(faceRO.faceId);
                    Debug.Log($"Detected face - Id: {faceRO.faceId}");
                }
    
                StartCoroutine(IdentifyFaces(facesIdList));
            }
        }
    
        /// <summary>
        /// Returns the contents of the specified file as a byte array.
        /// </summary>
        static byte[] GetImageAsByteArray(string imageFilePath)
        {
            FileStream fileStream = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read);
            BinaryReader binaryReader = new BinaryReader(fileStream);
            return binaryReader.ReadBytes((int)fileStream.Length);
        }
    
  12. IdentifyFaces() メソッドを追加します。このメソッドは、送信されたイメージで以前に検出された既知の顔を識別するように顔認識サービスに要求します。 要求によって、識別されたユーザーの ID が返されますが、名前は返されません。

        /// <summary>
        /// Identify the faces found in the image within the person group
        /// </summary>
        internal IEnumerator IdentifyFaces(List<string> listOfFacesIdToIdentify)
        {
            // Create the object hosting the faces to identify
            FacesToIdentify_RootObject facesToIdentify = new FacesToIdentify_RootObject();
            facesToIdentify.faceIds = new List<string>();
            facesToIdentify.personGroupId = personGroupId;
            foreach (string facesId in listOfFacesIdToIdentify)
            {
                facesToIdentify.faceIds.Add(facesId);
            }
            facesToIdentify.maxNumOfCandidatesReturned = 1;
            facesToIdentify.confidenceThreshold = 0.5;
    
            // Serialize to Json format
            string facesToIdentifyJson = JsonConvert.SerializeObject(facesToIdentify);
            // Change the object into a bytes array
            byte[] facesData = Encoding.UTF8.GetBytes(facesToIdentifyJson);
    
            WWWForm webForm = new WWWForm();
            string detectFacesEndpoint = $"{baseEndpoint}identify";
    
            using (UnityWebRequest www = UnityWebRequest.Post(detectFacesEndpoint, webForm))
            {
                www.SetRequestHeader("Ocp-Apim-Subscription-Key", key);
                www.SetRequestHeader("Content-Type", "application/json");
                www.uploadHandler.contentType = "application/json";
                www.uploadHandler = new UploadHandlerRaw(facesData);
                www.downloadHandler = new DownloadHandlerBuffer();
    
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
                Debug.Log($"Get Person - jsonResponse: {jsonResponse}");
                Candidate_RootObject [] candidate_RootObject = JsonConvert.DeserializeObject<Candidate_RootObject[]>(jsonResponse);
    
                // For each face to identify that ahs been submitted, display its candidate
                foreach (Candidate_RootObject candidateRO in candidate_RootObject)
                {
                    StartCoroutine(GetPerson(candidateRO.candidates[0].personId));
    
                    // Delay the next "GetPerson" call, so all faces candidate are displayed properly
                    yield return new WaitForSeconds(3);
                }           
            }
        }
    
  13. GetPerson() メソッドを追加します。 人物の ID を指定することで、このメソッドは顔認識サービスに対して、識別された人物の名前を返す要求を行います。

        /// <summary>
        /// Provided a personId, retrieve the person name associated with it
        /// </summary>
        internal IEnumerator GetPerson(string personId)
        {
            string getGroupEndpoint = $"{baseEndpoint}persongroups/{personGroupId}/persons/{personId}?";
            WWWForm webForm = new WWWForm();
    
            using (UnityWebRequest www = UnityWebRequest.Get(getGroupEndpoint))
            {
                www.SetRequestHeader("Ocp-Apim-Subscription-Key", key);
                www.downloadHandler = new DownloadHandlerBuffer();
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
    
                Debug.Log($"Get Person - jsonResponse: {jsonResponse}");
                IdentifiedPerson_RootObject identifiedPerson_RootObject = JsonConvert.DeserializeObject<IdentifiedPerson_RootObject>(jsonResponse);
    
                // Display the name of the person in the UI
                labelText.text = identifiedPerson_RootObject.name;
            }
        }
    
  14. Unity エディターに戻る前に、変更内容を保存しておきます。

  15. Unity エディターで、FaceAnalysis スクリプトを [Project](プロジェクト) パネルの Scripts フォルダーから、[Hierarchy](階層) パネルの Main Camera オブジェクトにドラッグします。 新しいスクリプト コンポーネントが Main Camera に追加されます。

FaceAnalysis をメイン カメラに配置する

第 7 章 - ImageCapture クラスの作成

ImageCapture クラスの目的は、Azure 顔認識サービスと通信して、キャプチャするイメージを分析し、その中の顔を識別し、それが既知の人物に属しているのかを判断するために必要なメソッドをホストすることです。 既知の人物が見つかった場合、このクラスは、その名前をシーン内の UI テキストとして表示します。

ImageCapture クラスを作成するには、次の手順を実行します。

  1. 前に作成した Scripts フォルダー内を右クリックし、[Create](作成)[C# Script](C# スクリプト) の順にクリックします。 スクリプトの名前を ImageCapture にします。

  2. 新しい ImageCapture スクリプトをダブルクリックして、Visual Studio 2017 で開きます。

  3. ImageCapture クラスの上に次の名前空間を入力します。

        using System.IO;
        using System.Linq;
        using UnityEngine;
        using UnityEngine.XR.WSA.Input;
        using UnityEngine.XR.WSA.WebCam;
    
  4. ImageCapture クラス内に以下の変数を追加します。

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static ImageCapture instance;
    
        /// <summary>
        /// Keeps track of tapCounts to name the captured images 
        /// </summary>
        private int tapsCount;
    
        /// <summary>
        /// PhotoCapture object used to capture images on HoloLens 
        /// </summary>
        private PhotoCapture photoCaptureObject = null;
    
        /// <summary>
        /// HoloLens class to capture user gestures
        /// </summary>
        private GestureRecognizer recognizer;
    
  5. クラスの初期化に必要な Awake() メソッドと Start() メソッドを追加し、HoloLens でユーザーのジェスチャをキャプチャできるようにします。

        /// <summary>
        /// Initialises this class
        /// </summary>
        private void Awake()
        {
            instance = this;
        }
    
        /// <summary>
        /// Called right after Awake
        /// </summary>
        void Start()
        {
            // Initialises user gestures capture 
            recognizer = new GestureRecognizer();
            recognizer.SetRecognizableGestures(GestureSettings.Tap);
            recognizer.Tapped += TapHandler;
            recognizer.StartCapturingGestures();
        }
    
  6. TapHandler() を追加します。これは、ユーザーがタップ ジェスチャを実行したときに呼び出されます。

        /// <summary>
        /// Respond to Tap Input.
        /// </summary>
        private void TapHandler(TappedEventArgs obj)
        {
            tapsCount++;
            ExecuteImageCaptureAndAnalysis();
        }
    
  7. ExecuteImageCaptureAndAnalysis() メソッドを追加します。このメソッドは、イメージ キャプチャのプロセスを開始します。

        /// <summary>
        /// Begin process of Image Capturing and send To Azure Computer Vision service.
        /// </summary>
        private void ExecuteImageCaptureAndAnalysis()
        {
            Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending
                ((res) => res.width * res.height).First();
            Texture2D targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);
    
            PhotoCapture.CreateAsync(false, delegate (PhotoCapture captureObject)
            {
                photoCaptureObject = captureObject;
    
                CameraParameters c = new CameraParameters();
                c.hologramOpacity = 0.0f;
                c.cameraResolutionWidth = targetTexture.width;
                c.cameraResolutionHeight = targetTexture.height;
                c.pixelFormat = CapturePixelFormat.BGRA32;
    
                captureObject.StartPhotoModeAsync(c, delegate (PhotoCapture.PhotoCaptureResult result)
                {
                    string filename = string.Format(@"CapturedImage{0}.jpg", tapsCount);
                    string filePath = Path.Combine(Application.persistentDataPath, filename);
    
                    // Set the image path on the FaceAnalysis class
                    FaceAnalysis.Instance.imagePath = filePath;
    
                    photoCaptureObject.TakePhotoAsync
                    (filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
                });
            });
        }
    
  8. 写真キャプチャ プロセスが完了すると呼び出されるハンドラーを追加します。

        /// <summary>
        /// Called right after the photo capture process has concluded
        /// </summary>
        void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
        {
            photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
        }
    
        /// <summary>
        /// Register the full execution of the Photo Capture. If successful, it will begin the Image Analysis process.
        /// </summary>
        void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
        {
            photoCaptureObject.Dispose();
            photoCaptureObject = null;
    
            // Request image caputer analysis
            StartCoroutine(FaceAnalysis.Instance.DetectFacesFromImage());
        }
    
  9. Unity エディターに戻る前に、変更内容を保存しておきます。

第 8 章 - ソリューションのビルド

アプリケーションの完全なテストを実行するには、アプリケーションを HoloLens にサイドロードする必要があります。

実行する前に、次のことを確認してください。

  • 第 3 章に記載されている設定がすべて正しく設定されています。
  • スクリプト FaceAnalysis が Main Camera オブジェクトにアタッチされています。
  • 認証キーグループ ID の両方が FaceAnalysis スクリプト内に設定されています。

この時点で、ソリューションをビルドする準備ができました。 ソリューションがビルドされた後、アプリケーションをデプロイする準備が整います。

ビルド プロセスを開始するには、次の手順を実行します。

  1. [File](ファイル)、[Save](保存) の順にクリックして現在のシーンを保存します。

  2. [File](ファイル)、[Build Settings](ビルド設定) の順に移動して、[Add Open Scenes](開いているシーンの追加) をクリックします。

  3. 必ず Unity C# プロジェクトを選択する必要があります。

    Visual Studio ソリューションをデプロイする

  4. [Build](ビルド) をクリックします。 その後、Unity によってエクスプローラー ウィンドウが起動されます。そこで、アプリをビルドするフォルダーを作成して選択する必要があります。 そのフォルダーを Unity プロジェクト内に作成し、名前を「App」にします。 次に、App フォルダーを選択した状態で、[フォルダーの選択] を押します。

  5. Unity がプロジェクトのビルドを開始し、App フォルダーに保存します。

  6. Unity のビルドが完了すると (これには時間がかかる場合があります)、ビルドの場所でエクスプローラーのウィンドウが開きます。

    Visual Studio からソリューションをデプロイする

  7. App フォルダーを開き、新しいプロジェクト ソリューションを開きます (上記の MR_FaceRecognition.sln)。

第 9 章 - アプリケーションのデプロイ

HoloLens にデプロイするには、次の手順を実行します。

  1. HoloLens の IP アドレスが必要になります (リモート デプロイの場合)。また、HoloLens が開発者モードになっていることを確認する必要があります。 手順は次のとおりです。

    1. HoloLens を装着した状態で、[設定] を開きます。
    2. [ネットワーク & インターネット>] Wi-Fi > [詳細オプション] に移動します
    3. IPv4 アドレスを書き留めます。
    4. 次に、[設定] に戻り、[Update & Security For Developers]\(開発者向けセキュリティ>の更新\) に移動します
    5. [開発者モード] を [オン] に設定します。
  2. 新しい Unity ビルド (App フォルダー) に移動し、Visual Studio を使用してソリューション ファイルを開きます。

  3. [ソリューション構成] で、[デバッグ] を選択します。

  4. ソリューション プラットフォームで、[X86][リモート コンピューター] を選択します。

    ソリューション構成を変更する

  5. [ビルド] メニューに移動して [ソリューションの配置] をクリックして、アプリケーションを HoloLens にサイドロードします。

  6. HoloLens にインストールされたアプリの一覧にこのアプリが表示され、起動できる状態になります。

Note

イマーシブ ヘッドセットにデプロイするには、[Solution Platform](ソリューション プラットフォーム)[Local Machine](ローカル コンピューター)に設定し、[Configuration](構成)[Debug](デバッグ) にし、プラットフォームとして x86 を設定します。 次に、[ビルド] メニュー[ソリューションの配置] を選択して、ローカル コンピューターにデプロイします。

第 10 章 - アプリケーションの使用

  1. HoloLens を装着してアプリを起動します。

  2. Face API に登録した人物を見ます。 次のことを確認してください。

    • 人物の顔が離れすぎず、明確に見える
    • 環境の照明が暗すぎない
  3. タップ ジェスチャを使用して、人物の画像をキャプチャします。

  4. アプリが分析要求を送信し、応答を受信するまで待ちます。

  5. 人物が正常に認識されると、その人物の名前が UI テキストとして表示されます。

  6. 数秒ごとにタップ ジェスチャを使用して、キャプチャ プロセスを繰り返し実行できます。

完成した Azure Face API アプリケーション

おめでとうございます。Azure 顔認識サービスを利用してイメージ内の顔を検出し、既知の顔を特定する Mixed Reality アプリを構築しました。

このコースを修了した結果

ボーナス演習

演習 1

Azure Face API は、1 つのイメージで最大 64 個の顔を検出できる強力な機能です。 アプリケーションを拡張して、多数の人物の中で 2 人または 3 人の顔を認識できるようにします。

演習 2

Azure Face API では、あらゆる種類の属性情報を提供することもできます。 これをアプリケーションに統合します。 Emotion API と組み合わせると、これはさらに興味深いものになる可能性があります。