MR と Azure 302b:カスタム ビジョンMR and Azure 302b: Custom vision


注意

Mixed Reality Academy のチュートリアルは、HoloLens (第 1 世代) と Mixed Reality イマーシブ ヘッドセットを念頭に置いて編成されています。The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. そのため、それらのデバイスの開発に関するガイダンスを引き続き探している開発者のために、これらのチュートリアルをそのまま残しておくことが重要だと考えています。As such, we feel it is important to leave these tutorials in place for developers who are still looking for guidance in developing for those devices. これらのチュートリアルが、HoloLens 2 に使用されている最新のツールセットや操作に更新されることは "ありません"。These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. これらは、サポートされているデバイス上で継続して動作するように、保守されます。They will be maintained to continue working on the supported devices. 今後、HoloLens 2 向けの開発方法を示す新しい一連のチュートリアルが掲載されています。There will be a new series of tutorials that will be posted in the future that will demonstrate how to develop for HoloLens 2. この通知は、これらのチュートリアルが投稿されたときのリンクと共に更新されます。This notice will be updated with a link to those tutorials when they are posted.


このコースでは、混合現実アプリケーションで Azure Custom Vision の機能を使用して、提供されたイメージ内のカスタムビジュアルコンテンツを認識する方法を学習します。In this course, you will learn how to recognize custom visual content within a provided image, using Azure Custom Vision capabilities in a mixed reality application.

このサービスでは、オブジェクトイメージを使用して機械学習モデルをトレーニングすることができます。This service will allow you to train a machine learning model using object images. 次に、トレーニング済みのモデルを使用して類似のオブジェクトを認識します。これは、Microsoft HoloLens のカメラキャプチャや、PC for イマーシブ (VR) ヘッドセットに接続されたカメラによって提供されます。You will then use the trained model to recognize similar objects, as provided by the camera capture of Microsoft HoloLens or a camera connected to your PC for immersive (VR) headsets.

コースの結果

Azure Custom Vision は、開発者がカスタムイメージ分類子を構築できる Microsoft 認知サービスです。Azure Custom Vision is a Microsoft Cognitive Service which allows developers to build custom image classifiers. これらの分類子を新しいイメージと共に使用して、新しいイメージ内のオブジェクトを認識したり、分類したりすることができます。These classifiers can then be used with new images to recognize, or classify, objects within that new image. このサービスでは、簡単で使いやすいオンラインポータルを使用して、プロセスを効率化できます。The Service provides a simple, easy to use, online portal to streamline the process. 詳細については、 Azure Custom Vision Service のページを参照してください。For more information, visit the Azure Custom Vision Service page.

このコースが完了すると、2つのモードで動作できる mixed reality アプリケーションが完成します。Upon completion of this course, you will have a mixed reality application which will be able to work in two modes:

  • 分析モード: イメージをアップロードし、タグを作成し、さまざまなオブジェクト (この場合はマウスとキーボード) を認識するようにサービスをトレーニングすることによって、Custom Vision Service を手動で設定します。Analysis Mode: setting up the Custom Vision Service manually by uploading images, creating tags, and training the Service to recognize different objects (in this case mouse and keyboard). 次に、カメラを使用してイメージをキャプチャする HoloLens アプリを作成し、実際の環境でそれらのオブジェクトを認識します。You will then create a HoloLens app that will capture images using the camera, and try to recognize those objects in the real world.

  • トレーニングモード: アプリで "トレーニングモード" を有効にするコードを実装します。Training Mode: you will implement code that will enable a "Training Mode" in your app. トレーニングモードでは、HoloLens のカメラを使用してイメージをキャプチャし、キャプチャしたイメージをサービスにアップロードして、カスタムビジョンモデルをトレーニングすることができます。The training mode will allow you to capture images using the HoloLens' camera, upload the captured images to the Service, and train the custom vision model.

このコースでは、Custom Vision Service から Unity ベースのサンプルアプリケーションに結果を取得する方法について説明します。This course will teach you how to get the results from the Custom Vision Service into a Unity-based sample application. これらの概念は、構築しているカスタムアプリケーションに適用する必要があります。It will be up to you to apply these concepts to a custom application you might be building.

デバイス サポートDevice support

コースCourse HoloLensHoloLens イマーシブ ヘッドセットImmersive headsets
MR と Azure 302b:カスタム ビジョンMR and Azure 302b: Custom vision ✔️✔️ ✔️✔️

注意

このコースでは主に HoloLens に焦点を当てていますが、このコースで学習する内容を Windows Mixed Reality イマーシブ (VR) ヘッドセットにも適用できます。While this course primarily focuses on HoloLens, you can also apply what you learn in this course to Windows Mixed Reality immersive (VR) headsets. イマーシブ (VR) ヘッドセットにはアクセス可能なカメラがないため、外部カメラが PC に接続されている必要があります。Because immersive (VR) headsets do not have accessible cameras, you will need an external camera connected to your PC. コースを進めると、イマーシブ (VR) ヘッドセットをサポートするために必要な変更についての注意事項が表示されます。As you follow along with the course, you will see notes on any changes you might need to employ to support immersive (VR) headsets.

必須コンポーネントPrerequisites

注意

このチュートリアルは、Unity と C# の基本的な経験がある開発者向けに設計されています。This tutorial is designed for developers who have basic experience with Unity and C#. また、このドキュメントに記載されている前提条件と記述に記載されている手順は、作成時にテストおよび検証された内容 (2018 年7月) を表しています。Please also be aware that the prerequisites and written instructions within this document represent what has been tested and verified at the time of writing (July 2018). ツールのインストール 」の記事に記載されているように、最新のソフトウェアを自由に使用できます。ただし、このコースの情報は、以下に記載されているものより新しいソフトウェアの内容と完全に一致するとは限りません。You are free to use the latest software, as listed within the install the tools article, though it should not be assumed that the information in this course will perfectly match what you will find in newer software than what is listed below.

このコースでは、次のハードウェアとソフトウェアをお勧めします。We recommend the following hardware and software for this course:

開始する前にBefore you start

  1. このプロジェクトのビルドで問題が発生しないように、このチュートリアルで説明されているプロジェクトをルートまたはほぼルートフォルダーに作成することを強くお勧めします (長いフォルダーパスはビルド時に問題を引き起こす可能性があります)。To avoid encountering issues building this project, it is strongly suggested that you create the project mentioned in this tutorial in a root or near-root folder (long folder paths can cause issues at build-time).
  2. HoloLens をセットアップしてテストします。Set up and test your HoloLens. HoloLens のセットアップをサポートする必要がある場合は、 hololens セットアップに関する記事にアクセスしてください。If you need support setting up your HoloLens, make sure to visit the HoloLens setup article.
  3. 新しい HoloLens アプリの開発を開始するときは、調整とセンサーのチューニングを実行することをお勧めします (ユーザーごとにこれらのタスクを実行するのに役立つ場合があります)。It is a good idea to perform Calibration and Sensor Tuning when beginning developing a new HoloLens app (sometimes it can help to perform those tasks for each user).

調整の詳細については、 「HoloLens の調整に関する記事へのリンク」を参照してください。For help on Calibration, please follow this link to the HoloLens Calibration article.

センサーチューニングの詳細については、 HoloLens センサーチューニングに関する記事へのリンクを参照してください。For help on Sensor Tuning, please follow this link to the HoloLens Sensor Tuning article.

章 1-Custom Vision Service ポータルChapter 1 - The Custom Vision Service Portal

Azure で Custom Vision Service を使用するには、アプリケーションで使用できるようにサービスのインスタンスを構成する必要があります。To use the Custom Vision Service in Azure, you will need to configure an instance of the Service to be made available to your application.

  1. 最初に、 Custom Vision Service メインページに移動します。First, navigate to the Custom Vision Service main page.

  2. [Get Started] (開始) ボタンをクリックします。Click on the Get Started button.

    Custom Vision Service を使ってみる

  3. Custom Vision Service ポータルにサインインします。Sign in to the Custom Vision Service Portal.

    ポータルへのサインイン

    注意

    まだ Azure アカウントを持っていない場合は、アカウントを作成する必要があります。If you do not already have an Azure account, you will need to create one. このチュートリアルを教室またはラボの状況で行っている場合は、新しいアカウントの設定について、インストラクターまたはそのいずれかの対処を依頼してください。If you are following this tutorial in a classroom or lab situation, ask your instructor or one of the proctors for help setting up your new account.

  4. 初めてログインした後は、 サービスパネルの使用条件 を確認するメッセージが表示されます。Once you are logged in for the first time, you will be prompted with the Terms of Service panel. 条件に同意するには、チェックボックスをオンにします。Click on the checkbox to agree to the terms. [ 同意 する] をクリックします。Then click on I agree.

    サービス使用条件

  5. 使用条件に同意すると、ポータルの [ プロジェクト ] セクションに移動します。Having agreed to the Terms, you will be navigated to the Projects section of the Portal. [ 新しいプロジェクト] をクリックします。Click on New Project.

    新しいプロジェクトの作成

  6. 右側にタブが表示され、プロジェクトのフィールドを指定するように求められます。A tab will appear on the right-hand side, which will prompt you to specify some fields for the project.

    1. プロジェクトの 名前 を挿入します。Insert a Name for your project.

    2. プロジェクトの 説明 を挿入します (省略可能)。Insert a Description for your project (optional).

    3. リソースグループを選択するか、新しい リソースグループ を作成します。Choose a Resource Group or create a new one. リソースグループは、Azure 資産のコレクションの課金を監視、制御する方法を提供します。A resource group provides a way to monitor, control access, provision and manage billing for a collection of Azure assets. 1つのプロジェクトに関連付けられているすべての Azure サービス (たとえば、これらのコースなど) を共通のリソースグループに保持することをお勧めします。It is recommended to keep all the Azure Services associated with a single project (e.g. such as these courses) under a common resource group).

    4. プロジェクトの 種類分類 に設定するSet the Project Types to Classification

    5. ドメイン全般 として設定します。Set the Domains as General.

      ドメインを設定する

      Azure リソースグループの詳細については、 リソースグループに関する記事をご覧ください。If you wish to read more about Azure Resource Groups, please visit the resource group article.

  7. 完了すると、[プロジェクトの 作成] をクリックすると、[Custom Vision Service、プロジェクト] ページにリダイレクトされます。Once you are finished, click on Create project, you will be redirected to the Custom Vision Service, project page.

第2章-Custom Vision プロジェクトのトレーニングChapter 2 - Training your Custom Vision project

Custom Vision ポータルでは、主な目的は、イメージ内の特定のオブジェクトを認識するようにプロジェクトをトレーニングすることです。Once in the Custom Vision portal, your primary objective is to train your project to recognize specific objects in images. アプリケーションで認識するオブジェクトごとに、少なくとも5つのイメージが必要ですが、10 (10) が推奨されます。You need at least five (5) images, though ten (10) is preferred, for each object that you would like your application to recognize. このコースに用意されているイメージ (コンピューターマウスとキーボード) を使用できます。You can use the images provided with this course (a computer mouse and a keyboard).

Custom Vision Service プロジェクトをトレーニングするには:To train your Custom Vision Service project:

  1. [タグ] の横にあるボタンをクリックし + ます。Click on the + button next to Tags.

    新しいタグを追加する

  2. 認識するオブジェクトの 名前 を追加します。Add the name of the object you would like to recognize. [Save] をクリックします。Click on Save.

    オブジェクト名を追加して保存

  3. タグ が追加されていることがわかります (表示するには、ページの再読み込みが必要になる場合があります)。You will notice your Tag has been added (you may need to reload your page for it to appear). まだ確認されていない場合は、新しいタグの横にあるチェックボックスをクリックします。Click the checkbox alongside your new tag, if it is not already checked.

    新しいタグを有効にする

  4. ページの中央にある [ イメージの追加 ] をクリックします。Click on Add Images in the center of the page.

    画像の追加

  5. [ ローカルファイルの参照] をクリックし、アップロードするイメージを検索して選択します。最小値は 5 (5) です。Click on Browse local files, and search, then select, the images you would like to upload, with the minimum being five (5). これらのイメージには、トレーニングするオブジェクトが含まれている必要があることに注意してください。Remember all of these images should contain the object which you are training.

    注意

    アップロードには、一度に複数のイメージを選択できます。You can select several images at a time, to upload.

  6. タブに画像が表示されたら、 [マイタグ ] ボックスで適切なタグを選択します。Once you can see the images in the tab, select the appropriate tag in the My Tags box.

    タグの選択

  7. [ ファイルのアップロード] をクリックします。Click on Upload files. ファイルのアップロードが開始されます。The files will begin uploading. アップロードの確認が完了したら、[ 完了] をクリックします。Once you have confirmation of the upload, click Done.

    ファイルのアップロード

  8. 同じプロセスを繰り返して、キーボード という名前の新しい タグ を作成し、適切な写真をアップロードします。Repeat the same process to create a new Tag named Keyboard and upload the appropriate photos for it. 新しいタグを作成したら、マウスオフ にして、[イメージの 追加] ウィンドウを表示します。Make sure to uncheck Mouse once you have created the new tags, so to show the Add images window.

  9. 両方のタグが設定されたら、[ トレーニング] をクリックすると、最初のトレーニングイテレーションがビルドを開始します。Once you have both Tags set up, click on Train, and the first training iteration will start building.

    トレーニングイテレーションの有効化

  10. ビルドが完了すると、[既定と 予測 URL作成] という2つのボタンが表示されます。Once it's built, you'll be able to see two buttons called Make default and Prediction URL. [ 既定値 に設定] をクリックし、[ 予測 URL] をクリックします。Click on Make default first, then click on Prediction URL.

    既定の URL と予測 URL を作成する

    注意

    このから提供されるエンドポイント URL は、既定としてマークされている イテレーション のいずれかに設定されます。The endpoint URL which is provided from this, is set to whichever Iteration has been marked as default. そのため、後で新しい イテレーション を作成して既定として更新する場合は、コードを変更する必要はありません。As such, if you later make a new Iteration and update it as default, you will not need to change your code.

  11. 予測 url をクリックしたら、メモ帳 を開き、 url予測キー をコピーして貼り付けます。これにより、後でコード内で必要になったときに取得できるようになります。Once you have clicked on Prediction URL, open Notepad, and copy and paste the URL and the Prediction-Key, so that you can retrieve it when you need it later in the code.

    URL と Prediction-Key をコピーして貼り付ける

  12. 画面の右上にある 歯車 をクリックします。Click on the Cog at the top right of the screen.

    歯車アイコンをクリックして設定を開く

  13. トレーニングキー をコピーし、メモ帳 に貼り付けて、後で使用できるようにします。Copy the Training Key and paste it into a Notepad, for later use.

    トレーニングキーのコピー

  14. また、 プロジェクト Id もコピーし、 メモ帳 ファイルに貼り付けて、後で使用できるようにします。Also copy your Project Id, and also paste it into your Notepad file, for later use.

    プロジェクト id のコピー

章 3-Unity プロジェクトの設定Chapter 3 - Set up the Unity project

次に示すのは、mixed reality で開発するための一般的な設定です。そのため、他のプロジェクトに適したテンプレートです。The following is a typical set up for developing with mixed reality, and as such, is a good template for other projects.

  1. Unity を開き、[新規] をクリックします。Open Unity and click New.

    新しい Unity プロジェクトを作成する

  2. ここで、Unity プロジェクト名を指定する必要があります。You will now need to provide a Unity project name. AzureCustomVision を挿入します。Insert AzureCustomVision. プロジェクトテンプレートが 3d に設定されていることを確認します。Make sure the project template is set to 3D. 場所を適切な 場所 に設定します (ルートディレクトリの方が適していることに注意してください)。Set the Location to somewhere appropriate for you (remember, closer to root directories is better). 次に、[ プロジェクトの作成] をクリックします。Then, click Create project.

    プロジェクト設定の構成

  3. Unity を開いている場合は、[既定の スクリプトエディター ] が Visual Studio に設定されていることを確認する必要があります。With Unity open, it is worth checking the default Script Editor is set to Visual Studio. [ Edit > 設定 の編集] に移動し、新しいウィンドウで [外部ツール] に移動します。Go to Edit > Preferences and then from the new window, navigate to External Tools. 外部スクリプトエディターVisual Studio 2017 に変更します。Change External Script Editor to Visual Studio 2017. [ 基本設定 ] ウィンドウを閉じます。Close the Preferences window.

    外部ツールの構成

  4. 次に、[ ファイル > ビルド設定 ] に移動し、[ ユニバーサル Windows プラットフォーム] を選択します。次に、[ プラットフォームの切り替え ] ボタンをクリックして選択内容を適用します。Next, go to File > Build Settings and select Universal Windows Platform, then click on the Switch Platform button to apply your selection.

    ビルド設定の構成Configure build settings

  5. それでも ファイル > ビルド設定 を行い、次のことを確認します。While still in File > Build Settings and make sure that:

    1. ターゲットデバイスHoloLens に設定されていますTarget Device is set to HoloLens

      イマーシブヘッドセットの場合は、 ターゲットデバイス任意のデバイス に設定します。For the immersive headsets, set Target Device to Any Device.

    2. ビルドの種類D3D に設定されていますBuild Type is set to D3D

    3. SDK は最新の インストール に設定されていますSDK is set to Latest installed

    4. Visual Studio のバージョン が、インストールされている最新 バージョンに設定されていますVisual Studio Version is set to Latest installed

    5. ビルドと実行ローカルコンピューター に設定されていますBuild and Run is set to Local Machine

    6. シーンを保存し、ビルドに追加します。Save the scene and add it to the build.

      1. これを行うには、[開いている シーンの追加] を選択します。Do this by selecting Add Open Scenes. 保存ウィンドウが表示されます。A save window will appear.

        開いているシーンをビルドリストに追加

      2. この新しいフォルダーを作成し、今後のシーンに加えて、[ 新しいフォルダー ] ボタンを選択します。新しいフォルダーを作成するには、名前を「 シーン」にします。Create a new folder for this, and any future, scene, then select the New folder button, to create a new folder, name it Scenes.

        新しいシーンフォルダーの作成

      3. 新しく作成した [ シーン ] フォルダーを開き、[ ファイル名: テキスト] フィールドに「 CustomVisionScene」と入力し、[ 保存] をクリックします。Open your newly created Scenes folder, and then in the File name: text field, type CustomVisionScene, then click on Save.

        新しいシーンファイルに名前を指定

        Unity プロジェクトに関連付けられている必要があるため、Unity のシーンを Assets フォルダー内に保存する必要があります。Be aware, you must save your Unity scenes within the Assets folder, as they must be associated with the Unity project. Unity プロジェクトを構成する一般的な方法は、シーンフォルダー (およびその他の同様のフォルダー) を作成することです。Creating the scenes folder (and other similar folders) is a typical way of structuring a Unity project.

    7. それ以外の設定は、[ ビルド設定] の [既定] のままにしておきます。The remaining settings, in Build Settings, should be left as default for now.

      既定のビルド設定

  6. [ ビルドの設定 ] ウィンドウで、[ プレーヤーの設定 ] ボタンをクリックします。これにより、 インスペクター が配置されている領域の関連パネルが開きます。In the Build Settings window, click on the Player Settings button, this will open the related panel in the space where the Inspector is located.

  7. このパネルでは、いくつかの設定を確認する必要があります。In this panel, a few settings need to be verified:

    1. [ その他の設定 ] タブで、次のようにします。In the Other Settings tab:

      1. Scripting Runtime のバージョン実験的 (.Net 4.6 と同等) である必要があります。これにより、エディターを再起動する必要が生じます。Scripting Runtime Version should be Experimental (.NET 4.6 Equivalent), which will trigger a need to restart the Editor.

      2. バックエンド.net である必要がありますScripting Backend should be .NET

      3. API 互換性レベル.net 4.6 である必要がありますAPI Compatibility Level should be .NET 4.6

      API compantiblity の設定

    2. [ 発行の設定 ] タブの [ 機能] で、次の項目を確認します。Within the Publishing Settings tab, under Capabilities, check:

      1. InternetClientInternetClient

      2. Web カメラWebcam

      3. マイクMicrophone

      発行の設定を構成する

    3. パネルの下にある [ XR settings (発行の 設定] の下にあります) で、[ サポートされている仮想現実] をティックし、 Windows Mixed reality SDK が追加されていることを確認します。Further down the panel, in XR Settings (found below Publish Settings), tick Virtual Reality Supported, make sure the Windows Mixed Reality SDK is added.

    XR 設定の構成

  8. ビルド設定 に戻る Unity C # プロジェクト はグレーで表示されなくなりました。この横にあるチェックボックスをオンにします。Back in Build Settings Unity C# Projects is no longer greyed out; tick the checkbox next to this.

  9. [ビルド設定] ウィンドウを閉じます。Close the Build Settings window.

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

章 4-Unity での Newtonsoft DLL のインポートChapter 4 - Importing the Newtonsoft DLL in Unity

重要

このコースの Unity セットアップ コンポーネントをスキップし、コードに直接進む場合は、この Azure-MR-302bをダウンロードし、 カスタムパッケージとしてプロジェクトにインポートしてから、 第6章から続行してください。If you wish to skip the Unity Set up component of this course, and continue straight into code, feel free to download this Azure-MR-302b.unitypackage, import it into your project as a Custom Package, and then continue from Chapter 6.

このコースでは、 Newtonsoft ライブラリを使用する必要があります。これは、アセットに DLL として追加できます。This course requires the use of the Newtonsoft library, which you can add as a DLL to your assets. このライブラリを含むパッケージは、 このリンクからダウンロードできます。The package containing this library can be downloaded from this Link. Newtonsoft ライブラリをプロジェクトにインポートするには、このコースに付属している Unity パッケージを使用します。To import the Newtonsoft library into your project, use the Unity Package which came with this course.

  1. [ アセット > インポート**パッケージ の > カスタム**パッケージ ] メニューオプションを使用して、 unitypackage を Unity に追加します。Add the .unitypackage to Unity by using the Assets > Import Package > Custom Package menu option.

  2. ポップアップ表示された [ Unity パッケージのインポート ] ボックスで、 プラグイン (およびそれを含む) のすべてが選択されていることを確認します。In the Import Unity Package box that pops up, ensure everything under (and including) Plugins is selected.

    すべてのパッケージアイテムをインポートする

  3. [ インポート ] ボタンをクリックして、プロジェクトに項目を追加します。Click the Import button to add the items to your project.

  4. プロジェクトビューの [プラグイン] の下にある newtonsoft フォルダーにアクセスし、プラグインの [ Newtonsoft.Js] を選択します。Go to the Newtonsoft folder under Plugins in the project view and select the Newtonsoft.Json plugin.

    Newtonsoft プラグインを選択します。

  5. [ Newtonsoft.Jsのプラグイン ] を選択した状態で、任意の プラットフォームオフ になっていることを確認し、[ wsaplayer ] も オフ になっていることを確認して、[ 適用] をクリックします。With the Newtonsoft.Json plugin selected, ensure that Any Platform is unchecked, then ensure that WSAPlayer is also unchecked, then click Apply. これは、ファイルが正しく構成されていることを確認するためのものです。This is just to confirm that the files are configured correctly.

    Newtonsoft プラグインの構成

    注意

    これらのプラグインをマークすると、Unity エディターでのみ使用するように構成されます。Marking these plugins configures them to only be used in the Unity Editor. WSA フォルダーには、Unity からプロジェクトがエクスポートされた後に使用される、異なるセットがあります。There are a different set of them in the WSA folder which will be used after the project is exported from Unity.

  6. 次に、 Newtonsoft フォルダー内の WSA フォルダーを開く必要があります。Next, you need to open the WSA folder, within the Newtonsoft folder. 先ほど構成したものと同じファイルのコピーが表示されます。You will see a copy of the same file you just configured. ファイルを選択し、インスペクターで次のことを確認します。Select the file, and then in the inspector, ensure that

    • すべてのプラットフォームオフ になっていますAny Platform is unchecked
    • only wsaplayer のみが チェック されますonly WSAPlayer is checked
    • 処理 されないかどうかを 確認 しますDont process is checked

    Newtonsoft plugin platform の設定を構成する

第5章-カメラの設定Chapter 5 - Camera setup

  1. [階層] パネルで、 メインカメラ を選択します。In the Hierarchy Panel, select the Main Camera.

  2. 選択すると、 メインカメラ のすべてのコンポーネントが [ インスペクター] パネル に表示されます。Once selected, you will be able to see all the components of the Main Camera in the Inspector Panel.

    1. カメラ オブジェクトは メインカメラ という名前にする必要があります (スペルに注意してください)。The camera object must be named Main Camera (note the spelling!)

    2. メインカメラの タグ は、 maincamera に設定する必要があります (スペルに注意してください)。The Main Camera Tag must be set to MainCamera (note the spelling!)

    3. 変換位置0、0、0 に設定されていることを確認します。Make sure the Transform Position is set to 0, 0, 0

    4. クリアフラグ純色 に設定します (イマーシブヘッドセットの場合は無視します)。Set Clear Flags to Solid Color (ignore this for immersive headset).

    5. カメラコンポーネントの 背景 色を 黒、アルファ 0 (16 進コード: #00000000) に設定します (イマーシブヘッドセットの場合は無視します)。Set the Background Color of the camera Component to Black, Alpha 0 (Hex Code: #00000000) (ignore this for immersive headset).

    カメラコンポーネントのプロパティの構成

Chapter 6-CustomVisionAnalyser クラスを作成するChapter 6 - Create the CustomVisionAnalyser class.

この時点で、コードを記述する準備ができました。At this point you are ready to write some code.

最初に、 CustomVisionAnalyser クラスを使用します。You will begin with the CustomVisionAnalyser class.

注意

次に示すコードで行われた Custom Vision Service の呼び出しは、 Custom Vision REST API を使用して行われます。The calls to the Custom Vision Service made in the code shown below are made using the Custom Vision REST API. これを使用すると、この API を実装して使用する方法を確認できます (独自のものを実装する方法を理解するために役立ちます)。Through using this, you will see how to implement and make use of this API (useful for understanding how to implement something similar on your own). Microsoft では、サービスの呼び出しを行うために使用できる CUSTOM VISION SERVICE SDK を提供していることに注意してください。Be aware, that Microsoft offers a Custom Vision Service SDK that can also be used to make calls to the Service. 詳細については、 CUSTOM VISION SERVICE SDK に関する記事をご覧ください。For more information visit the Custom Vision Service SDK article.

このクラスの役割は次のとおりです。This class is responsible for:

  • バイト配列としてキャプチャされた最新のイメージを読み込んでいます。Loading the latest image captured as an array of bytes.

  • 分析のために、Azure Custom Vision Service インスタンスにバイト配列を送信しています。Sending the byte array to your Azure Custom Vision Service instance for analysis.

  • JSON 文字列として応答を受信しています。Receiving the response as a JSON string.

  • 応答を逆シリアル化し、結果の 予測SceneOrganiser クラスに渡します。これにより、応答の表示方法が決まります。Deserializing the response and passing the resulting Prediction to the SceneOrganiser class, which will take care of how the response should be displayed.

このクラスを作成するには:To create this class:

  1. [プロジェクト] パネル にある [アセット] フォルダー を右クリックし、[ > フォルダーの作成] をクリックします。Right-click in the Asset Folder located in the Project Panel, then click Create > Folder. フォルダー スクリプト を呼び出します。Call the folder Scripts.

    スクリプトフォルダーの作成

  2. 作成したばかりのフォルダーをダブルクリックして開きます。Double-click on the folder just created, to open it.

  3. フォルダー内を右クリックし、[ Create > C # スクリプト の作成] をクリックします。Right-click inside the folder, then click Create > C# Script. スクリプトに CustomVisionAnalyser という名前を指定します。Name the script CustomVisionAnalyser.

  4. 新しい CustomVisionAnalyser スクリプトをダブルクリックして、 Visual Studio で開きます。Double-click on the new CustomVisionAnalyser script to open it with Visual Studio.

  5. ファイルの先頭にある名前空間を次のように更新します。Update the namespaces at the top of your file to match the following:

    using System.Collections;
    using System.IO;
    using UnityEngine;
    using UnityEngine.Networking;
    using Newtonsoft.Json;
    
  6. CustomVisionAnalyser クラスに、次の変数を追加します。In the CustomVisionAnalyser class, add the following variables:

        /// <summary>
        /// Unique instance of this class
        /// </summary>
        public static CustomVisionAnalyser Instance;
    
        /// <summary>
        /// Insert your Prediction Key here
        /// </summary>
        private string predictionKey = "- Insert your key here -";
    
        /// <summary>
        /// Insert your prediction endpoint here
        /// </summary>
        private string predictionEndpoint = "Insert your prediction endpoint here";
    
        /// <summary>
        /// Byte array of the image to submit for analysis
        /// </summary>
        [HideInInspector] public byte[] imageBytes;
    

    注意

    予測キーpredictionKey 変数に挿入し、予測エンドポイントpredictionEndpoint 変数に挿入してください。Make sure you insert your Prediction Key into the predictionKey variable and your Prediction Endpoint into the predictionEndpoint variable. これらは、コースの前の メモ帳 にコピーしました。You copied these to Notepad earlier in the course.

  7. インスタンス変数を初期化するには、起動前 () のコードを追加する必要があります。Code for Awake() now needs to be added to initialize the Instance variable:

        /// <summary>
        /// Initialises this class
        /// </summary>
        private void Awake()
        {
            // Allows this instance to behave like a singleton
            Instance = this;
        }
    
  8. Start () および Update () メソッドを削除します。Delete the methods Start() and Update().

  9. 次に、コルーチン (static GetImageAsByteArray () メソッドをその下に追加) を追加します。これにより、 imagecapture クラスによってキャプチャされたイメージの分析結果が得られます。Next, add the coroutine (with the static GetImageAsByteArray() method below it), which will obtain the results of the analysis of the image captured by the ImageCapture class.

    注意

    分析 Seimagecapture コルーチンには、まだ作成していない SceneOrganiser クラスの呼び出しがあります。In the AnalyseImageCapture coroutine, there is a call to the SceneOrganiser class that you are yet to create. そのため、 これらの行はコメントの付いたままに しておきます。Therefore, leave those lines commented for now.

        /// <summary>
        /// Call the Computer Vision Service to submit the image.
        /// </summary>
        public IEnumerator AnalyseLastImageCaptured(string imagePath)
        {
            WWWForm webForm = new WWWForm();
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Post(predictionEndpoint, webForm))
            {
                // Gets a byte array out of the saved image
                imageBytes = GetImageAsByteArray(imagePath);
    
                unityWebRequest.SetRequestHeader("Content-Type", "application/octet-stream");
                unityWebRequest.SetRequestHeader("Prediction-Key", predictionKey);
    
                // The upload handler will help uploading the byte array with the request
                unityWebRequest.uploadHandler = new UploadHandlerRaw(imageBytes);
                unityWebRequest.uploadHandler.contentType = "application/octet-stream";
    
                // The download handler will help receiving the analysis from Azure
                unityWebRequest.downloadHandler = new DownloadHandlerBuffer();
    
                // Send the request
                yield return unityWebRequest.SendWebRequest();
    
                string jsonResponse = unityWebRequest.downloadHandler.text;
    
                // The response will be in JSON format, therefore it needs to be deserialized    
    
                // The following lines refers to a class that you will build in later Chapters
                // Wait until then to uncomment these lines
    
                //AnalysisObject analysisObject = new AnalysisObject();
                //analysisObject = JsonConvert.DeserializeObject<AnalysisObject>(jsonResponse);
                //SceneOrganiser.Instance.SetTagsToLastLabel(analysisObject);
            }
        }
    
        /// <summary>
        /// Returns the contents of the specified image 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);
        }
    
  10. Unity に戻る前に、変更内容を Visual Studio に保存してください。Be sure to save your changes in Visual Studio before returning to Unity.

第7章-CustomVisionObjects クラスの作成Chapter 7 - Create the CustomVisionObjects class

ここで作成するクラスは、 CustomVisionObjects クラスです。The class you will create now is the CustomVisionObjects class.

このスクリプトには、 Custom Vision Service に対する呼び出しをシリアル化および逆シリアル化するために、他のクラスによって使用される多数のオブジェクトが含まれています。This script contains a number of objects used by other classes to serialize and deserialize the calls made to the Custom Vision Service.

警告

次の JSON 構造が Custom Vision 予測v2.0 で動作するように設定されているため、Custom Vision Service によって提供されるエンドポイントをメモしておくことが重要です。It is important that you take note of the endpoint that the Custom Vision Service provides you, as the below JSON structure has been set up to work with Custom Vision Prediction v2.0. バージョンが異なる場合は、以下の構造を更新する必要がある場合があります。If you have a different version, you may need to update the below structure.

このクラスを作成するには:To create this class:

  1. Scripts フォルダー内を右クリックし、[ Create > C # Script] をクリックします。Right-click inside the Scripts folder, then click Create > C# Script. スクリプト CustomVisionObjects を呼び出します。Call the script CustomVisionObjects.

  2. 新しい CustomVisionObjects スクリプトをダブルクリックして、 Visual Studio で開きます。Double-click on the new CustomVisionObjects script to open it with Visual Studio.

  3. ファイルの先頭に次の名前空間を追加します。Add the following namespaces to the top of the file:

    using System;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Networking;
    
  4. CustomVisionObjects クラス内の Start () および Update () メソッドを削除します。これで、このクラスは空になります。Delete the Start() and Update() methods inside the CustomVisionObjects class; this class should now be empty.

  5. CustomVisionObjects クラスの に次のクラスを追加します。Add the following classes outside the CustomVisionObjects class. これらのオブジェクトは、応答データをシリアル化および逆シリアル化するために Newtonsoft ライブラリによって使用されます。These objects are used by the Newtonsoft library to serialize and deserialize the response data:

    // The objects contained in this script represent the deserialized version
    // of the objects used by this application 
    
    /// <summary>
    /// Web request object for image data
    /// </summary>
    class MultipartObject : IMultipartFormSection
    {
        public string sectionName { get; set; }
    
        public byte[] sectionData { get; set; }
    
        public string fileName { get; set; }
    
        public string contentType { get; set; }
    }
    
    /// <summary>
    /// JSON of all Tags existing within the project
    /// contains the list of Tags
    /// </summary> 
    public class Tags_RootObject
    {
        public List<TagOfProject> Tags { get; set; }
        public int TotalTaggedImages { get; set; }
        public int TotalUntaggedImages { get; set; }
    }
    
    public class TagOfProject
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public int ImageCount { get; set; }
    }
    
    /// <summary>
    /// JSON of Tag to associate to an image
    /// Contains a list of hosting the tags,
    /// since multiple tags can be associated with one image
    /// </summary> 
    public class Tag_RootObject
    {
        public List<Tag> Tags { get; set; }
    }
    
    public class Tag
    {
        public string ImageId { get; set; }
        public string TagId { get; set; }
    }
    
    /// <summary>
    /// JSON of Images submitted
    /// Contains objects that host detailed information about one or more images
    /// </summary> 
    public class ImageRootObject
    {
        public bool IsBatchSuccessful { get; set; }
        public List<SubmittedImage> Images { get; set; }
    }
    
    public class SubmittedImage
    {
        public string SourceUrl { get; set; }
        public string Status { get; set; }
        public ImageObject Image { get; set; }
    }
    
    public class ImageObject
    {
        public string Id { get; set; }
        public DateTime Created { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public string ImageUri { get; set; }
        public string ThumbnailUri { get; set; }
    }
    
    /// <summary>
    /// JSON of Service Iteration
    /// </summary> 
    public class Iteration
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public bool IsDefault { get; set; }
        public string Status { get; set; }
        public string Created { get; set; }
        public string LastModified { get; set; }
        public string TrainedAt { get; set; }
        public string ProjectId { get; set; }
        public bool Exportable { get; set; }
        public string DomainId { get; set; }
    }
    
    /// <summary>
    /// Predictions received by the Service after submitting an image for analysis
    /// </summary> 
    [Serializable]
    public class AnalysisObject
    {
        public List<Prediction> Predictions { get; set; }
    }
    
    [Serializable]
    public class Prediction
    {
        public string TagName { get; set; }
        public double Probability { get; set; }
    }
    

章 8-VoiceRecognizer クラスを作成するChapter 8 - Create the VoiceRecognizer class

このクラスは、ユーザーからの音声入力を認識します。This class will recognize the voice input from the user.

このクラスを作成するには:To create this class:

  1. Scripts フォルダー内を右クリックし、[ Create > C # Script] をクリックします。Right-click inside the Scripts folder, then click Create > C# Script. スクリプト VoiceRecognizer を呼び出します。Call the script VoiceRecognizer.

  2. 新しい VoiceRecognizer スクリプトをダブルクリックして、 Visual Studio で開きます。Double-click on the new VoiceRecognizer script to open it with Visual Studio.

  3. VoiceRecognizer クラスの上に次の名前空間を追加します。Add the following namespaces above the VoiceRecognizer class:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.Windows.Speech;
    
  4. 次に、 Start () メソッドの上に、 VoiceRecognizer クラス内に次の変数を追加します。Then add the following variables inside the VoiceRecognizer class, above the Start() method:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static VoiceRecognizer Instance;
    
        /// <summary>
        /// Recognizer class for voice recognition
        /// </summary>
        internal KeywordRecognizer keywordRecognizer;
    
        /// <summary>
        /// List of Keywords registered
        /// </summary>
        private Dictionary<string, Action> _keywords = new Dictionary<string, Action>();
    
  5. 起動前 () および 開始 () メソッドを追加します。後者の場合、タグをイメージに関連付けるときに認識されるユーザー キーワード が設定されます。Add the Awake() and Start() methods, the latter of which will set up the user keywords to be recognized when associating a tag to an image:

        /// <summary>
        /// Called on initialization
        /// </summary>
        private void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Runs at initialization right after Awake method
        /// </summary>
        void Start ()
        {
    
            Array tagsArray = Enum.GetValues(typeof(CustomVisionTrainer.Tags));
    
            foreach (object tagWord in tagsArray)
            {
                _keywords.Add(tagWord.ToString(), () =>
                {
                    // When a word is recognized, the following line will be called
                    CustomVisionTrainer.Instance.VerifyTag(tagWord.ToString());
                });
            }
    
            _keywords.Add("Discard", () =>
            {
                // When a word is recognized, the following line will be called
                // The user does not want to submit the image
                // therefore ignore and discard the process
                ImageCapture.Instance.ResetImageCapture();
                keywordRecognizer.Stop();
            });
    
            //Create the keyword recognizer 
            keywordRecognizer = new KeywordRecognizer(_keywords.Keys.ToArray());
    
            // Register for the OnPhraseRecognized event 
            keywordRecognizer.OnPhraseRecognized += KeywordRecognizer_OnPhraseRecognized;
        }
    
  6. Update () メソッドを削除します。Delete the Update() method.

  7. 次のハンドラーを追加します。これは、音声入力が認識されるたびに呼び出されます。Add the following handler, which is called whenever voice input is recognized:

        /// <summary>
        /// Handler called when a word is recognized
        /// </summary>
        private void KeywordRecognizer_OnPhraseRecognized(PhraseRecognizedEventArgs args)
        {
            Action keywordAction;
            // if the keyword recognized is in our dictionary, call that Action.
            if (_keywords.TryGetValue(args.text, out keywordAction))
            {
                keywordAction.Invoke();
            }
        }
    
  8. Unity に戻る前に、変更内容を Visual Studio に保存してください。Be sure to save your changes in Visual Studio before returning to Unity.

注意

エラーが発生する可能性のあるコードについては気にしないでください。これにより、後でクラスを修正することになります。Do not worry about code which might appear to have an error, as you will provide further classes soon, which will fix these.

第9章-CustomVisionTrainer クラスの作成Chapter 9 - Create the CustomVisionTrainer class

このクラスは、一連の web 呼び出しをチェーンして、 Custom Vision Service をトレーニングします。This class will chain a series of web calls to train the Custom Vision Service. 各呼び出しの詳細については、コードの上に説明します。Each call will be explained in detail right above the code.

このクラスを作成するには:To create this class:

  1. Scripts フォルダー内を右クリックし、[ Create > C # Script] をクリックします。Right-click inside the Scripts folder, then click Create > C# Script. スクリプト CustomVisionTrainer を呼び出します。Call the script CustomVisionTrainer.

  2. 新しい CustomVisionTrainer スクリプトをダブルクリックして、 Visual Studio で開きます。Double-click on the new CustomVisionTrainer script to open it with Visual Studio.

  3. CustomVisionTrainer クラスの上に次の名前空間を追加します。Add the following namespaces above the CustomVisionTrainer class:

    using Newtonsoft.Json;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using UnityEngine;
    using UnityEngine.Networking;
    
  4. 次に、 Start () メソッドの上に、 CustomVisionTrainer クラス内に次の変数を追加します。Then add the following variables inside the CustomVisionTrainer class, above the Start() method.

    注意

    ここで使用されているトレーニング URL は Custom Vision トレーニング 1.2 のドキュメントに記載されており、の構造は次のとおりです。 https://southcentralus.api.cognitive.microsoft.com/customvision/v1.2/Training/projects/{projectId}/The training URL used here is provided within the Custom Vision Training 1.2 documentation, and has a structure of: https://southcentralus.api.cognitive.microsoft.com/customvision/v1.2/Training/projects/{projectId}/
    詳細については、 Custom Vision トレーニング v2.0 リファレンス API」を参照してください。For more information, visit the Custom Vision Training v1.2 reference API.

    警告

    Custom Vision Service がトレーニングモード用に提供するエンドポイントをメモしておくことが重要です。これは、( CustomVisionObjects クラス内で使用される) JSON 構造が Custom Vision トレーニングv1.0 で動作するように設定されているためです。It is important that you take note of the endpoint that the Custom Vision Service provides you for the training mode, as the JSON structure used (within the CustomVisionObjects class) has been set up to work with Custom Vision Training v1.2. バージョンが異なる場合は、 オブジェクト の構造を更新することが必要になる場合があります。If you have a different version, you may need to update the Objects structure.

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static CustomVisionTrainer Instance;
    
        /// <summary>
        /// Custom Vision Service URL root
        /// </summary>
        private string url = "https://southcentralus.api.cognitive.microsoft.com/customvision/v1.2/Training/projects/";
    
        /// <summary>
        /// Insert your prediction key here
        /// </summary>
        private string trainingKey = "- Insert your key here -";
    
        /// <summary>
        /// Insert your Project Id here
        /// </summary>
        private string projectId = "- Insert your Project Id here -";
    
        /// <summary>
        /// Byte array of the image to submit for analysis
        /// </summary>
        internal byte[] imageBytes;
    
        /// <summary>
        /// The Tags accepted
        /// </summary>
        internal enum Tags {Mouse, Keyboard}
    
        /// <summary>
        /// The UI displaying the training Chapters
        /// </summary>
        private TextMesh trainingUI_TextMesh;
    

    重要

    前にメモしておいた、 サービスキー (トレーニングキー) 値と プロジェクト Id 値を必ず追加してください。これらは、コースの 前の段階でポータルから収集した値です (第2章、手順10以降)Ensure that you add your Service Key (Training Key) value and Project Id value, which you noted down previous; these are the values you collected from the portal earlier in the course (Chapter 2, step 10 onwards).

  5. 次の Start () および「起動前 () 」の各メソッドを追加します。Add the following Start() and Awake() methods. これらのメソッドは初期化時に呼び出され、UI を設定するための呼び出しを含みます。Those methods are called on initialization and contain the call to set up the UI:

        /// <summary>
        /// Called on initialization
        /// </summary>
        private void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Runs at initialization right after Awake method
        /// </summary>
        private void Start()
        { 
            trainingUI_TextMesh = SceneOrganiser.Instance.CreateTrainingUI("TrainingUI", 0.04f, 0, 4, false);
        }
    
  6. Update () メソッドを削除します。Delete the Update() method. このクラスは、このクラスを必要としません。This class will not need it.

  7. Requesttagselection () メソッドを追加します。Add the RequestTagSelection() method. このメソッドは、イメージをキャプチャしてデバイスに格納し、 Custom Vision Service に送信してトレーニングする準備ができたときに最初に呼び出されるメソッドです。This method is the first to be called when an image has been captured and stored in the device and is now ready to be submitted to the Custom Vision Service, to train it. このメソッドは、トレーニング UI に、キャプチャされたイメージをタグ付けするためにユーザーが使用できる一連のキーワードを表示します。This method displays, in the training UI, a set of keywords the user can use to tag the image that has been captured. また、 VoiceRecognizer クラスに対して、ユーザーの音声入力のリッスンを開始するように通知します。It also alerts the VoiceRecognizer class to begin listening to the user for voice input.

        internal void RequestTagSelection()
        {
            trainingUI_TextMesh.gameObject.SetActive(true);
            trainingUI_TextMesh.text = $" \nUse voice command \nto choose between the following tags: \nMouse\nKeyboard \nor say Discard";
    
            VoiceRecognizer.Instance.keywordRecognizer.Start();
        }
    
  8. Verifytag () メソッドを追加します。Add the VerifyTag() method. このメソッドは、 VoiceRecognizer クラスによって認識される音声入力を受け取り、その有効性を確認してから、トレーニングプロセスを開始します。This method will receive the voice input recognized by the VoiceRecognizer class and verify its validity, and then begin the training process.

        /// <summary>
        /// Verify voice input against stored tags.
        /// If positive, it will begin the Service training process.
        /// </summary>
        internal void VerifyTag(string spokenTag)
        {
            if (spokenTag == Tags.Mouse.ToString() || spokenTag == Tags.Keyboard.ToString())
            {
                trainingUI_TextMesh.text = $"Tag chosen: {spokenTag}";
                VoiceRecognizer.Instance.keywordRecognizer.Stop();
                StartCoroutine(SubmitImageForTraining(ImageCapture.Instance.filePath, spokenTag));
            }
        }
    
  9. SubmitImageForTraining () メソッドを追加します。Add the SubmitImageForTraining() method. このメソッドは Custom Vision Service トレーニングプロセスを開始します。This method will begin the Custom Vision Service training process. 最初の手順では、ユーザーからの検証済み音声入力に関連付けられているサービスから タグ Id を取得します。The first step is to retrieve the Tag Id from the Service which is associated with the validated speech input from the user. タグ Id がイメージと共にアップロードされます。The Tag Id will then be uploaded along with the image.

        /// <summary>
        /// Call the Custom Vision Service to submit the image.
        /// </summary>
        public IEnumerator SubmitImageForTraining(string imagePath, string tag)
        {
            yield return new WaitForSeconds(2);
            trainingUI_TextMesh.text = $"Submitting Image \nwith tag: {tag} \nto Custom Vision Service";
            string imageId = string.Empty;
            string tagId = string.Empty;
    
            // Retrieving the Tag Id relative to the voice input
            string getTagIdEndpoint = string.Format("{0}{1}/tags", url, projectId);
            using (UnityWebRequest www = UnityWebRequest.Get(getTagIdEndpoint))
            {
                www.SetRequestHeader("Training-Key", trainingKey);
                www.downloadHandler = new DownloadHandlerBuffer();
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
    
                Tags_RootObject tagRootObject = JsonConvert.DeserializeObject<Tags_RootObject>(jsonResponse);
    
                foreach (TagOfProject tOP in tagRootObject.Tags)
                {
                    if (tOP.Name == tag)
                    {
                        tagId = tOP.Id;
                    }             
                }
            }
    
            // Creating the image object to send for training
            List<IMultipartFormSection> multipartList = new List<IMultipartFormSection>();
            MultipartObject multipartObject = new MultipartObject();
            multipartObject.contentType = "application/octet-stream";
            multipartObject.fileName = "";
            multipartObject.sectionData = GetImageAsByteArray(imagePath);
            multipartList.Add(multipartObject);
    
            string createImageFromDataEndpoint = string.Format("{0}{1}/images?tagIds={2}", url, projectId, tagId);
    
            using (UnityWebRequest www = UnityWebRequest.Post(createImageFromDataEndpoint, multipartList))
            {
                // Gets a byte array out of the saved image
                imageBytes = GetImageAsByteArray(imagePath);           
    
                //unityWebRequest.SetRequestHeader("Content-Type", "application/octet-stream");
                www.SetRequestHeader("Training-Key", trainingKey);
    
                // The upload handler will help uploading the byte array with the request
                www.uploadHandler = new UploadHandlerRaw(imageBytes);
    
                // The download handler will help receiving the analysis from Azure
                www.downloadHandler = new DownloadHandlerBuffer();
    
                // Send the request
                yield return www.SendWebRequest();
    
                string jsonResponse = www.downloadHandler.text;
    
                ImageRootObject m = JsonConvert.DeserializeObject<ImageRootObject>(jsonResponse);
                imageId = m.Images[0].Image.Id;
            }
            trainingUI_TextMesh.text = "Image uploaded";
            StartCoroutine(TrainCustomVisionProject());
        }
    
  10. TrainCustomVisionProject () メソッドを追加します。Add the TrainCustomVisionProject() method. イメージが送信され、タグが付けられると、このメソッドが呼び出されます。Once the image has been submitted and tagged, this method will be called. これにより、サービスに送信された以前のすべてのイメージに加え、アップロードしたイメージを使用してトレーニングされる新しいイテレーションが作成されます。It will create a new Iteration that will be trained with all the previous images submitted to the Service plus the image just uploaded. トレーニングが完了すると、このメソッドはメソッドを呼び出して、新しく作成された イテレーション既定 として設定します。これにより、分析に使用するエンドポイントがトレーニング済みの最新のイテレーションになります。Once the training has been completed, this method will call a method to set the newly created Iteration as Default, so that the endpoint you are using for analysis is the latest trained iteration.

        /// <summary>
        /// Call the Custom Vision Service to train the Service.
        /// It will generate a new Iteration in the Service
        /// </summary>
        public IEnumerator TrainCustomVisionProject()
        {
            yield return new WaitForSeconds(2);
    
            trainingUI_TextMesh.text = "Training Custom Vision Service";
    
            WWWForm webForm = new WWWForm();
    
            string trainProjectEndpoint = string.Format("{0}{1}/train", url, projectId);
    
            using (UnityWebRequest www = UnityWebRequest.Post(trainProjectEndpoint, webForm))
            {
                www.SetRequestHeader("Training-Key", trainingKey);
                www.downloadHandler = new DownloadHandlerBuffer();
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
                Debug.Log($"Training - JSON Response: {jsonResponse}");
    
                // A new iteration that has just been created and trained
                Iteration iteration = new Iteration();
                iteration = JsonConvert.DeserializeObject<Iteration>(jsonResponse);
    
                if (www.isDone)
                {
                    trainingUI_TextMesh.text = "Custom Vision Trained";
    
                    // Since the Service has a limited number of iterations available,
                    // we need to set the last trained iteration as default
                    // and delete all the iterations you dont need anymore
                    StartCoroutine(SetDefaultIteration(iteration)); 
                }
            }
        }
    
  11. Setdefaultiterfrom() メソッドを追加します。Add the SetDefaultIteration() method. このメソッドは、以前に作成され、トレーニングされたイテレーションを 既定 として設定します。This method will set the previously created and trained iteration as Default. 完了すると、このメソッドは、サービス内の既存のイテレーションを削除する必要があります。Once completed, this method will have to delete the previous iteration existing in the Service. このコースの執筆時点では、サービスに同時に存在できるイテレーションは最大で10個までに制限されています。At the time of writing this course, there is a limit of a maximum ten (10) iterations allowed to exist at the same time in the Service.

        /// <summary>
        /// Set the newly created iteration as Default
        /// </summary>
        private IEnumerator SetDefaultIteration(Iteration iteration)
        {
            yield return new WaitForSeconds(5);
            trainingUI_TextMesh.text = "Setting default iteration";
    
            // Set the last trained iteration to default
            iteration.IsDefault = true;
    
            // Convert the iteration object as JSON
            string iterationAsJson = JsonConvert.SerializeObject(iteration);
            byte[] bytes = Encoding.UTF8.GetBytes(iterationAsJson);
    
            string setDefaultIterationEndpoint = string.Format("{0}{1}/iterations/{2}", 
                                                            url, projectId, iteration.Id);
    
            using (UnityWebRequest www = UnityWebRequest.Put(setDefaultIterationEndpoint, bytes))
            {
                www.method = "PATCH";
                www.SetRequestHeader("Training-Key", trainingKey);
                www.SetRequestHeader("Content-Type", "application/json");
                www.downloadHandler = new DownloadHandlerBuffer();
    
                yield return www.SendWebRequest();
    
                string jsonResponse = www.downloadHandler.text;
    
                if (www.isDone)
                {
                    trainingUI_TextMesh.text = "Default iteration is set \nDeleting Unused Iteration";
                    StartCoroutine(DeletePreviousIteration(iteration));
                }
            }
        }
    
  12. DeletePreviousIteration () メソッドを追加します。Add the DeletePreviousIteration() method. このメソッドは、以前の既定以外のイテレーションを見つけて削除します。This method will find and delete the previous non-default iteration:

        /// <summary>
        /// Delete the previous non-default iteration.
        /// </summary>
        public IEnumerator DeletePreviousIteration(Iteration iteration)
        {
            yield return new WaitForSeconds(5);
    
            trainingUI_TextMesh.text = "Deleting Unused \nIteration";
    
            string iterationToDeleteId = string.Empty;
    
            string findAllIterationsEndpoint = string.Format("{0}{1}/iterations", url, projectId);
    
            using (UnityWebRequest www = UnityWebRequest.Get(findAllIterationsEndpoint))
            {
                www.SetRequestHeader("Training-Key", trainingKey);
                www.downloadHandler = new DownloadHandlerBuffer();
                yield return www.SendWebRequest();
    
                string jsonResponse = www.downloadHandler.text;
    
                // The iteration that has just been trained
                List<Iteration> iterationsList = new List<Iteration>();
                iterationsList = JsonConvert.DeserializeObject<List<Iteration>>(jsonResponse);
    
                foreach (Iteration i in iterationsList)
                {
                    if (i.IsDefault != true)
                    {
                        Debug.Log($"Cleaning - Deleting iteration: {i.Name}, {i.Id}");
                        iterationToDeleteId = i.Id;
                        break;
                    }
                }
            }
    
            string deleteEndpoint = string.Format("{0}{1}/iterations/{2}", url, projectId, iterationToDeleteId);
    
            using (UnityWebRequest www2 = UnityWebRequest.Delete(deleteEndpoint))
            {
                www2.SetRequestHeader("Training-Key", trainingKey);
                www2.downloadHandler = new DownloadHandlerBuffer();
                yield return www2.SendWebRequest();
                string jsonResponse = www2.downloadHandler.text;
    
                trainingUI_TextMesh.text = "Iteration Deleted";
                yield return new WaitForSeconds(2);
                trainingUI_TextMesh.text = "Ready for next \ncapture";
    
                yield return new WaitForSeconds(2);
                trainingUI_TextMesh.text = "";
                ImageCapture.Instance.ResetImageCapture();
            }
        }
    
  13. このクラスに最後に追加するメソッドは、 GetImageAsByteArray () メソッドです。このメソッドは、キャプチャしたイメージをバイト配列に変換するために、web 呼び出しで使用されます。The last method to add in this class is the GetImageAsByteArray() method, used on the web calls to convert the image captured into a byte array.

        /// <summary>
        /// Returns the contents of the specified image 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);
        }
    
  14. Unity に戻る前に、変更内容を Visual Studio に保存してください。Be sure to save your changes in Visual Studio before returning to Unity.

Chapter 10-SceneOrganiser クラスの作成Chapter 10 - Create the SceneOrganiser class

このクラスは次のことを行います。This class will:

  • メインカメラに接続するための Cursor オブジェクトを作成します。Create a Cursor object to attach to the Main Camera.

  • サービスが実際のオブジェクトを認識したときに表示される ラベル オブジェクトを作成します。Create a Label object that will appear when the Service recognizes the real-world objects.

  • 適切なコンポーネントをアタッチして、メインカメラを設定します。Set up the Main Camera by attaching the appropriate components to it.

  • 分析モード では、実行時に、メインカメラの位置を基準とした適切なワールド空間でラベルが生成され、Custom Vision Service から受信したデータが表示されます。When in Analysis Mode, spawn the Labels at runtime, in the appropriate world space relative to the position of the Main Camera, and display the data received from the Custom Vision Service.

  • トレーニングモード では、トレーニングプロセスのさまざまな段階を表示する UI を生成します。When in Training Mode, spawn the UI that will display the different stages of the training process.

このクラスを作成するには:To create this class:

  1. Scripts フォルダー内を右クリックし、[ Create > C # Script] をクリックします。Right-click inside the Scripts folder, then click Create > C# Script. スクリプトに SceneOrganiser という名前を指定します。Name the script SceneOrganiser.

  2. 新しい SceneOrganiser スクリプトをダブルクリックして、 Visual Studio で開きます。Double-click on the new SceneOrganiser script to open it with Visual Studio.

  3. 必要な名前空間は1つだけです。 SceneOrganiser クラスの上から他の名前空間を削除します。You will only need one namespace, remove the others from above the SceneOrganiser class:

    using UnityEngine;
    
  4. 次に、 Start () メソッドの上に、 SceneOrganiser クラス内に次の変数を追加します。Then add the following variables inside the SceneOrganiser class, above the Start() method:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static SceneOrganiser Instance;
    
        /// <summary>
        /// The cursor object attached to the camera
        /// </summary>
        internal GameObject cursor;
    
        /// <summary>
        /// The label used to display the analysis on the objects in the real world
        /// </summary>
        internal GameObject label;
    
        /// <summary>
        /// Object providing the current status of the camera.
        /// </summary>
        internal TextMesh cameraStatusIndicator;
    
        /// <summary>
        /// Reference to the last label positioned
        /// </summary>
        internal Transform lastLabelPlaced;
    
        /// <summary>
        /// Reference to the last label positioned
        /// </summary>
        internal TextMesh lastLabelPlacedText;
    
        /// <summary>
        /// Current threshold accepted for displaying the label
        /// Reduce this value to display the recognition more often
        /// </summary>
        internal float probabilityThreshold = 0.5f;
    
  5. Start () および Update () メソッドを削除します。Delete the Start() and Update() methods.

  6. 変数のすぐ下に、起動前 () メソッドを追加します。このメソッドは、クラスを初期化し、シーンを設定します。Right underneath the variables, add the Awake() method, which will initialize the class and set up the scene.

        /// <summary>
        /// Called on initialization
        /// </summary>
        private void Awake()
        {
            // Use this class instance as singleton
            Instance = this;
    
            // Add the ImageCapture class to this GameObject
            gameObject.AddComponent<ImageCapture>();
    
            // Add the CustomVisionAnalyser class to this GameObject
            gameObject.AddComponent<CustomVisionAnalyser>();
    
            // Add the CustomVisionTrainer class to this GameObject
            gameObject.AddComponent<CustomVisionTrainer>();
    
            // Add the VoiceRecogniser class to this GameObject
            gameObject.AddComponent<VoiceRecognizer>();
    
            // Add the CustomVisionObjects class to this GameObject
            gameObject.AddComponent<CustomVisionObjects>();
    
            // Create the camera Cursor
            cursor = CreateCameraCursor();
    
            // Load the label prefab as reference
            label = CreateLabel();
    
            // Create the camera status indicator label, and place it above where predictions
            // and training UI will appear.
            cameraStatusIndicator = CreateTrainingUI("Status Indicator", 0.02f, 0.2f, 3, true);
    
            // Set camera status indicator to loading.
            SetCameraStatus("Loading");
        }
    
  7. 次に、メインカメラカーソルを作成して配置する CreateCameraCursor () メソッドを追加し、 CreateLabel () メソッドを追加して、 分析ラベル オブジェクトを作成します。Now add the CreateCameraCursor() method that creates and positions the Main Camera cursor, and the CreateLabel() method, which creates the Analysis Label object.

        /// <summary>
        /// Spawns cursor for the Main Camera
        /// </summary>
        private GameObject CreateCameraCursor()
        {
            // Create a sphere as new cursor
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
            // Attach it to the camera
            newCursor.transform.parent = gameObject.transform;
    
            // Resize the new cursor
            newCursor.transform.localScale = new Vector3(0.02f, 0.02f, 0.02f);
    
            // Move it to the correct position
            newCursor.transform.localPosition = new Vector3(0, 0, 4);
    
            // Set the cursor color to red
            newCursor.GetComponent<Renderer>().material = new Material(Shader.Find("Diffuse"));
            newCursor.GetComponent<Renderer>().material.color = Color.green;
    
            return newCursor;
        }
    
        /// <summary>
        /// Create the analysis label object
        /// </summary>
        private GameObject CreateLabel()
        {
            // Create a sphere as new cursor
            GameObject newLabel = new GameObject();
    
            // Resize the new cursor
            newLabel.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f);
    
            // Creating the text of the label
            TextMesh t = newLabel.AddComponent<TextMesh>();
            t.anchor = TextAnchor.MiddleCenter;
            t.alignment = TextAlignment.Center;
            t.fontSize = 50;
            t.text = "";
    
            return newLabel;
        }
    
  8. SetCameraStatus () メソッドを追加します。このメソッドは、カメラの状態を提供するテキストメッシュを目的としたメッセージを処理します。Add the SetCameraStatus() method, which will handle messages intended for the text mesh providing the status of the camera.

        /// <summary>
        /// Set the camera status to a provided string. Will be coloured if it matches a keyword.
        /// </summary>
        /// <param name="statusText">Input string</param>
        public void SetCameraStatus(string statusText)
        {
            if (string.IsNullOrEmpty(statusText) == false)
            {
                string message = "white";
    
                switch (statusText.ToLower())
                {
                    case "loading":
                        message = "yellow";
                        break;
    
                    case "ready":
                        message = "green";
                        break;
    
                    case "uploading image":
                        message = "red";
                        break;
    
                    case "looping capture":
                        message = "yellow";
                        break;
    
                    case "analysis":
                        message = "red";
                        break;
                }
    
                cameraStatusIndicator.GetComponent<TextMesh>().text = $"Camera Status:\n<color={message}>{statusText}..</color>";
            }
        }
    
  9. PlaceAnalysisLabel () メソッドと SetTagsToLastLabel () メソッドを追加します。これにより、Custom Vision Service のデータが生成され、シーンに表示されます。Add the PlaceAnalysisLabel() and SetTagsToLastLabel() methods, which will spawn and display the data from the Custom Vision Service into the scene.

        /// <summary>
        /// Instantiate a label in the appropriate location relative to the Main Camera.
        /// </summary>
        public void PlaceAnalysisLabel()
        {
            lastLabelPlaced = Instantiate(label.transform, cursor.transform.position, transform.rotation);
            lastLabelPlacedText = lastLabelPlaced.GetComponent<TextMesh>();
        }
    
        /// <summary>
        /// Set the Tags as Text of the last label created. 
        /// </summary>
        public void SetTagsToLastLabel(AnalysisObject analysisObject)
        {
            lastLabelPlacedText = lastLabelPlaced.GetComponent<TextMesh>();
    
            if (analysisObject.Predictions != null)
            {
                foreach (Prediction p in analysisObject.Predictions)
                {
                    if (p.Probability > 0.02)
                    {
                        lastLabelPlacedText.text += $"Detected: {p.TagName} {p.Probability.ToString("0.00 \n")}";
                        Debug.Log($"Detected: {p.TagName} {p.Probability.ToString("0.00 \n")}");
                    }
                }
            }
        }
    
  10. 最後に、 CreateTrainingUI () メソッドを追加します。これにより、アプリケーションがトレーニングモードのときにトレーニングプロセスの複数のステージを表示する UI が生成されます。Lastly, add the CreateTrainingUI() method, which will spawn the UI displaying the multiple stages of the training process when the application is in Training Mode. このメソッドは、カメラの状態オブジェクトを作成するためにも開花されます。This method will also be harnessed to create the camera status object.

        /// <summary>
        /// Create a 3D Text Mesh in scene, with various parameters.
        /// </summary>
        /// <param name="name">name of object</param>
        /// <param name="scale">scale of object (i.e. 0.04f)</param>
        /// <param name="yPos">height above the cursor (i.e. 0.3f</param>
        /// <param name="zPos">distance from the camera</param>
        /// <param name="setActive">whether the text mesh should be visible when it has been created</param>
        /// <returns>Returns a 3D text mesh within the scene</returns>
        internal TextMesh CreateTrainingUI(string name, float scale, float yPos, float zPos, bool setActive)
        {
            GameObject display = new GameObject(name, typeof(TextMesh));
            display.transform.parent = Camera.main.transform;
            display.transform.localPosition = new Vector3(0, yPos, zPos);
            display.SetActive(setActive);
            display.transform.localScale = new Vector3(scale, scale, scale);
            display.transform.rotation = new Quaternion();
            TextMesh textMesh = display.GetComponent<TextMesh>();
            textMesh.anchor = TextAnchor.MiddleCenter;
            textMesh.alignment = TextAlignment.Center;
            return textMesh;
        }
    
  11. Unity に戻る前に、変更内容を Visual Studio に保存してください。Be sure to save your changes in Visual Studio before returning to Unity.

重要

続行する前に、 CustomVisionAnalyser クラスを開き、 AnalyseLastImageCaptured () メソッド内で次の行を コメント 解除します。Before you continue, open the CustomVisionAnalyser class, and within the AnalyseLastImageCaptured() method, uncomment the following lines:

  AnalysisObject analysisObject = new AnalysisObject();
  analysisObject = JsonConvert.DeserializeObject<AnalysisObject>(jsonResponse);
  SceneOrganiser.Instance.SetTagsToLastLabel(analysisObject);

第11章-ImageCapture クラスを作成するChapter 11 - Create the ImageCapture class

次に作成するクラスは、 Imagecapture クラスです。The next class you are going to create is the ImageCapture class.

このクラスの役割は次のとおりです。This class is responsible for:

  • HoloLens カメラを使用してイメージをキャプチャし、 アプリ フォルダーに格納します。Capturing an image using the HoloLens camera and storing it in the App Folder.

  • ユーザーからの Tap ジェスチャを処理します。Handling Tap gestures from the user.

  • アプリケーションを 分析 モードと トレーニング モードのどちらで実行するかを決定する 列挙 値を保持する。Maintaining the Enum value that determines if the application will run in Analysis mode or Training Mode.

このクラスを作成するには:To create this class:

  1. 前に作成した Scripts フォルダーにアクセスします。Go to the Scripts folder you created previously.

  2. フォルダー内を右クリックし、[ Create > C # Script] をクリックします。Right-click inside the folder, then click Create > C# Script. スクリプトに「 Imagecapture」という名前を指定します。Name the script ImageCapture.

  3. 新しい Imagecapture スクリプトをダブルクリックして、 Visual Studio で開きます。Double-click on the new ImageCapture script to open it with Visual Studio.

  4. ファイルの先頭にある名前空間を次のように置き換えます。Replace the namespaces at the top of the file with the following:

    using System;
    using System.IO;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    using UnityEngine.XR.WSA.WebCam;
    
  5. 次に、 Start () メソッドの上に、 imagecapture クラス内に次の変数を追加します。Then add the following variables inside the ImageCapture class, above the Start() method:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static ImageCapture Instance;
    
        /// <summary>
        /// Keep counts of the taps for image renaming
        /// </summary>
        private int captureCount = 0;
    
        /// <summary>
        /// Photo Capture object
        /// </summary>
        private PhotoCapture photoCaptureObject = null;
    
        /// <summary>
        /// Allows gestures recognition in HoloLens
        /// </summary>
        private GestureRecognizer recognizer;
    
        /// <summary>
        /// Loop timer
        /// </summary>
        private float secondsBetweenCaptures = 10f;
    
        /// <summary>
        /// Application main functionalities switch
        /// </summary>
        internal enum AppModes {Analysis, Training }
    
        /// <summary>
        /// Local variable for current AppMode
        /// </summary>
        internal AppModes AppMode { get; private set; }
    
        /// <summary>
        /// Flagging if the capture loop is running
        /// </summary>
        internal bool captureIsActive;
    
        /// <summary>
        /// File path of current analysed photo
        /// </summary>
        internal string filePath = string.Empty;
    
  6. 起動可能な () メソッドと Start () メソッドのコードを追加する必要があります。Code for Awake() and Start() methods now needs to be added:

        /// <summary>
        /// Called on initialization
        /// </summary>
        private void Awake()
        {
            Instance = this;
    
            // Change this flag to switch between Analysis Mode and Training Mode 
            AppMode = AppModes.Training;
        }
    
        /// <summary>
        /// Runs at initialization right after Awake method
        /// </summary>
        void Start()
        {
            // Clean up the LocalState folder of this application from all photos stored
            DirectoryInfo info = new DirectoryInfo(Application.persistentDataPath);
            var fileInfo = info.GetFiles();
            foreach (var file in fileInfo)
            {
                try
                {
                    file.Delete();
                }
                catch (Exception)
                {
                    Debug.LogFormat("Cannot delete file: ", file.Name);
                }
            } 
    
            // Subscribing to the HoloLens API gesture recognizer to track user gestures
            recognizer = new GestureRecognizer();
            recognizer.SetRecognizableGestures(GestureSettings.Tap);
            recognizer.Tapped += TapHandler;
            recognizer.StartCapturingGestures();
    
            SceneOrganiser.Instance.SetCameraStatus("Ready");
        }
    
  7. Tap ジェスチャが発生したときに呼び出されるハンドラーを実装します。Implement a handler that will be called when a Tap gesture occurs.

        /// <summary>
        /// Respond to Tap Input.
        /// </summary>
        private void TapHandler(TappedEventArgs obj)
        {
            switch (AppMode)
            {
                case AppModes.Analysis:
                    if (!captureIsActive)
                    {
                        captureIsActive = true;
    
                        // Set the cursor color to red
                        SceneOrganiser.Instance.cursor.GetComponent<Renderer>().material.color = Color.red;
    
                        // Update camera status to looping capture.
                        SceneOrganiser.Instance.SetCameraStatus("Looping Capture");
    
                        // Begin the capture loop
                        InvokeRepeating("ExecuteImageCaptureAndAnalysis", 0, secondsBetweenCaptures);
                    }
                    else
                    {
                        // The user tapped while the app was analyzing 
                        // therefore stop the analysis process
                        ResetImageCapture();
                    }
                    break;
    
                case AppModes.Training:
                    if (!captureIsActive)
                    {
                        captureIsActive = true;
    
                        // Call the image capture
                        ExecuteImageCaptureAndAnalysis();
    
                        // Set the cursor color to red
                        SceneOrganiser.Instance.cursor.GetComponent<Renderer>().material.color = Color.red;
    
                        // Update camera status to uploading image.
                        SceneOrganiser.Instance.SetCameraStatus("Uploading Image");
                    }              
                    break;
            }     
        }
    

    注意

    分析 モードでは、 TapHandler メソッドはフォトキャプチャループを開始または停止するためのスイッチとして機能します。In Analysis mode, the TapHandler method acts as a switch to start or stop the photo capture loop.

    トレーニング モードでは、カメラからイメージをキャプチャします。In Training mode, it will capture an image from the camera.

    カーソルが緑色の場合は、カメラを使用してイメージを撮影できることを意味します。When the cursor is green, it means the camera is available to take the image.

    カーソルが赤の場合、カメラがビジー状態であることを示します。When the cursor is red, it means the camera is busy.

  8. アプリケーションがイメージキャプチャプロセスを開始してイメージを格納するために使用するメソッドを追加します。Add the method that the application uses to start the image capture process and store the image.

        /// <summary>
        /// Begin process of Image Capturing and send To Azure Custom Vision Service.
        /// </summary>
        private void ExecuteImageCaptureAndAnalysis()
        {
            // Update camera status to analysis.
            SceneOrganiser.Instance.SetCameraStatus("Analysis");
    
            // Create a label in world space using the SceneOrganiser class 
            // Invisible at this point but correctly positioned where the image was taken
            SceneOrganiser.Instance.PlaceAnalysisLabel();
    
            // Set the camera resolution to be the highest possible
            Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
    
            Texture2D targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);
    
            // Begin capture process, set the image format
            PhotoCapture.CreateAsync(false, delegate (PhotoCapture captureObject)
            {
                photoCaptureObject = captureObject;
    
                CameraParameters camParameters = new CameraParameters
                {
                    hologramOpacity = 0.0f,
                    cameraResolutionWidth = targetTexture.width,
                    cameraResolutionHeight = targetTexture.height,
                    pixelFormat = CapturePixelFormat.BGRA32
                };
    
                // Capture the image from the camera and save it in the App internal folder
                captureObject.StartPhotoModeAsync(camParameters, delegate (PhotoCapture.PhotoCaptureResult result)
                {
                    string filename = string.Format(@"CapturedImage{0}.jpg", captureCount);
                    filePath = Path.Combine(Application.persistentDataPath, filename);          
                    captureCount++;              
                    photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);              
                });
            });   
        }
    
  9. 写真がキャプチャされ、分析の準備ができたときに呼び出されるハンドラーを追加します。Add the handlers that will be called when the photo has been captured and for when it is ready to be analyzed. 次に、コードが設定されているモードに応じて、結果が CustomVisionAnalyser または CustomVisionTrainer に渡されます。The result is then passed to the CustomVisionAnalyser or the CustomVisionTrainer depending on which mode the code is set on.

        /// <summary>
        /// Register the full execution of the Photo Capture. 
        /// </summary>
        void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
        {
                // Call StopPhotoMode once the image has successfully captured
                photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
        }
    
    
        /// <summary>
        /// The camera photo mode has stopped after the capture.
        /// Begin the Image Analysis process.
        /// </summary>
        void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
        {
            Debug.LogFormat("Stopped Photo Mode");
    
            // Dispose from the object in memory and request the image analysis 
            photoCaptureObject.Dispose();
            photoCaptureObject = null;
    
            switch (AppMode)
            {
                case AppModes.Analysis:
                    // Call the image analysis
                    StartCoroutine(CustomVisionAnalyser.Instance.AnalyseLastImageCaptured(filePath));
                    break;
    
                case AppModes.Training:
                    // Call training using captured image
                    CustomVisionTrainer.Instance.RequestTagSelection();
                    break;
            }
        }
    
        /// <summary>
        /// Stops all capture pending actions
        /// </summary>
        internal void ResetImageCapture()
        {
            captureIsActive = false;
    
            // Set the cursor color to green
            SceneOrganiser.Instance.cursor.GetComponent<Renderer>().material.color = Color.green;
    
            // Update camera status to ready.
            SceneOrganiser.Instance.SetCameraStatus("Ready");
    
            // Stop the capture loop if active
            CancelInvoke();
        }
    
  10. Unity に戻る前に、変更内容を Visual Studio に保存してください。Be sure to save your changes in Visual Studio before returning to Unity.

  11. すべてのスクリプトが完了したので、Unity エディターに戻り、[スクリプト] フォルダーの SceneOrganiser クラスをクリックして、階層パネルメインカメラ オブジェクトにドラッグします。Now that all the scripts have been completed, go back in the Unity Editor, then click and drag the SceneOrganiser class from the Scripts folder to the Main Camera object in the Hierarchy Panel.

第12章-ビルド前Chapter 12 - Before building

アプリケーションの徹底的なテストを実行するには、アプリケーションを HoloLens にサイドロードする必要があります。To perform a thorough test of your application you will need to sideload it onto your HoloLens.

これを行う前に、次のことを確認してください。Before you do, ensure that:

  • 章 2で説明したすべての設定が正しく設定されています。All the settings mentioned in the Chapter 2 are set correctly.

  • メインカメラ の [インスペクター] パネルのすべてのフィールドが適切に割り当てられます。All the fields in the Main Camera, Inspector Panel, are assigned properly.

  • スクリプト SceneOrganiser は、 メインカメラ オブジェクトにアタッチされます。The script SceneOrganiser is attached to the Main Camera object.

  • 必ず、 予測キーpredictionKey 変数に挿入してください。Make sure you insert your Prediction Key into the predictionKey variable.

  • 予測エンドポイントpredictionEndpoint 変数に挿入しました。You have inserted your Prediction Endpoint into the predictionEndpoint variable.

  • トレーニングキーCustomVisionTrainer クラスの trainingKey 変数に挿入しました。You have inserted your Training Key into the trainingKey variable, of the CustomVisionTrainer class.

  • プロジェクト IDCustomVisionTrainer クラスの projectId 変数に挿入されました。You have inserted your Project ID into the projectId variable, of the CustomVisionTrainer class.

第13章-アプリケーションのビルドとサイドロードChapter 13 - Build and sideload your application

ビルド プロセスを開始するには:To begin the Build process:

  1. ファイル > ビルド設定 にアクセスします。Go to File > Build Settings.

  2. Unity C # プロジェクト をティックします。Tick Unity C# Projects.

  3. [ビルド] をクリックします。Click Build. Unity は エクスプローラー ウィンドウを起動します。このウィンドウでは、アプリを作成するフォルダーを作成して選択する必要があります。Unity will launch a File Explorer window, where you need to create and then select a folder to build the app into. ここでそのフォルダーを作成し、「 App」という名前を指定します。Create that folder now, and name it App. 次に、 アプリ フォルダーを選択し、[ フォルダーの選択] をクリックします。Then with the App folder selected, click on Select Folder.

  4. Unity は、 アプリ フォルダーへのプロジェクトのビルドを開始します。Unity will begin building your project to the App folder.

  5. Unity のビルドが完了すると (時間がかかる場合があります)、ビルドの場所で ファイルエクスプローラー ウィンドウを開きます (ウィンドウの上に常に表示されるとは限りませんが、新しいウィンドウが追加されたことが通知されます)。Once Unity has finished building (it might take some time), it will open a File Explorer window at the location of your build (check your task bar, as it may not always appear above your windows, but will notify you of the addition of a new window).

HoloLens に展開するには:To deploy on HoloLens:

  1. Hololens が 開発者モード になっていることを確認するには、HOLOLENS の IP アドレス (リモートデプロイ用) が必要です。You will need the IP Address of your HoloLens (for Remote Deploy), and to ensure your HoloLens is in Developer Mode. この操作を行うには、次の手順を実行します。To do this:

    1. HoloLens を装着した後、 設定 を開きます。Whilst wearing your HoloLens, open the Settings.

    2. [ネットワーク & インターネット > wi-fi > 詳細オプション] にアクセスします。Go to Network & Internet > Wi-Fi > Advanced Options

    3. IPv4 アドレスをメモしておきます。Note the IPv4 address.

    4. 次に、[設定] に戻り、 Update & Security > 開発者の& セキュリティを更新します。Next, navigate back to Settings, and then to Update & Security > For Developers

    5. 開発者モードをに 設定します。Set Developer Mode On.

  2. 新しい Unity ビルド ( アプリ フォルダー) に移動し、 Visual Studio でソリューションファイルを開きます。Navigate to your new Unity build (the App folder) and open the solution file with Visual Studio.

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

  4. ソリューションプラットフォーム で、[ X86、リモートコンピューター] を選択します。In the Solution Platform, select x86, Remote Machine. リモートデバイスの IP アドレス (この場合は、ここでメモした HoloLens) を挿入するように求められます。You will be prompted to insert the IP address of a remote device (the HoloLens, in this case, which you noted).

    IP アドレスの設定

  5. [ ビルド ] メニューの [ ソリューションの配置 ] をクリックして、アプリケーションを HoloLens にサイドロードします。Go to Build menu and click on Deploy Solution to sideload the application to your HoloLens.

  6. アプリが HoloLens にインストールされているアプリの一覧に表示され、起動できる状態になります。Your app should now appear in the list of installed apps on your HoloLens, ready to be launched!

注意

イマーシブヘッドセットにデプロイするには 、ソリューションプラットフォームローカルコンピューター に設定し、プラットフォーム として x86 を使用して、構成 を [デバッグ] に設定します。To deploy to immersive headset, set the Solution Platform to Local Machine, and set the Configuration to Debug, with x86 as the Platform. 次に、[ ビルド ] メニュー項目を使用して [ ソリューションの配置] を選択し、ローカルコンピューターに配置します。Then deploy to the local machine, using the Build menu item, selecting Deploy Solution.

アプリケーションを使用するには:To use the application:

トレーニング モードと 予測 モードの間でアプリの機能を切り替えるには、 imagecapture クラス内にある、起動前の () メソッドにある appmode 変数を更新する必要があります。To switch the app functionality between Training mode and Prediction mode you need to update the AppMode variable, located in the Awake() method located within the ImageCapture class.

        // Change this flag to switch between Analysis mode and Training mode 
        AppMode = AppModes.Training;

oror

        // Change this flag to switch between Analysis mode and Training mode 
        AppMode = AppModes.Analysis;

トレーニング モードの場合:In Training mode:

  • マウス または キーボード を見て、 Tap ジェスチャ を使用します。Look at Mouse or Keyboard and use the Tap gesture.

  • 次に、タグの入力を求めるテキストが表示されます。Next, text will appear asking you to provide a tag.

  • マウス または キーボード のいずれかを言います。Say either Mouse or Keyboard.

予測 モードの場合:In Prediction mode:

  • オブジェクトを確認し、 Tap ジェスチャ を使用します。Look at an object and use the Tap gesture.

  • オブジェクトが検出され、確率が最も高い (これは正規化されている) ことを示すテキストが表示されます。Text will appear providing the object detected, with the highest probability (this is normalized).

第14章-Custom Vision モデルの評価と改善Chapter 14 - Evaluate and improve your Custom Vision model

サービスの精度を高めるには、予測に使用するモデルのトレーニングを続行する必要があります。To make your Service more accurate, you will need to continue to train the model used for prediction. これは、 トレーニング予測 の両方のモードで新しいアプリケーションを使用することによって実現されます。後者の場合はポータルにアクセスする必要があります。これについては、この章で説明します。This is accomplished through using your new application, with both the training and prediction modes, with the latter requiring you to visit the portal, which is what is covered in this Chapter. モデルを継続的に改善するために、ポータルに何度も再訪問できるように準備してください。Be prepared to revisit your portal many times, to continually improve your model.

  1. Azure Custom Vision ポータルにもう一度移動します。プロジェクトが表示されたら、[ 予測 ] タブ (ページの上部中央) を選択します。Head to your Azure Custom Vision Portal again, and once you are in your project, select the Predictions tab (from the top center of the page):

    [予測] タブの選択

  2. アプリケーションの実行中にサービスに送信されたすべてのイメージが表示されます。You will see all the images which were sent to your Service whilst your application was running. 画像にマウスポインターを合わせると、その画像に対して行われた予測が表示されます。If you hover over the images, they will provide you with the predictions that were made for that image:

    予測イメージの一覧

  3. イメージの1つを選択して開きます。Select one of your images to open it. 開いた後、そのイメージの予測が右側に表示されます。Once open, you will see the predictions made for that image to the right. 予測が適切で、このイメージをサービスのトレーニングモデルに追加する場合は、[ マイタグ ] 入力ボックスをクリックし、関連付けるタグを選択します。If you the predictions were correct, and you wish to add this image to your Service's training model, click the My Tags input box, and select the tag you wish to associate. 操作が完了したら、右下にある [ 保存して閉じる ] ボタンをクリックし、次の画像に進みます。When you are finished, click the Save and close button to the bottom right, and continue on to the next image.

    開くイメージの選択

  4. 画像のグリッドに戻ると、タグを追加した (および保存した) イメージが削除されます。Once you are back to the grid of images, you will notice the images which you have added tags to (and saved), will be removed. タグ付けされた項目がないと思われるイメージが見つかった場合は、そのイメージの目盛りをクリックし (複数のイメージに対してこれを実行できます)、グリッドページの右上隅にある [ 削除 ] をクリックすることで、イメージを削除できます。If you find any images which you think do not have your tagged item within them, you can delete them, by clicking the tick on that image (can do this for several images) and then clicking Delete in the upper right corner of the grid page. 次のポップアップで、[はい]、[ 削除 ]、または [ いいえ] をクリックして、それぞれ削除を確認するか、キャンセルします。On the popup that follows, you can click either Yes, delete or No, to confirm the deletion or cancel it, respectively.

    イメージを削除する

  5. 操作を続行する準備ができたら、右上にある緑色の [ Train ] ボタンをクリックします。When you are ready to proceed, click the green Train button in the top right. サービスモデルは、現在提供されているすべてのイメージでトレーニングされます (これにより、より正確になります)。Your Service model will be trained with all the images which you have now provided (which will make it more accurate). トレーニングが完了したら、[ 既定値 に設定] ボタンをもう一度クリックし、 予測 URL がサービスの最新のイテレーションを引き続き使用するようにしてください。Once the training is complete, make sure to click the Make default button once more, so that your Prediction URL continues to use the most up-to-date iteration of your Service.

    トレーニングサービスモデルの開始  [既定の設定] オプションの選択Start training service model Select make default option

完成した Custom Vision API アプリケーションYour finished Custom Vision API application

これで、Azure Custom Vision API を活用して実際のオブジェクトを認識し、サービスモデルをトレーニングし、表示されている内容の信頼性を表示する、mixed reality アプリを構築しました。Congratulations, you built a mixed reality app that leverages the Azure Custom Vision API to recognize real world objects, train the Service model, and display confidence of what has been seen.

完成したプロジェクトの例

ボーナス演習Bonus exercises

演習1Exercise 1

Custom Vision Service をトレーニングして、より多くのオブジェクトを認識します。Train your Custom Vision Service to recognize more objects.

演習2Exercise 2

学習した内容を拡張する方法として、次の演習を実行します。As a way to expand on what you have learned, complete the following exercises:

オブジェクトが認識されたときにサウンドを再生します。Play a sound when an object is recognized.

演習3Exercise 3

API を使用して、アプリが分析しているのと同じイメージでサービスを再トレーニングします。これにより、サービスの精度が向上します (予測とトレーニングの両方を同時に行うことができます)。Use the API to re-train your Service with the same images your app is analyzing, so to make the Service more accurate (do both prediction and training simultaneously).