注意

Mixed Reality Academy チュートリアルでは、HoloLens として設計された (第 1 世代) と混在の現実イマーシブ ヘッドセットに注意してください。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.

Mr と Azure 310:オブジェクトの検出Mr and Azure 310: Object detection

このコースでは方法を学習しますカスタム ビジュアルのコンテンツと、指定されたイメージに含まれる空間位置を認識して Azure の Custom Vision を使用して、複合現実のアプリケーションでは「オブジェクトの検出」機能します。In this course, you will learn how to recognize custom visual content and its spatial position within a provided image, using Azure Custom Vision "Object Detection" capabilities in a mixed reality application.

このサービスを使用して、オブジェクトのイメージを使用して機械学習モデルのトレーニングにはできます。This service will allow you to train a machine learning model using object images. Microsoft HoloLens のカメラ キャプチャによって提供される同等のオブジェクトを認識し、おおよその現実の世界での場所に、トレーニング済みモデルを使用してまたは没入型の (VR) ヘッドセットの PC にカメラを接続します。You will then use the trained model to recognize similar objects and approximate their location in the real world, as provided by the camera capture of Microsoft HoloLens or a camera connect to a PC for immersive (VR) headsets.

コースの結果

Azure の Custom Vision、オブジェクトの検出Microsoft サービスで、開発者がカスタム イメージ分類モデルを構築します。Azure Custom Vision, Object Detection is a Microsoft Service which allows developers to build custom image classifiers. 提供することで、そのイメージ内のオブジェクトを検出するために新しいイメージでこれらの分類モデルが使用しできますボックス境界はイメージ自体。These classifiers can then be used with new images to detect objects within that new image, by providing Box Boundaries within the image itself. サービスは、このプロセスを効率化のシンプルで使いやすい、オンライン ポータルを提供します。The Service provides a simple, easy to use, online portal to streamline this process. 詳細については、次のリンクを参照してください。For more information, visit the following links:

このコースを修了、以下を実行できる必要が複合現実のアプリケーションが用意されます。Upon completion of this course, you will have a mixed reality application which will be able to do the following:

  1. ユーザーができるようになります視線Azure Custom Vision Service オブジェクトの検出を使用して、トレーニングがオブジェクトにします。The user will be able to gaze at an object, which they have trained using the Azure Custom Vision Service, Object Detection.
  2. ユーザーが使用する、タップで目的のイメージをキャプチャするジェスチャ。The user will use the Tap gesture to capture an image of what they are looking at.
  3. アプリはイメージを Azure の Custom Vision Service に送信します。The app will send the image to the Azure Custom Vision Service.
  4. ワールド空間テキストとして認識の結果が表示されるサービスからの応答があります。There will be a reply from the Service which will display the result of the recognition as world-space text. これは、Microsoft HoloLens の空間追跡、認識されているオブジェクトのワールド位置を理解して使用し、方法として利用するによって実現されますが、タグイメージ内に検出された内容に関連付けられています。ラベルのテキストを提供します。This will be accomplished through utilizing the Microsoft HoloLens' Spatial Tracking, as a way of understanding the world position of the recognized object, and then using the Tag associated with what is detected in the image, to provide the label text.

コースは、タグを作成、アップロードを手動でのイメージも説明し、トレーニング異なるを認識する、サービス オブジェクト (指定の例では、杯) での設定、境界ボックスを送信する、イメージ内で。The course will also cover manually uploading images, creating tags, and training the Service, to recognize different objects (in the provided example, a cup), by setting the Boundary Box within the image you submit.

重要

次の作成とアプリの使用、開発者する必要があります Azure の Custom Vision Service に戻るを特定、サービスによって行われた予測しかどうかが正しいかどうかを判断する (サービスを何もタグ付けによってがなくと調整、境界ボックス)。Following the creation and use of the app, the developer should navigate back to the Azure Custom Vision Service, and identify the predictions made by the Service, and determine whether they were correct or not (through tagging anything the Service missed, and adjusting the Bounding Boxes). サービス、再トレーニングできます、現実世界のオブジェクトを認識することの可能性が高くなりますが。The Service can then be re-trained, which will increase the likelihood of it recognizing real world objects.

このコースでは、Azure の Custom Vision Service、オブジェクトの検出から Unity に基づくサンプル アプリケーションに結果を取得する方法を説明します。This course will teach you how to get the results from the Azure Custom Vision Service, Object Detection, 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 310:オブジェクトの検出MR and Azure 310: Object detection ✔️✔️

前提条件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 ポータルChapter 1 - The Custom Vision Portal

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

  1. 移動Custom Vision Serviceメイン ページします。Navigate to the Custom Vision Service main page.

  2. をクリックしてGetting Startedします。Click on Getting Started.

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

  4. Azure アカウントがいない場合は、1 つを作成する必要があります。If you do not already have an Azure account, you will need to create one. クラスルームまたはラボのような状況では、このチュートリアルをフォローしている場合は、講師または新しいアカウントのセットアップについて proctors のいずれかにお問い合わせください。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.

  5. 求められます初めてログインした後、サービス利用規約パネル。Once you are logged in for the first time, you will be prompted with the Terms of Service panel. チェック ボックスをクリックして条項に同意します。Click the checkbox to agree to the terms. クリックして同意します。Then click I agree.

  6. 条項に同意したこと、れるので、マイ プロジェクトセクション。Having agreed to the terms, you are now in the My Projects section. をクリックして新しいプロジェクトします。Click on New Project.

  7. プロジェクトの一部のフィールドを指定するように求められますが、右側にあるタブが表示されます。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 as Object Detection (preview).

  8. 終了したらをクリックしてプロジェクトの作成、し、Custom Vision Service プロジェクトのページにリダイレクトされます。Once you are finished, click on Create project, and you will be redirected to the Custom Vision Service project page.

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

1 回、Custom Vision ポータルの主な目的はイメージ内の特定のオブジェクトを認識するようにプロジェクトのトレーニングには。Once in the Custom Vision Portal, your primary objective is to train your project to recognize specific objects in images.

各オブジェクトを認識するアプリケーションを少なくとも 15 (15) イメージが必要です。You need at least fifteen (15) images for each object that you would like your application to recognize. このコースで提供されるイメージを使用することができます (一連の cup)。You can use the images provided with this course (a series of cups).

Custom Vision プロジェクトのトレーニング。To train your Custom Vision project:

  1. をクリックして、 + 横にタグします。Click on the + button next to Tags.

  2. 追加、名前タグのによって、イメージを関連付けるために使用されます。Add a name for the tag that will be used to associate your images with. 認識のため、これは、タグを付けた、カップのイメージを使用しているがこの例ではCupします。In this example we are using images of cups for recognition, so have named the tag for this, Cup. クリックして保存完了後します。Click Save once finished.

  3. タグが追加されました (表示するページを再読み込みする必要があります)。You will notice your Tag has been added (you may need to reload your page for it to appear).

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

  5. をクリックしてローカル ファイルを参照とに 1 つのオブジェクト、15、最小されていると (15) をアップロードするイメージを参照します。Click on Browse local files, and browse to the images you would like to upload for one object, with the minimum being fifteen (15).

    ヒント

    一度にアップロードするいくつかのイメージを選択できます。You can select several images at a time, to upload.

  6. キーを押してファイルをアップロードトレーニングを使用してプロジェクトにするすべてのイメージを選択するとします。Press Upload files once you have selected all the images you would like to train the project with. ファイル アップロードが開始されます。The files will begin uploading. アップロードの確認したら、クリックして完了します。Once you have confirmation of the upload, click Done.

  7. この時点で、イメージがアップロードされるが、タグ付けされていません。At this point your images are uploaded, but not tagged.

  8. イメージをタグにマウスを使用します。To tag your images, use your mouse. イメージをポイントするよう選択の強調表示する助けとなります、オブジェクトの周りに選択範囲を自動的に描画することで。As you hover over your image, a selection highlight will aid you by automatically drawing a selection around your object. 正確でない場合を描画できます独自。If it is not accurate, you can draw your own. これは、マウスの左クリックを保持していると、オブジェクトを囲むように選択した領域にドラッグすることによって実現されます。This is accomplished by holding left-click on the mouse, and dragging the selection region to encompass your object.

  9. 次のイメージ内のオブジェクトの選択、小規模なプロンプトがするように求められますリージョン タグを追加します。Following the selection of your object within the image, a small prompt will ask for you to Add Region Tag. 以前に作成したタグ ('Cup'、上記の例では) を選択するかその他のタグを追加する場合でを入力し、をクリックして、 + (正符号 +) ボタンをクリックします。Select your previously created tag ('Cup', in the above example), or if you are adding more tags, type that in and click the + (plus) button.

  10. 次の画像をタグ付けする、ブレードの右側にある矢印をクリックします。 または、[タグ] ブレードを閉じます (をクリックして、 Xブレードの右上隅にある) を次の画像をクリックします。To tag the next image, you can click the arrow to the right of the blade, or close the tag blade (by clicking the X in the top-right corner of the blade) and then click the next image. 次のイメージを準備した後は、同じ手順を繰り返します。Once you have the next image ready, repeat the same procedure. これまで、すべてタグ付けされている、アップロードしたすべてのイメージを行います。Do this for all the images you have uploaded, until they are all tagged.

    注意

    次の図のように、同じイメージでは、いくつかのオブジェクトを選択できます。You can select several objects in the same image, like the image below:

  11. それらすべてにタグが、クリックして、タグが付けられたタグが付けられたイメージを表示する画面の左側にボタンをクリックします。Once you have tagged them all, click on the tagged button, on the left of the screen, to reveal the tagged images.

  12. サービスをトレーニングする準備が整いました。You are now ready to train your Service. をクリックして、トレーニングボタン、および最初のトレーニングのイテレーションが開始されます。Click the Train button, and the first training iteration will begin.

  13. ビルドされたらという 2 つのボタンを表示できるが既定予測 URLします。Once it is built, you will be able to see two buttons called Make default and Prediction URL. をクリックして既定でクリックし、最初に、予測 URLします。Click on Make default first, then click on Prediction URL.

    注意

    これにより、提供されているエンドポイントがどちらに設定されているイテレーションが既定としてマークされました。The endpoint 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.

  14. クリックすると予測 URL、オープンメモ帳、コピーして貼り付け、 URL (とも呼ばれます、予測エンドポイント)サービス予測キーコードの後半で必要なときに取得できるようにします。Once you have clicked on Prediction URL, open Notepad, and copy and paste the URL (also called your Prediction-Endpoint) and the Service Prediction-Key, so that you can retrieve it when you need it later in the code.

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

次のコード例が複合現実での開発の一般的な設定して、そのため、他のプロジェクトの適切なテンプレートには。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.

  2. これで、Unity プロジェクトの名前を指定する必要があります。You will now need to provide a Unity project name. 挿入CustomVisionObjDetectionします。Insert CustomVisionObjDetection. 必ず、プロジェクトの種類に設定されて3D、設定と、場所で該当する別の場所を (ただし、ルート ディレクトリに近づけるためのより良い)。Make sure the project type is set to 3D, and 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. 移動して 編集 > 設定 し、新しいウィンドウに移動 外部ツール します。Go to Edit > Preferences and then from the new window, navigate to External Tools. 変更 External Script EditorVisual Studio します。Change External Script Editor to Visual Studio. 閉じる、設定ウィンドウ。Close the Preferences window.

  4. 移動して次に、ファイル > Build Settingsスイッチと、プラットフォームユニバーサル Windows プラットフォームをクリックし、 プラットフォームの切り替えボタンをクリックします。Next, go to File > Build Settings and switch the Platform to Universal Windows Platform, and then clicking on the Switch Platform button.

  5. 同じBuild Settingsウィンドウで、次を設定してください。In the same Build Settings window, ensure the following are set:

    1. デバイスを対象にに設定されているHoloLensTarget Device is set to HoloLens

    2. ビルドの種類に設定されているD3DBuild 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. 設定に残っているBuild Settings、ここでは既定値として残しておく必要があります。The remaining settings, in Build Settings, should be left as default for now.

  6. 同じBuild Settingsウィンドウで、をクリックして、プレーヤー設定ボタン、領域に関連するパネルが開き、インスペクターが配置されています。In the same 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. ランタイム バージョンをスクリプトする必要があります試験的(.NET 4.6 Equivalent)、エディターを再起動する必要があるします。Scripting Runtime Version should be Experimental (.NET 4.6 Equivalent), which will trigger a need to restart the Editor.

      2. バックエンドの scriptingべき .NETします。Scripting Backend should be .NET.

      3. API の互換性レベルべき .NET 4.6します。API Compatibility Level should be .NET 4.6.

    2. 内で、発行の設定] タブの [機能、確認してください。Within the Publishing Settings tab, under Capabilities, check:

      1. InternetClientInternetClient

      2. Web カメラWebcam

      3. SpatialPerceptionSpatialPerception

    3. パネル、下の方にXR 設定(次に示します発行設定)、ティック仮想現実サポート、確認してください、 Windows 混在実際には SDKが追加されます。Further down the panel, in XR Settings (found below Publish Settings), tick Virtual Reality Supported, then make sure the Windows Mixed Reality SDK is added.

  8. 戻りBuild SettingsUnity C#プロジェクトが不要になったグレー: この横にあるチェック ボックスをオンにします。Back in Build Settings, Unity C# Projects is no longer greyed out: tick the checkbox next to this.

  9. 閉じる、 Build Settingsウィンドウ。Close the Build Settings window.

  10. エディター、 をクリックして編集 > プロジェクト設定 > グラフィックスします。In the Editor, click on Edit > Project Settings > Graphics.

  11. インスペクター パネルグラフィックス設定開きます。In the Inspector Panel the Graphics Settings will be open. 呼ばれる配列が表示されるまで下にスクロールシェーダーを常に含めるします。Scroll down until you see an array called Always Include Shaders. スロットの追加を増やすことで、サイズで 1 つは、変数 (この例でこれが 8 のでが 9)。Add a slot by increasing the Size variable by one (in this example, it was 8 so we made it 9). 新しいスロットが表示されます、配列の最後の位置に次に示すよう。A new slot will appear, in the last position of the array, as shown below:

  12. スロットでは、シェーダーのリストを開いて、スロットの横にあるターゲットの小さな円をクリックします。In the slot, click on the small target circle next to the slot to open a list of shaders. 探して、レガシ シェーダー/Transparent 拡散シェーダーし、ダブルクリックします。Look for the Legacy Shaders/Transparent/Diffuse shader and double-click it.

第 4 章 - CustomVisionObjDetection Unity パッケージをインポートします。Chapter 4 - Importing the CustomVisionObjDetection Unity package

このコースには、Unity Asset のパッケージと呼ばれるAzure-MR-310.unitypackageします。For this course you are provided with a Unity Asset Package called Azure-MR-310.unitypackage.

[ヒント]シーンの全体を含む、Unity でサポートされているすべてのオブジェクトをパッケージ化できます、 .unitypackageファイル、およびエクスポート/その他のプロジェクトにインポートされています。[TIP] Any objects supported by Unity, including entire scenes, can be packaged into a .unitypackage file, and exported / imported in other projects. 別の間で資産を移動する最も安全な最も効率的な方法はUnity プロジェクトします。It is the safest, and most efficient, way to move assets between different Unity projects.

検索することができます、ここからダウンロードする必要がある Azure-MR-310 パッケージします。You can find the Azure-MR-310 package that you need to download here.

  1. 前 [Unity ダッシュ ボード] をクリックして資産画面の上部にあるメニューでクリックしてパッケージのインポート > カスタム パッケージします。With the Unity dashboard in front of you, click on Assets in the menu at the top of the screen, then click on Import Package > Custom Package.

  2. ファイル ピッカーを使用して、 Azure-MR-310.unitypackageパッケージ化し、をクリックしてオープンします。Use the file picker to select the Azure-MR-310.unitypackage package and click Open. この資産のコンポーネントの一覧が表示されます。A list of components for this asset will be displayed to you. クリックして、インポートの確認、インポートボタンをクリックします。Confirm the import by clicking the Import button.

  3. これには、インポートが完了したら後に、パッケージからのフォルダーが追加されたようになりましたことがわかりますが、資産フォルダー。Once it has finished importing, you will notice that folders from the package have now been added to your Assets folder. このようなフォルダー構造は、Unity プロジェクトの一般的なものです。This kind of folder structure is typical for a Unity project.

    1. 資料フォルダーにはで使用される材料が含まれています、視線カーソルします。The Materials folder contains the material used by the Gaze Cursor.

    2. プラグインフォルダーには、サービスの web 応答を逆シリアル化するコードで使用、Newtonsoft DLL が含まれています。The Plugins folder contains the Newtonsoft DLL used by the code to deserialize the Service web response. 2 つの異なるバージョンにフォルダーとサブフォルダーに含まれているを使用でき、Unity エディターと UWP ビルドの両方でビルドされたライブラリを許可するために必要です。The two (2) different versions contained in the folder, and sub-folder, are necessary to allow the library to be used and built by both the Unity Editor and the UWP build.

    3. プレハブフォルダーには、シーン内に含まれているプレハブが含まれています。The Prefabs folder contains the prefabs contained in the scene. これらは。Those are:

      1. GazeCursorアプリケーションで使用するカーソル。The GazeCursor, the cursor used in the application. 物理オブジェクト上にシーンに配置することができる SpatialMapping プレハブと共に動作します。Will work together with the SpatialMapping prefab to be able to be placed in the scene on top of physical objects.
      2. ラベル、必要な場合に、シーン内のオブジェクト タグの表示に使用される UI オブジェクトであります。The Label, which is the UI object used to display the object tag in the scene when required.
      3. SpatialMappingこれを使用するアプリケーションを有効にするオブジェクトは、Microsoft HoloLens の空間の追跡を使用して、仮想のマップを作成します。The SpatialMapping, which is the object that enables the application to use create a virtual map, using the Microsoft HoloLens' spatial tracking.
    4. シーンフォルダーには現在このコースの既成のシーンが含まれています。The Scenes folder which currently contains the pre-built scene for this course.

  4. 開く、シーンフォルダーで、プロジェクト パネル、ダブルクリックして、 ObjDetectionScene、このコースで使用するシーンを読み込む。Open the Scenes folder, in the Project Panel, and double-click on the ObjDetectionScene, to load the scene that you will use for this course.

    注意

    コードが含まれていない、このコースで、コードを記述します。No code is included, you will write the code by following this course.

5 -」の章では、CustomVisionAnalyser クラスを作成します。Chapter 5 - 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 が提供する、カスタム ビジョン SDKをサービスを呼び出すことにも使用できます。Be aware, that Microsoft offers a Custom Vision SDK that can also be used to make calls to the Service. 詳細については、次を参照してください。、カスタム ビジョン SDK の記事します。For more information visit the Custom Vision 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 newly created folder, to open it.

  3. フォルダー内を右クリックし、をクリックして作成 > 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. 次のファイルの上部にある参照される名前空間を確認してください。Make sure you have the following namespaces referenced at the top of the file:

    using Newtonsoft.Json;
    using System.Collections;
    using System.IO;
    using UnityEngine;
    using UnityEngine.Networking;
    
  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>
        /// Bite array of the image to submit for analysis
        /// </summary>
        [HideInInspector] public byte[] imageBytes;
    

    注意

    挿入することを確認、サービス予測キーに、 predictionKey変数、および予測エンドポイントに、 predictionEndpoint変数。Make sure you insert your Service Prediction-Key into the predictionKey variable and your Prediction-Endpoint into the predictionEndpoint variable. これらをコピーしたメモ帳以前では、第 2 章の手順 14します。You copied these to Notepad earlier, in Chapter 2, Step 14.

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

        /// <summary>
        /// Initializes this class
        /// </summary>
        private void Awake()
        {
            // Allows this instance to behave like a singleton
            Instance = this;
        }
    
  8. コルーチンを追加 (静的でGetImageAsByteArray() 下にあるメソッド)、によってキャプチャされたイメージの分析の結果を取得するが、 ImageCaptureクラス。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.

    注意

    AnalyseImageCaptureコルーチンへの呼び出しがある、 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)
        {
            Debug.Log("Analyzing...");
    
            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;
    
                Debug.Log("response: " + jsonResponse);
    
                // Create a texture. Texture size does not matter, since
                // LoadImage will replace with the incoming image size.
                //Texture2D tex = new Texture2D(1, 1);
                //tex.LoadImage(imageBytes);
                //SceneOrganiser.Instance.quadRenderer.material.SetTexture("_MainTex", tex);
    
                // The response will be in JSON format, therefore it needs to be deserialized
                //AnalysisRootObject analysisRootObject = new AnalysisRootObject();
                //analysisRootObject = JsonConvert.DeserializeObject<AnalysisRootObject>(jsonResponse);
    
                //SceneOrganiser.Instance.FinaliseLabel(analysisRootObject);
            }
        }
    
        /// <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);
        }
    
  9. 削除、 Start()Update() メソッドを使用できません。Delete the Start() and Update() methods, as they will not be used.

  10. 変更を保存することを確認するVisual Studioに戻る前にUnityします。Be sure to save your changes in Visual Studio, before returning to Unity.

重要

前述のように、あまり心配しないでコード クラスすぐに、これらを修正するをさらに提供されますが、エラーを表示する可能性があります。As mentioned earlier, do not worry about code which might appear to have an error, as you will provide further classes soon, which will fix these.

第 6 章 - CustomVisionObjects クラスを作成します。Chapter 6 - 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.

このクラスを作成します。To create this class:

  1. 内で右クリック、スクリプトフォルダー、 をクリックし、作成 > C#スクリプトします。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. 次のファイルの上部にある参照される名前空間を確認してください。Make sure you have the following namespaces referenced at the top of the file:

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

    警告

    慎重に次の手順に従ってくださいが重要です。It is important you follow the next instruction carefully. 新しいクラスの宣言内に配置した場合、 CustomVisionObjectsクラスにコンパイル エラーが表示されます第 10 章というをAnalysisRootObjectBoundingBoxが見つかりません。If you put the new class declarations inside the CustomVisionObjects class, you will get compile errors in chapter 10, stating that AnalysisRootObject and BoundingBox are not found.

  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
    /// Includes Bounding Box
    /// </summary>
    public class AnalysisRootObject
    {
        public string id { get; set; }
        public string project { get; set; }
        public string iteration { get; set; }
        public DateTime created { get; set; }
        public List<Prediction> predictions { get; set; }
    }
    
    public class BoundingBox
    {
        public double left { get; set; }
        public double top { get; set; }
        public double width { get; set; }
        public double height { get; set; }
    }
    
    public class Prediction
    {
        public double probability { get; set; }
        public string tagId { get; set; }
        public string tagName { get; set; }
        public BoundingBox boundingBox { get; set; }
    }
    
  6. 変更を保存することを確認するVisual Studioに戻る前にUnityします。Be sure to save your changes in Visual Studio, before returning to Unity.

7 - 章 SpatialMapping クラスを作成します。Chapter 7 - Create the SpatialMapping class

このクラスは設定、空間マッピング Collider仮想オブジェクトと実際のオブジェクト間の競合を検出できるようにするシーンにします。This class will set the Spatial Mapping Collider in the scene so to be able to detect collisions between virtual objects and real objects.

このクラスを作成します。To create this class:

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

  2. ダブルクリックして、新しいSpatialMappingスクリプト ファイルを開くVisual Studio。Double-click on the new SpatialMapping script to open it with Visual Studio.

  3. 上記の次の名前空間があるかどうかを確認、 SpatialMappingクラス。Make sure you have the following namespaces referenced above the SpatialMapping class:

    using UnityEngine;
    using UnityEngine.XR.WSA;
    
  4. 次に、内部では、次の変数を追加、 SpatialMappingクラス上、 Start() メソッド。Then, add the following variables inside the SpatialMapping class, above the Start() method:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static SpatialMapping Instance;
    
        /// <summary>
        /// Used by the GazeCursor as a property with the Raycast call
        /// </summary>
        internal static int PhysicsRaycastMask;
    
        /// <summary>
        /// The layer to use for spatial mapping collisions
        /// </summary>
        internal int physicsLayer = 31;
    
        /// <summary>
        /// Creates environment colliders to work with physics
        /// </summary>
        private SpatialMappingCollider spatialMappingCollider;
    
  5. 追加、 Awake()Start() :Add the Awake() and Start():

        /// <summary>
        /// Initializes this class
        /// </summary>
        private void Awake()
        {
            // Allows this instance to behave like a singleton
            Instance = this;
        }
    
        /// <summary>
        /// Runs at initialization right after Awake method
        /// </summary>
        void Start()
        {
            // Initialize and configure the collider
            spatialMappingCollider = gameObject.GetComponent<SpatialMappingCollider>();
            spatialMappingCollider.surfaceParent = this.gameObject;
            spatialMappingCollider.freezeUpdates = false;
            spatialMappingCollider.layer = physicsLayer;
    
            // define the mask
            PhysicsRaycastMask = 1 << physicsLayer;
    
            // set the object as active one
            gameObject.SetActive(true);
        }
    
  6. 削除、 Update() メソッド。Delete the Update() method.

  7. 変更を保存することを確認するVisual Studioに戻る前にUnityします。Be sure to save your changes in Visual Studio, before returning to Unity.

8 - 章 GazeCursor クラスを作成します。Chapter 8 - Create the GazeCursor class

このクラスは実際の領域で、正しい位置にカーソルを設定するための使用することで、 SpatialMappingCollider前の章で作成された。This class is responsible for setting up the cursor in the correct location in real space, by making use of the SpatialMappingCollider, created in the previous chapter.

このクラスを作成します。To create this class:

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

  2. ダブルクリックして、新しいGazeCursorスクリプト ファイルを開くVisual Studio。Double-click on the new GazeCursor script to open it with Visual Studio.

  3. 上記の次の名前空間があるかどうかを確認、 GazeCursorクラス。Make sure you have the following namespace referenced above the GazeCursor class:

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

        /// <summary>
        /// The cursor (this object) mesh renderer
        /// </summary>
        private MeshRenderer meshRenderer;
    
  5. 更新プログラム、 Start() メソッドを次のコード。Update the Start() method with the following code:

        /// <summary>
        /// Runs at initialization right after the Awake method
        /// </summary>
        void Start()
        {
            // Grab the mesh renderer that is on the same object as this script.
            meshRenderer = gameObject.GetComponent<MeshRenderer>();
    
            // Set the cursor reference
            SceneOrganiser.Instance.cursor = gameObject;
            gameObject.GetComponent<Renderer>().material.color = Color.green;
    
            // If you wish to change the size of the cursor you can do so here
            gameObject.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f);
        }
    
  6. 更新プログラム、 Update() メソッドを次のコード。Update the Update() method with the following code:

        /// <summary>
        /// Update is called once per frame
        /// </summary>
        void Update()
        {
            // Do a raycast into the world based on the user's head position and orientation.
            Vector3 headPosition = Camera.main.transform.position;
            Vector3 gazeDirection = Camera.main.transform.forward;
    
            RaycastHit gazeHitInfo;
            if (Physics.Raycast(headPosition, gazeDirection, out gazeHitInfo, 30.0f, SpatialMapping.PhysicsRaycastMask))
            {
                // If the raycast hit a hologram, display the cursor mesh.
                meshRenderer.enabled = true;
                // Move the cursor to the point where the raycast hit.
                transform.position = gazeHitInfo.point;
                // Rotate the cursor to hug the surface of the hologram.
                transform.rotation = Quaternion.FromToRotation(Vector3.up, gazeHitInfo.normal);
            }
            else
            {
                // If the raycast did not hit a hologram, hide the cursor mesh.
                meshRenderer.enabled = false;
            }
        }
    

    注意

    エラーをあまり心配しないで、 SceneOrganiserクラスが、[次へ] の章では作成します。Do not worry about the error for the SceneOrganiser class not being found, you will create it in the next chapter.

  7. 変更を保存することを確認するVisual Studioに戻る前にUnityします。Be sure to save your changes in Visual Studio, before returning to Unity.

9 - 章 SceneOrganiser クラスを作成します。Chapter 9 - Create the SceneOrganiser class

このクラスは。This class will:

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

  • オブジェクトが検出されたときに、現実の世界と配置内の位置を計算する責任を負いますなります、タグ ラベルと、該当の近くタグ名します。When an object is detected, it will be responsible for calculating its position in the real world and place a Tag Label near it with the appropriate Tag Name.

このクラスを作成します。To create this class:

  1. 内で右クリック、スクリプトフォルダー、 をクリックし、作成 > C#スクリプトします。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. 上記の次の名前空間があるかどうかを確認、 SceneOrganiserクラス。Make sure you have the following namespaces referenced above the SceneOrganiser class:

    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    
  4. 内で、次の変数を追加し、 SceneOrganiserクラス上、 Start() メソッド。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 Main Camera
        /// </summary>
        internal GameObject cursor;
    
        /// <summary>
        /// The label used to display the analysis on the objects in the real world
        /// </summary>
        public GameObject label;
    
        /// <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.8f;
    
        /// <summary>
        /// The quad object hosting the imposed image captured
        /// </summary>
        private GameObject quad;
    
        /// <summary>
        /// Renderer of the quad object
        /// </summary>
        internal Renderer quadRenderer;
    
  5. 削除、 Start()Update() メソッド。Delete the Start() and Update() methods.

  6. 変数の下に追加、 Awake() メソッドはクラスを初期化し、シーンを設定します。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 CustomVisionObjects class to this Gameobject
            gameObject.AddComponent<CustomVisionObjects>();
        }
    
  7. 追加、 PlaceAnalysisLabel() メソッドはInstantiate (これは、この時点では、ユーザーに表示される)、シーン内のラベル。Add the PlaceAnalysisLabel() method, which will Instantiate the label in the scene (which at this point is invisible to the user). クアッド (も非表示)、イメージが配置されると、し、現実の世界と重複しても配置されます。It also places the quad (also invisible) where the image is placed, and overlaps with the real world. これは、機能は、分析は、実際のオブジェクトのおおよその場所を決定するには、このクアッドにまでトレースした後、ボックスの座標が、サービスから取得したため、重要です。This is important because the box coordinates retrieved from the Service after analysis are traced back into this quad to determined the approximate location of the object in the real world.

        /// <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>();
            lastLabelPlacedText.text = "";
            lastLabelPlaced.transform.localScale = new Vector3(0.005f,0.005f,0.005f);
    
            // Create a GameObject to which the texture can be applied
            quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
            quadRenderer = quad.GetComponent<Renderer>() as Renderer;
            Material m = new Material(Shader.Find("Legacy Shaders/Transparent/Diffuse"));
            quadRenderer.material = m;
    
            // Here you can set the transparency of the quad. Useful for debugging
            float transparency = 0f;
            quadRenderer.material.color = new Color(1, 1, 1, transparency);
    
            // Set the position and scale of the quad depending on user position
            quad.transform.parent = transform;
            quad.transform.rotation = transform.rotation;
    
            // The quad is positioned slightly forward in font of the user
            quad.transform.localPosition = new Vector3(0.0f, 0.0f, 3.0f);
    
            // The quad scale as been set with the following value following experimentation,  
            // to allow the image on the quad to be as precisely imposed to the real world as possible
            quad.transform.localScale = new Vector3(3f, 1.65f, 1f);
            quad.transform.parent = null;
        }
    
  8. 追加、 FinaliseLabel() メソッド。Add the FinaliseLabel() method. 担当します。It is responsible for:

    • 設定、ラベルテキストをタグの最高の信頼性と予測します。Setting the Label text with the Tag of the Prediction with the highest confidence.
    • 計算を呼び出す、境界ボックスクアッドのオブジェクトでは、以前は、配置およびシーン内のラベルを配置することにします。Calling the calculation of the Bounding Box on the quad object, positioned previously, and placing the label in the scene.
    • に向けての Raycast を使用して、ラベルの深さを調整すること、境界ボックス、現実の世界でオブジェクトが衝突する必要があります。Adjusting the label depth by using a Raycast towards the Bounding Box, which should collide against the object in the real world.
    • 別のイメージをキャプチャするユーザーを許可するキャプチャ プロセスをリセットしています。Resetting the capture process to allow the user to capture another image.
        /// <summary>
        /// Set the Tags as Text of the last label created. 
        /// </summary>
        public void FinaliseLabel(AnalysisRootObject analysisObject)
        {
            if (analysisObject.predictions != null)
            {
                lastLabelPlacedText = lastLabelPlaced.GetComponent<TextMesh>();
                // Sort the predictions to locate the highest one
                List<Prediction> sortedPredictions = new List<Prediction>();
                sortedPredictions = analysisObject.predictions.OrderBy(p => p.probability).ToList();
                Prediction bestPrediction = new Prediction();
                bestPrediction = sortedPredictions[sortedPredictions.Count - 1];
    
                if (bestPrediction.probability > probabilityThreshold)
                {
                    quadRenderer = quad.GetComponent<Renderer>() as Renderer;
                    Bounds quadBounds = quadRenderer.bounds;
    
                    // Position the label as close as possible to the Bounding Box of the prediction 
                    // At this point it will not consider depth
                    lastLabelPlaced.transform.parent = quad.transform;
                    lastLabelPlaced.transform.localPosition = CalculateBoundingBoxPosition(quadBounds, bestPrediction.boundingBox);
    
                    // Set the tag text
                    lastLabelPlacedText.text = bestPrediction.tagName;
    
                    // Cast a ray from the user's head to the currently placed label, it should hit the object detected by the Service.
                    // At that point it will reposition the label where the ray HL sensor collides with the object,
                    // (using the HL spatial tracking)
                    Debug.Log("Repositioning Label");
                    Vector3 headPosition = Camera.main.transform.position;
                    RaycastHit objHitInfo;
                    Vector3 objDirection = lastLabelPlaced.position;
                    if (Physics.Raycast(headPosition, objDirection, out objHitInfo, 30.0f,   SpatialMapping.PhysicsRaycastMask))
                    {
                        lastLabelPlaced.position = objHitInfo.point;
                    }
                }
            }
            // Reset the color of the cursor
            cursor.GetComponent<Renderer>().material.color = Color.green;
    
            // Stop the analysis process
            ImageCapture.Instance.ResetImageCapture();        
        }
    
  9. 追加、 CalculateBoundingBoxPosition() メソッドは、さまざまな変換に必要な計算をホストする、境界ボックス座標は、サービスから取得され、再作成します。クアッド比例的に。Add the CalculateBoundingBoxPosition() method, which hosts a number of calculations necessary to translate the Bounding Box coordinates retrieved from the Service and recreate them proportionally on the quad.

        /// <summary>
        /// This method hosts a series of calculations to determine the position 
        /// of the Bounding Box on the quad created in the real world
        /// by using the Bounding Box received back alongside the Best Prediction
        /// </summary>
        public Vector3 CalculateBoundingBoxPosition(Bounds b, BoundingBox boundingBox)
        {
            Debug.Log($"BB: left {boundingBox.left}, top {boundingBox.top}, width {boundingBox.width}, height {boundingBox.height}");
    
            double centerFromLeft = boundingBox.left + (boundingBox.width / 2);
            double centerFromTop = boundingBox.top + (boundingBox.height / 2);
            Debug.Log($"BB CenterFromLeft {centerFromLeft}, CenterFromTop {centerFromTop}");
    
            double quadWidth = b.size.normalized.x;
            double quadHeight = b.size.normalized.y;
            Debug.Log($"Quad Width {b.size.normalized.x}, Quad Height {b.size.normalized.y}");
    
            double normalisedPos_X = (quadWidth * centerFromLeft) - (quadWidth/2);
            double normalisedPos_Y = (quadHeight * centerFromTop) - (quadHeight/2);
    
            return new Vector3((float)normalisedPos_X, (float)normalisedPos_Y, 0);
        }
    
  10. 変更を保存することを確認するVisual Studioに戻る前にUnityします。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:

    // Create a texture. Texture size does not matter, since 
    // LoadImage will replace with the incoming image size.
    Texture2D tex = new Texture2D(1, 1);
    tex.LoadImage(imageBytes);
    SceneOrganiser.Instance.quadRenderer.material.SetTexture("_MainTex", tex);
    
    // The response will be in JSON format, therefore it needs to be deserialized
    AnalysisRootObject analysisRootObject = new AnalysisRootObject();
    analysisRootObject = JsonConvert.DeserializeObject<AnalysisRootObject>(jsonResponse);
    
    SceneOrganiser.Instance.FinaliseLabel(analysisRootObject);
    

注意

心配しないで、 ImageCapture '見つかりませんでした' メッセージのクラス、[次へ] の章では作成します。Do not worry about the ImageCapture class 'could not be found' message, you will create it in the next chapter.

10 - 章 ImageCapture クラスを作成します。Chapter 10 - 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.
  • 処理タップユーザーからのジェスチャ。Handling Tap gestures from the user.

このクラスを作成します。To create this class:

  1. 移動して、スクリプト以前に作成したフォルダーです。Go to the Scripts folder you created previously.

  2. フォルダー内を右クリックし、をクリックして作成 > C#スクリプトします。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. 内で、次の変数を追加し、 ImageCaptureクラス上、 Start() メソッド。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>
        /// 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. コードをAwake()Start() 今すぐメソッドを追加する必要があります。Code for Awake() and Start() methods now needs to be added:

        /// <summary>
        /// Called on initialization
        /// </summary>
        private void Awake()
        {
            Instance = this;
        }
    
        /// <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 Microsoft HoloLens API gesture recognizer to track user gestures
            recognizer = new GestureRecognizer();
            recognizer.SetRecognizableGestures(GestureSettings.Tap);
            recognizer.Tapped += TapHandler;
            recognizer.StartCapturingGestures();
        }
    
  7. タップ ジェスチャが発生したときに呼び出されるハンドラーを実装します。Implement a handler that will be called when a Tap gesture occurs:

        /// <summary>
        /// Respond to Tap Input.
        /// </summary>
        private void TapHandler(TappedEventArgs obj)
        {
            if (!captureIsActive)
            {
                captureIsActive = true;
    
                // Set the cursor color to red
                SceneOrganiser.Instance.cursor.GetComponent<Renderer>().material.color = Color.red;
    
                // Begin the capture loop
                Invoke("ExecuteImageCaptureAndAnalysis", 0);
            }
        }
    

    重要

    カーソルがある場合緑色カメラが、イメージを意味します。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()
        {
            // Create a label in world space using the ResultsLabel 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(true, delegate (PhotoCapture captureObject)
            {
                photoCaptureObject = captureObject;
    
                CameraParameters camParameters = new CameraParameters
                {
                    hologramOpacity = 1.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分析します。The result is then passed to the CustomVisionAnalyser for analysis.

        /// <summary>
        /// Register the full execution of the Photo Capture. 
        /// </summary>
        void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
        {
            try
            {
                // Call StopPhotoMode once the image has successfully captured
                photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
            }
            catch (Exception e)
            {
                Debug.LogFormat("Exception capturing photo to disk: {0}", e.Message);
            }
        }
    
        /// <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;
    
            // Call the image analysis
            StartCoroutine(CustomVisionAnalyser.Instance.AnalyseLastImageCaptured(filePath)); 
        }
    
        /// <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;
    
            // Stop the capture loop if active
            CancelInvoke();
        }
    
  10. 変更を保存することを確認するVisual Studioに戻る前にUnityします。Be sure to save your changes in Visual Studio, before returning to Unity.

第 11 章 – シーン内のスクリプトの設定Chapter 11 - Setting up the scripts in the scene

これですべてのこのプロジェクトに必要なコードを記述して、シーンと正しく動作するように、プレハブのスクリプトを設定するにはNow that you have written all of the code necessary for this project, is time to set up the scripts in the scene, and on the prefabs, for them to behave correctly.

  1. 内で、 Unity エディター階層パネルを選択、 Main Cameraします。Within the Unity Editor, in the Hierarchy Panel, select the Main Camera.

  2. インスペクター パネルで、 Main Camera選択すると、をクリックしてコンポーネントの追加、検索しSceneOrganiserスクリプトと追加するをダブルクリックします。In the Inspector Panel, with the Main Camera selected, click on Add Component, then search for SceneOrganiser script and double-click, to add it.

  3. プロジェクト パネル、オープン、 Prefabs フォルダー、ドラッグ、ラベルにプレハブ、ラベル空の参照先の領域を入力する、SceneOrganiserに追加したスクリプト、 Main Camera次の図に示すように、します。In the Project Panel, open the Prefabs folder, drag the Label prefab into the Label empty reference target input area, in the SceneOrganiser script that you have just added to the Main Camera, as shown in the image below:

  4. 階層パネルを選択、 GazeCursorの子、 Main Cameraします。In the Hierarchy Panel, select the GazeCursor child of the Main Camera.

  5. インスペクター パネルで、 GazeCursor選択すると、をクリックしてコンポーネントの追加を検索しGazeCursorスクリプトと追加するをダブルクリックします。In the Inspector Panel, with the GazeCursor selected, click on Add Component, then search for GazeCursor script and double-click, to add it.

  6. もう一度、階層パネルを選択、 SpatialMappingの子、 Main CameraAgain, in the Hierarchy Panel, select the SpatialMapping child of the Main Camera.

  7. インスペクター パネルで、 SpatialMapping選択すると、をクリックしてコンポーネントの追加を検索しSpatialMappingスクリプトそれを追加する をダブルクリックします。In the Inspector Panel, with the SpatialMapping selected, click on Add Component, then search for SpatialMapping script and double-click, to add it.

残りのスクリプトをするがないセット内のコードで追加されます、 SceneOrganiserスクリプトの実行時に、します。The remaining scripts thats you have not set will be added by the code in the SceneOrganiser script, during runtime.

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

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

実行する前にいることを確認します。Before you do, ensure that:

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

  • スクリプトSceneOrganiserにアタッチされて、 Main Cameraオブジェクト。The script SceneOrganiser is attached to the Main Camera object.

  • スクリプトGazeCursorにアタッチされて、 GazeCursorオブジェクト。The script GazeCursor is attached to the GazeCursor object.

  • スクリプトSpatialMappingにアタッチされて、 SpatialMappingオブジェクト。The script SpatialMapping is attached to the SpatialMapping object.

  • 第 5 章手順 6。In Chapter 5, Step 6:

    • 挿入することを確認、サービス予測キーに、 predictionKey変数。Make sure you insert your Service Prediction Key into the predictionKey variable.
    • 挿入した、予測エンドポイントに、 predictionEndpointクラス。You have inserted your Prediction Endpoint into the predictionEndpoint class.

章 13 - アプリケーションを作成、UWP のソリューションとサイドロードします。Chapter 13 - Build the UWP solution and sideload your application

Microsoft HoloLens にデプロイすることができますを UWP ソリューションとしてのアプリケーションを構築する準備が整いました。You are now ready to build you application as a UWP Solution that you will be able to deploy on to the Microsoft HoloLens. ビルド プロセスを開始します。To begin the build process:

  1. 移動してファイル > のビルド設定します。Go to File > Build Settings.

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

  3. をクリックして開くシーンを追加します。Click on Add Open Scenes. これにより、ビルドに現在開いているシーンが追加されます。This will add the currently open scene to the build.

  4. [Build] をクリックします。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. ここで、そのフォルダーを作成し、名前アプリします。Create that folder now, and name it App. 使用し、アプリフォルダーを選択すると、クリックしてフォルダーの選択します。Then with the App folder selected, click Select Folder.

  5. Unity にプロジェクトをビルドを開始、アプリフォルダー。Unity will begin building your project to the App folder.

  6. 1 回 Unity には、(少し時間がかかる場合があります) ビルドが完了したが開き、ファイル エクスプ ローラービルドの位置にあるウィンドウ (上の windows では、常に表示されないの新しい追加の通知をタスク バーを確認ウィンドウ)。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).

  7. Microsoft HoloLens を展開する必要がありますそのデバイスの IP アドレス (リモート) をデプロイ用ともいることを確認するのには開発者モードを設定します。To deploy on to Microsoft HoloLens, you will need the IP Address of that device (for Remote Deploy), and to ensure that it also has Developer Mode set. これには、次の手順を実行します。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. 次に移動します設定、し更新とセキュリティ > 開発者向けNext, navigate back to Settings, and then to Update & Security > For Developers

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

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

  9. ソリューション構成の選択でデバッグします。In the Solution Configuration select Debug.

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

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

  12. アプリが、Microsoft HoloLens、起動の準備完了にインストールされているアプリの一覧に表示されます。Your app should now appear in the list of installed apps on your Microsoft HoloLens, ready to be launched!

アプリケーションを使用します。To use the application:

  • トレーニングがオブジェクトを見て、 Azure Custom Vision Service、オブジェクトの検出を使用して、タップ ジェスチャします。Look at an object, which you have trained with your Azure Custom Vision Service, Object Detection, and use the Tap gesture.
  • 場合は、オブジェクトが正常に検出されると、ワールド空間ラベル テキストタグ名と共に表示されます。If the object is successfully detected, a world-space Label Text will appear with the tag name.

重要

写真をキャプチャして、サービスに送信するたびには、サービスのページに戻るし、新しくキャプチャされたイメージのサービスの再トレーニングします。Every time you capture a photo and send it to the Service, you can go back to the Service page and retrain the Service with the newly captured images. を先頭には、おそらく修正する必要も、境界ボックスより正確になるし、サービスの再トレーニングします。At the beginning, you will probably also have to correct the Bounding Boxes to be more accurate and retrain the Service.

注意

配置ラベルのテキストは可能性があります、現実世界のオブジェクトを基準とした、適切なコライダーを配置する Microsoft HoloLens のセンサーや Unity で SpatialTrackingComponent が失敗したときに、オブジェクトの近くは表示されません。The Label Text placed might not appear near the object when the Microsoft HoloLens sensors and/or the SpatialTrackingComponent in Unity fails to place the appropriate colliders, relative to the real world objects. その場合は、異なる画面で、アプリケーションを使用してください。Try to use the application on a different surface if that is the case.

カスタム ビジョン、アプリケーションのオブジェクトの検出Your Custom Vision, Object Detection application

これで、Azure の Custom Vision がイメージからオブジェクトを認識して 3D 空間でそのオブジェクトのおおよその位置を提供し、オブジェクト検出 API を利用している mixed reality アプリを構築します。Congratulations, you built a mixed reality app that leverages the Azure Custom Vision, Object Detection API, which can recognize an object from an image, and then provide an approximate position for that object in 3D space.

ボーナスの演習Bonus exercises

手順 1Exercise 1

3D に実際のオブジェクトをラップする半透明にするキューブを使用して、テキスト ラベルを追加する境界ボックスします。Adding to the Text Label, use a semi-transparent cube to wrap the real object in a 3D Bounding Box.

手順 2Exercise 2

複数のオブジェクトを認識する、Custom Vision Service をトレーニングします。Train your Custom Vision Service to recognize more objects.

手順 3Exercise 3

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

手順 4Exercise 4

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).