MR und Azure 302b: Custom VisionMR and Azure 302b: Custom vision


Hinweis

Die Tutorials der Mixed Reality Academy wurden im Hinblick auf HoloLens (1. Gen.) und immersive Mixed Reality-Headsets entworfen.The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. Daher halten wir es für wichtig, diese Tutorials für Entwickler verfügbar zu halten, die noch nach Anleitung beim Entwickeln für diese Geräte suchen.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. Diese Tutorials werden nicht mit den neuesten Toolsets oder Interaktionen aktualisiert, die für HoloLens 2 verwendet werden.These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. Sie werden gewartet, um weiterhin auf den unterstützten Geräten zu funktionieren.They will be maintained to continue working on the supported devices. Es gibt eine neue Reihe von Tutorials, die in Zukunft veröffentlicht werden, um die Entwicklung für hololens 2 zu veranschaulichen.There will be a new series of tutorials that will be posted in the future that will demonstrate how to develop for HoloLens 2. Dieser Hinweis wird mit einem Link zu diesen Tutorials aktualisiert, wenn diese veröffentlicht werden.This notice will be updated with a link to those tutorials when they are posted.


In diesem Kurs erfahren Sie, wie Sie benutzerdefinierte visuelle Inhalte in einem bereitgestellten Image erkennen können, indem Sie die Funktionen von Azure Custom Vision in einer Mixed Reality-Anwendung verwenden.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.

Mit diesem Dienst können Sie ein Machine Learning-Modell mithilfe von Objekt Images trainieren.This service will allow you to train a machine learning model using object images. Sie verwenden dann das trainierte Modell, um ähnliche Objekte zu erkennen, die von der Kamera Erfassung von Microsoft hololens oder einer Kamera bereitgestellt werden, die mit Ihrem PC für immersive (VR) Headsets verbunden ist.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.

Kurs Ergebnis

Bei Azure Custom Vision handelt es sich um einen Microsoft Cognitive Service, der Entwicklern das Erstellen benutzerdefinierter Image Klassifizierer ermöglicht.Azure Custom Vision is a Microsoft Cognitive Service which allows developers to build custom image classifiers. Diese Klassifizierungen können dann mit neuen Bildern verwendet werden, um Objekte innerhalb dieses neuen Bilds zu erkennen oder zu klassifizieren.These classifiers can then be used with new images to recognize, or classify, objects within that new image. Der Dienst bietet ein einfaches, leicht zu verwendende Onlineportal, um den Prozess zu optimieren.The Service provides a simple, easy to use, online portal to streamline the process. Weitere Informationen finden Sie auf der Seite Azure Custom Vision Service.For more information, visit the Azure Custom Vision Service page.

Nach Abschluss dieses Kurses verfügen Sie über eine Mixed Reality-Anwendung, die in zwei Modi arbeiten kann:Upon completion of this course, you will have a mixed reality application which will be able to work in two modes:

  • Analysemodus: Manuelles Einrichten der Custom Vision Service durch Hochladen von Bildern, Erstellen von Tags und trainieren des Dienstanbieter, um unterschiedliche Objekte (in diesem Fall Maus und Tastatur) zu erkennen.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). Anschließend erstellen Sie eine hololens-APP, mit der Bilder mithilfe der Kamera erfasst werden, und versuchen, diese Objekte in der realen Welt zu erkennen.You will then create a HoloLens app that will capture images using the camera, and try to recognize those objects in the real world.

  • Schulungs Modus: Sie implementieren Code, der einen "Schulungs Modus" in ihrer App aktiviert.Training Mode: you will implement code that will enable a "Training Mode" in your app. Der Trainingsmodus ermöglicht Ihnen das Erfassen von Bildern mithilfe der Kamera von hololens, das Hochladen der aufgezeichneten Images in den Dienst und das Trainieren des benutzerdefinierten Vision-Modells.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.

In diesem Kurs erfahren Sie, wie Sie die Ergebnisse aus dem Custom Vision Service in einer Unity-basierten Beispielanwendung erhalten.This course will teach you how to get the results from the Custom Vision Service into a Unity-based sample application. Sie müssen diese Konzepte auf eine benutzerdefinierte Anwendung anwenden, die Sie möglicherweise aufbauen.It will be up to you to apply these concepts to a custom application you might be building.

GeräteunterstützungDevice support

KursCourse HoloLensHoloLens Immersive HeadsetsImmersive headsets
MR und Azure 302b: Custom VisionMR and Azure 302b: Custom vision ✔️✔️ ✔️✔️

Hinweis

Dieser Kurs konzentriert sich in erster Linie auf hololens, aber Sie können auch das Erlernen, was Sie in diesem Kurs lernen, auf Windows Mixed Reality-(VR)-Headsets.While this course primarily focuses on HoloLens, you can also apply what you learn in this course to Windows Mixed Reality immersive (VR) headsets. Da immersive Headsets (VR) nicht über barrierefreie Kameras verfügen, benötigen Sie eine externe Kamera, die mit Ihrem PC verbunden ist.Because immersive (VR) headsets do not have accessible cameras, you will need an external camera connected to your PC. Wenn Sie den Kurs befolgen, finden Sie Hinweise zu allen Änderungen, die Sie möglicherweise für die Unterstützung von immersiven (VR)-Headsets verwenden müssen.As you follow along with the course, you will see notes on any changes you might need to employ to support immersive (VR) headsets.

VoraussetzungenPrerequisites

Hinweis

Dieses Tutorial richtet sich an Entwickler, die über grundlegende Kenntnisse in Unity und c# verfügen.This tutorial is designed for developers who have basic experience with Unity and C#. Beachten Sie auch, dass die Voraussetzungen und Anweisungen in diesem Dokument darstellen, was zum Zeitpunkt des Schreibens getestet und überprüft wurde (Juli 2018).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). Sie können die neueste Software verwenden, die im Artikel Installieren der Tools aufgeführt ist. es sollte jedoch nicht davon ausgegangen werden, dass die Informationen in diesem Kurs genau mit den Informationen in neueren Software vergleichen, als im folgenden aufgeführt werden.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.

Für diesen Kurs empfehlen wir die folgende Hardware und Software:We recommend the following hardware and software for this course:

VorbereitungBefore you start

  1. Um Probleme zu vermeiden, die beim Erstellen dieses Projekts auftreten, wird dringend empfohlen, dass Sie das in diesem Tutorial erwähnte Projekt in einem Stamm Ordner oder in einem Ordner mit einem Stamm Ordner erstellen (lange Ordner Pfade können zur Buildzeit Probleme verursachen).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. Richten Sie Ihre hololens ein, und testen Sie Sie.Set up and test your HoloLens. Wenn Sie Unterstützung für die Einrichtung ihrer hololens benötigen, besuchen Sie den Artikel zum Einrichten von hololens.If you need support setting up your HoloLens, make sure to visit the HoloLens setup article.
  3. Es empfiehlt sich, eine Kalibrierung und Sensor Optimierung durchzuführen, wenn Sie mit der Entwicklung einer neuen hololens-App beginnen (manchmal kann es hilfreich sein, diese Aufgaben für jeden Benutzer auszuführen).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).

Hilfe zur Kalibrierung finden Sie unter diesem Link zum Artikel zur hololens-Kalibrierung.For help on Calibration, please follow this link to the HoloLens Calibration article.

Hilfe zur Sensor Optimierung finden Sie unter diesem Link zum Artikel zur Überwachung von hololens-Sensoren.For help on Sensor Tuning, please follow this link to the HoloLens Sensor Tuning article.

Kapitel 1: das Custom Vision Service-PortalChapter 1 - The Custom Vision Service Portal

Um die Custom Vision Service in Azure verwenden zu können, müssen Sie eine Instanz des-Dienstanbieter konfigurieren, die für die Anwendung verfügbar gemacht wird.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. Navigieren Sie zunächst zur Custom Vision Service Hauptseite.First, navigate to the Custom Vision Service main page.

  2. Klicken Sie auf die Schaltfläche Get Started .Click on the Get Started button.

    Beginnen Sie mit Custom Vision Service

  3. Melden Sie sich beim Custom Vision Service -Portal an.Sign in to the Custom Vision Service Portal.

    Anmelden beim Portal

    Hinweis

    Wenn Sie noch nicht über ein Azure-Konto verfügen, müssen Sie eines erstellen.If you do not already have an Azure account, you will need to create one. Wenn Sie dieses Tutorial in einer Classroom-oder Lab-Situation befolgen, bitten Sie Ihren Dozenten oder einen der Proctors, Hilfe beim Einrichten Ihres neuen Kontos zu erhalten.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. Wenn Sie sich zum ersten Mal angemeldet haben, werden Sie im Bereich mit den Nutzungsbedingungen aufgefordert.Once you are logged in for the first time, you will be prompted with the Terms of Service panel. Aktivieren Sie das Kontrollkästchen, um den Bedingungen zuzustimmen.Click on the checkbox to agree to the terms. Klicken Sie dann auf Ich stimme zu.Then click on I agree.

    Vertragsbedingungen

  5. Nachdem Sie die Bedingungen zugestimmt haben, werden Sie zum Abschnitt " Projekte " im Portal navigiert.Having agreed to the Terms, you will be navigated to the Projects section of the Portal. Klicken Sie auf Neues Projekt.Click on New Project.

    Erstellen eines neuen Projekts

  6. Eine Registerkarte wird auf der rechten Seite angezeigt, auf der Sie aufgefordert werden, einige Felder für das Projekt anzugeben.A tab will appear on the right-hand side, which will prompt you to specify some fields for the project.

    1. Fügen Sie einen Namen für das Projekt ein.Insert a Name for your project.

    2. Fügen Sie eine Beschreibung für das Projekt ein (optional).Insert a Description for your project (optional).

    3. Wählen Sie eine Ressourcengruppe aus, oder erstellen Sie eine neue Ressourcengruppe .Choose a Resource Group or create a new one. Eine Ressourcengruppe bietet eine Möglichkeit zum überwachen, Steuern des Zugriffs, bereitstellen und Verwalten der Abrechnung für eine Sammlung von Azure-Ressourcen.A resource group provides a way to monitor, control access, provision and manage billing for a collection of Azure assets. Es wird empfohlen, alle Azure-Dienste, die einem einzelnen Projekt (z. b. diesen Kursen) zugeordnet sind, in einer gemeinsamen Ressourcengruppe zu speichern.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. Festlegen der Projekttypen auf KlassifizierungSet the Project Types to Classification

    5. Legen Sie die Domänen als Allgemein fest.Set the Domains as General.

      Festlegen der Domänen

      Weitere Informationen zu Azure-Ressourcengruppen finden Sie im Artikel Ressourcengruppe.If you wish to read more about Azure Resource Groups, please visit the resource group article.

  7. Wenn Sie fertig sind, klicken Sie auf Projekt erstellen. Sie werden auf die Seite Custom Vision Service, Projekt, umgeleitet.Once you are finished, click on Create project, you will be redirected to the Custom Vision Service, project page.

Kapitel 2: trainieren Ihres Custom Vision ProjektsChapter 2 - Training your Custom Vision project

Wenn Sie sich im Custom Vision Portal befinden, besteht das Hauptziel darin, das Projekt zu trainieren, um bestimmte Objekte in Bildern zu erkennen.Once in the Custom Vision portal, your primary objective is to train your project to recognize specific objects in images. Sie benötigen mindestens fünf (5) Images, obwohl zehn (10) für jedes Objekt bevorzugt werden, das Ihre Anwendung erkennen soll.You need at least five (5) images, though ten (10) is preferred, for each object that you would like your application to recognize. Sie können die Bilder verwenden, die mit diesem Kurs bereitgestellt werden (Computermaus und Tastatur).You can use the images provided with this course (a computer mouse and a keyboard).

So trainieren Sie das Custom Vision Service Projekt:To train your Custom Vision Service project:

  1. Klicken Sie auf die + Schaltfläche neben Tags.Click on the + button next to Tags.

    Hinzufügen eines neuen Tags

  2. Fügen Sie den Namen des Objekts hinzu, das Sie erkennen möchten.Add the name of the object you would like to recognize. Klicken Sie auf Speichern.Click on Save.

    Objektnamen hinzufügen und speichern

  3. Sie werden feststellen, dass Ihr Tag hinzugefügt wurde (möglicherweise müssen Sie die Seite erneut laden, damit es angezeigt wird).You will notice your Tag has been added (you may need to reload your page for it to appear). Aktivieren Sie das Kontrollkästchen neben dem neuen Tag, wenn es nicht bereits aktiviert ist.Click the checkbox alongside your new tag, if it is not already checked.

    Neues Tag aktivieren

  4. Klicken Sie in der Mitte der Seite auf Bilder hinzufügen .Click on Add Images in the center of the page.

    Hinzufügen von Bildern

  5. Klicken Sie auf lokale Dateien durchsuchen, suchen Sie, und wählen Sie dann die Images aus, die Sie hochladen möchten, mit dem Minimalwert fünf (5).Click on Browse local files, and search, then select, the images you would like to upload, with the minimum being five (5). Denken Sie daran, dass alle diese Images das Objekt enthalten sollten, das Sie trainieren.Remember all of these images should contain the object which you are training.

    Hinweis

    Sie können mehrere Bilder gleichzeitig zum Hochladen auswählen.You can select several images at a time, to upload.

  6. Wenn Sie die Bilder auf der Registerkarte sehen können, wählen Sie im Feld Meine Tags das entsprechende Tag aus.Once you can see the images in the tab, select the appropriate tag in the My Tags box.

    Tags auswählen

  7. Klicken Sie auf Dateien hochladen.Click on Upload files. Die Dateien werden hochgeladen.The files will begin uploading. Nachdem Sie den Upload bestätigt haben, klicken Sie auf done.Once you have confirmation of the upload, click Done.

    Hochladen von Dateien

  8. Wiederholen Sie den Vorgang, um ein neues Tag mit dem Namen Tastatur zu erstellen, und laden Sie die entsprechenden Fotos dafür hoch.Repeat the same process to create a new Tag named Keyboard and upload the appropriate photos for it. Wenn Sie die neuen Tags erstellt haben, Deaktivieren Sie die Maus , um das Fenster Bilder hinzufügen anzuzeigen.Make sure to uncheck Mouse once you have created the new tags, so to show the Add images window.

  9. Nachdem Sie beide Tags eingerichtet haben, klicken Sie auf trainieren, und die erste Trainings Iterationen wird erstellt.Once you have both Tags set up, click on Train, and the first training iteration will start building.

    Trainings Iterationen aktivieren

  10. Nachdem er erstellt wurde, können Sie zwei Schaltflächen mit dem Namen " default " und die Vorhersage-URL anzeigen.Once it's built, you'll be able to see two buttons called Make default and Prediction URL. Klicken Sie zuerst auf Standardwert erstellen , und klicken Sie dann auf Vorhersage-URL.Click on Make default first, then click on Prediction URL.

    Standard-und Vorhersage-URL erstellen

    Hinweis

    Die Endpunkt-URL, die von diesem bereitgestellt wird, wird auf den Wert festgelegt, welcher iterations Wert als Standard markiert wurde.The endpoint URL which is provided from this, is set to whichever Iteration has been marked as default. Wenn Sie später eine neue iterations Zeit erstellen und diese als Standard aktualisieren, müssen Sie den Code nicht ändern.As such, if you later make a new Iteration and update it as default, you will not need to change your code.

  11. Nachdem Sie auf die Vorhersage-URL geklickt haben, öffnen Sie Notepad, kopieren Sie die URL und den Vorhersage Schlüssel, und fügen Sie Sie ein, damit Sie Sie später im Code abrufen können.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.

    Kopieren und Einfügen von URL und Prediction-Key

  12. Klicken Sie rechts oben auf dem Bildschirm auf das Zahnrad Symbol.Click on the Cog at the top right of the screen.

    Klicken Sie auf das Zahnrad Symbol, um Einstellungen zu öffnen.

  13. Kopieren Sie den Trainings Schlüssel , und fügen Sie ihn zur späteren Verwendung in einen Editor ein.Copy the Training Key and paste it into a Notepad, for later use.

    Schulungs Schlüssel kopieren

  14. Kopieren Sie auch die Projekt-ID, und fügen Sie Sie zur späteren Verwendung in die Notepad -Datei ein.Also copy your Project Id, and also paste it into your Notepad file, for later use.

    Projekt-ID kopieren

Kapitel 3: Einrichten des Unity-ProjektsChapter 3 - Set up the Unity project

Folgendes ist eine typische Einrichtung für die Entwicklung mit gemischter Realität und ist daher eine gute Vorlage für andere Projekte.The following is a typical set up for developing with mixed reality, and as such, is a good template for other projects.

  1. Öffnen Sie Unity , und klicken Sie auf neu.Open Unity and click New.

    Erstellen eines neuen Unity-Projekts

  2. Sie müssen nun einen Unity-Projektnamen angeben.You will now need to provide a Unity project name. Fügen Sie azurecustomvision ein.Insert AzureCustomVision. Stellen Sie sicher, dass die Projektvorlage auf 3D festgelegt ist.Make sure the project template is set to 3D. Legen Sie den Speicherort auf einen geeigneten Speicherort fest (denken Sie daran, dass die Stamm Verzeichnisse besser sind).Set the Location to somewhere appropriate for you (remember, closer to root directories is better). Klicken Sie dann auf Projekt erstellen.Then, click Create project.

    Konfigurieren von Projekteinstellungen

  3. Wenn Unity geöffnet ist, sollten Sie überprüfen, dass der Standard Skript-Editor auf Visual Studio festgelegt ist.With Unity open, it is worth checking the default Script Editor is set to Visual Studio. Wechseln Sie zu * > Einstellungen bearbeiten* , und navigieren Sie dann im neuen Fenster zu externe Tools.Go to Edit > Preferences and then from the new window, navigate to External Tools. Ändern Sie den Editor für externe Skripts in Visual Studio 2017.Change External Script Editor to Visual Studio 2017. Schließen Sie das Fenster " Einstellungen ".Close the Preferences window.

    Externe Tools konfigurieren

  4. Navigieren Sie als nächstes zu Datei > Buildeinstellungen , wählen Sie universelle Windows-Plattform aus, und klicken Sie dann auf die Schaltfläche Plattform wechseln , um Ihre Auswahl zu übernehmenNext, go to File > Build Settings and select Universal Windows Platform, then click on the Switch Platform button to apply your selection.

    Konfigurieren von BuildeinstellungenConfigure build settings

  5. In Datei > Buildeinstellungen , und stellen Sie Folgendes sicher:While still in File > Build Settings and make sure that:

    1. Zielgerät ist auf hololens festgelegtTarget Device is set to HoloLens

      Legen Sie für die immersiven Headsets das Zielgerät auf ein beliebiges Gerät fest.For the immersive headsets, set Target Device to Any Device.

    2. Der Buildtyp ist auf D3D festgelegt.Build Type is set to D3D

    3. SDK ist auf neueste installierte Version festgelegt.SDK is set to Latest installed

    4. Visual Studio-Version ist auf neueste installierte Version festgelegt.Visual Studio Version is set to Latest installed

    5. Build und Run sind auf lokaler Computer festgelegt.Build and Run is set to Local Machine

    6. Speichern Sie die Szene, und fügen Sie Sie dem Build hinzu.Save the scene and add it to the build.

      1. Wählen Sie hierzu die Option geöffnete Szenen hinzufügen aus.Do this by selecting Add Open Scenes. Ein Fenster zum Speichern wird angezeigt.A save window will appear.

        Hinzufügen einer geöffneten Szene zu einer Buildliste

      2. Erstellen Sie einen neuen Ordner für dieses und jede zukünftige Szene, und wählen Sie dann die Schaltfläche neuer Ordner aus, um einen neuen Ordner zu erstellen.Create a new folder for this, and any future, scene, then select the New folder button, to create a new folder, name it Scenes.

        Neuen Szenen Ordner erstellen

      3. Öffnen Sie den neu erstellten Ordner Szenen , geben Sie im Feld Dateiname: Text den Text customvisionscene ein, und klicken Sie dann auf Speichern.Open your newly created Scenes folder, and then in the File name: text field, type CustomVisionScene, then click on Save.

        Neue Szenen Datei benennen

        Beachten Sie, dass Sie Ihre Unity-Szenen im Ordner " Assets " speichern müssen, da Sie dem Unity-Projekt zugeordnet werden müssen.Be aware, you must save your Unity scenes within the Assets folder, as they must be associated with the Unity project. Das Erstellen eines Szenen Ordners (und anderer ähnlicher Ordner) ist eine typische Methode zum Strukturieren eines Unity-Projekts.Creating the scenes folder (and other similar folders) is a typical way of structuring a Unity project.

    7. Die restlichen Einstellungen in den Buildeinstellungen sollten vorerst als Standard belassen werden.The remaining settings, in Build Settings, should be left as default for now.

      Standardbuildeinstellungen

  6. Klicken Sie im Fenster Buildeinstellungen auf die Schaltfläche Player Einstellungen . Dadurch wird der entsprechende Bereich in dem Bereich geöffnet, in dem sich der Inspektor befindet.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 diesem Bereich müssen einige Einstellungen überprüft werden:In this panel, a few settings need to be verified:

    1. Auf der Registerkarte andere Einstellungen :In the Other Settings tab:

      1. Die CLR- Lauf Zeit Version sollte experimentell sein (.NET 4,6-Entsprechung), wodurch der Editor neu gestartet werden muss.Scripting Runtime Version should be Experimental (.NET 4.6 Equivalent), which will trigger a need to restart the Editor.

      2. Skript -Back-End sollte .net seinScripting Backend should be .NET

      3. API-Kompatibilitäts Grad sollte .NET 4,6 lautenAPI Compatibility Level should be .NET 4.6

      API-Komprimierbarkeit festlegen

    2. Überprüfen Sie auf der Registerkarte Veröffentlichungs Einstellungen unter Funktionen Folgendes:Within the Publishing Settings tab, under Capabilities, check:

      1. InternetClientInternetClient

      2. WebcamWebcam

      3. MikrofonMicrophone

      Konfigurieren von Veröffentlichungseinstellungen

    3. Weiter unten im Bereich in den XR-Einstellungen (siehe Veröffentlichungs Einstellungen), unterstützt Tick Virtual Reality, stellen Sie sicher, dass das Windows Mixed Reality SDK hinzugefügt wurde.Further down the panel, in XR Settings (found below Publish Settings), tick Virtual Reality Supported, make sure the Windows Mixed Reality SDK is added.

    Konfigurieren von XR-Einstellungen

  8. Zurück in Buildeinstellungen : Unity-C- # Projekte sind nicht mehr abgeblendet. Aktivieren Sie das Kontrollkästchen neben this.Back in Build Settings Unity C# Projects is no longer greyed out; tick the checkbox next to this.

  9. Schließen Sie das Fenster „Build Settings“ (Buildeinstellungen).Close the Build Settings window.

  10. Speichern Sie Ihre Szene und Ihr Projekt (Datei > speichern Sie Szenen/Dateien > speichern Sie das Projekt).Save your Scene and project (FILE > SAVE SCENE / FILE > SAVE PROJECT).

Kapitel 4: Importieren der newtonsoft-dll in UnityChapter 4 - Importing the Newtonsoft DLL in Unity

Wichtig

Wenn Sie die Unity-Setup Komponente dieses Kurses überspringen und direkt mit dem Code fortfahren möchten, können Sie dieses Azure-Mr-302b. unitypackageherunterladen, es als benutzerdefiniertes Paketin Ihr Projekt importieren und dann aus Kapitel 6fortfahren.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.

Für diesen Kurs muss die newtonsoft -Bibliothek verwendet werden, die Sie Ihren Assets als dll hinzufügen können.This course requires the use of the Newtonsoft library, which you can add as a DLL to your assets. Das Paket, das Diese Bibliothek enthält, kann von diesem Link heruntergeladen werden.The package containing this library can be downloaded from this Link. Verwenden Sie das Unity-Paket, das in diesem Kurs verwendet wurde, um die newtonsoft-Bibliothek in Ihr Projekt zu importieren.To import the Newtonsoft library into your project, use the Unity Package which came with this course.

  1. Fügen Sie das . unitypackage zu Unity hinzu, indem Sie die Menüoption Assets > Import Package > Custom Package verwenden.Add the .unitypackage to Unity by using the Assets > Import Package > Custom Package menu option.

  2. Vergewissern Sie sich, dass im Feld Unity-Paket importieren , das angezeigt wird, alles unter (und einschließlich) Plug -ins ausgewählt ist.In the Import Unity Package box that pops up, ensure everything under (and including) Plugins is selected.

    Alle Paket Elemente importieren

  3. Klicken Sie auf die Schaltfläche importieren , um dem Projekt die Elemente hinzuzufügen.Click the Import button to add the items to your project.

  4. Wechseln Sie in der Projektansicht unter Plug -in in den Ordner Newton Soft , und wählen Sie die Newtonsoft.Jsfür das Plug-in aus.Go to the Newtonsoft folder under Plugins in the project view and select the Newtonsoft.Json plugin.

    Newtonsoft-Plug-in auswählen

  5. Stellen Sie sicher, dass die Option für das Plug-inNewtonsoft.Js aktiviert ist, und stellen Sie sicher, dass alle Plattformen deaktiviert sind. Stellen Sie dann sicher, dass der wsaplayerWith the Newtonsoft.Json plugin selected, ensure that Any Platform is unchecked, then ensure that WSAPlayer is also unchecked, then click Apply. Dies dient nur zur Bestätigung, dass die Dateien ordnungsgemäß konfiguriert sind.This is just to confirm that the files are configured correctly.

    Konfigurieren des Newton Soft-Plug-ins

    Hinweis

    Wenn Sie diese Plug-ins markieren, werden Sie nur im Unity-Editor verwendet.Marking these plugins configures them to only be used in the Unity Editor. Im WSA-Ordner gibt es eine andere Gruppe, die verwendet wird, nachdem das Projekt aus Unity exportiert wurde.There are a different set of them in the WSA folder which will be used after the project is exported from Unity.

  6. Als nächstes müssen Sie den Ordner " WSA " im Ordner " newtonsoft " öffnen.Next, you need to open the WSA folder, within the Newtonsoft folder. Es wird eine Kopie derselben Datei angezeigt, die Sie soeben konfiguriert haben.You will see a copy of the same file you just configured. Wählen Sie die Datei aus, und vergewissern Sie sich dann im Inspektor, dassSelect the file, and then in the inspector, ensure that

    • Jede Plattform ist deaktiviert .Any Platform is unchecked
    • nur wsaplayer ist aktiviert .only WSAPlayer is checked
    • "Nicht verarbeiten " ist aktiviertDont process is checked

    Konfigurieren von newtonsoft Plugin Platform-Einstellungen

Kapitel 5: Kamera EinrichtungChapter 5 - Camera setup

  1. Wählen Sie im Bereich Hierarchie die Hauptkamera aus.In the Hierarchy Panel, select the Main Camera.

  2. Nachdem Sie diese Option ausgewählt haben, können Sie alle Komponenten der Hauptkamera im Inspektor-Panel sehen.Once selected, you will be able to see all the components of the Main Camera in the Inspector Panel.

    1. Das Kamera Objekt muss als Hauptkamera benannt werden (Beachten Sie die Schreibweise).The camera object must be named Main Camera (note the spelling!)

    2. Das Hauptkamera Kennzeichen muss auf maincamera festgelegt sein (Beachten Sie die Schreibweise).The Main Camera Tag must be set to MainCamera (note the spelling!)

    3. Stellen Sie sicher, dass die Transformations Position auf 0, 0, 0 festgelegt ist.Make sure the Transform Position is set to 0, 0, 0

    4. Legen Sie klar Flags auf voll Tonfarbe fest (diese Einstellung wird für immersives Headset ignoriert).Set Clear Flags to Solid Color (ignore this for immersive headset).

    5. Legen Sie die Hintergrund Farbe der Kamera Komponente auf schwarz, Alpha 0 (Hexadezimal Code: #00000000) fest (Dies wird für das immersive Headset ignoriert).Set the Background Color of the camera Component to Black, Alpha 0 (Hex Code: #00000000) (ignore this for immersive headset).

    Konfigurieren von Eigenschaften der Kamera Komponente

Kapitel 6: Erstellen der customvisionanalyser-Klasse.Chapter 6 - Create the CustomVisionAnalyser class.

An diesem Punkt können Sie Code schreiben.At this point you are ready to write some code.

Sie beginnen mit der customvisionanalyser -Klasse.You will begin with the CustomVisionAnalyser class.

Hinweis

Die Aufrufe der Custom Vision Service , die im unten gezeigten Code vorgenommen wurden, werden mithilfe der Custom Vision Rest-API vorgenommen.The calls to the Custom Vision Service made in the code shown below are made using the Custom Vision REST API. Durch die Verwendung dieser API sehen Sie, wie Sie diese API implementieren und nutzen können (nützlich, um zu verstehen, wie Sie etwas ähnliches implementieren können).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). Beachten Sie, dass Microsoft ein Custom Vision Service SDK bietet, das auch zum Aufrufen des Dienstanbieter verwendet werden kann.Be aware, that Microsoft offers a Custom Vision Service SDK that can also be used to make calls to the Service. Weitere Informationen finden Sie im Custom Vision Service SDK -Artikel.For more information visit the Custom Vision Service SDK article.

Diese Klasse ist für Folgendes zuständig:This class is responsible for:

  • Das letzte als Bytearray erfasste Bild wird geladen.Loading the latest image captured as an array of bytes.

  • Das Bytearray wird zur Analyse an Ihre Azure Custom Vision Service -Instanz gesendet.Sending the byte array to your Azure Custom Vision Service instance for analysis.

  • Die Antwort wird als JSON-Zeichenfolge empfangen.Receiving the response as a JSON string.

  • Deserialisieren der Antwort und übergeben der resultierenden Vorhersage an die sceneorganisator -Klasse, um die Anzeige der Antwort zu übernehmen.Deserializing the response and passing the resulting Prediction to the SceneOrganiser class, which will take care of how the response should be displayed.

So erstellen Sie diese Klasse:To create this class:

  1. Klicken Sie im Projekt Panel mit der rechten Maustaste in den Ordner Asset , und klicken Sie dann auf > Ordner erstellen.Right-click in the Asset Folder located in the Project Panel, then click Create > Folder. Nennen Sie die Ordner Skripts.Call the folder Scripts.

    Ordner für die Skripterstellung

  2. Doppelklicken Sie auf den soeben erstellten Ordner, um ihn zu öffnen.Double-click on the folder just created, to open it.

  3. Klicken Sie mit der rechten Maustaste in den Ordner , und klicken Sie dann auf > # Skript erstellen.Right-click inside the folder, then click Create > C# Script. Benennen Sie das Skript customvisionanalyser.Name the script CustomVisionAnalyser.

  4. Doppelklicken Sie auf das neue customvisionanalyser -Skript, um es in Visual Studio zu öffnen.Double-click on the new CustomVisionAnalyser script to open it with Visual Studio.

  5. Aktualisieren Sie die Namespaces am Anfang der Datei so, dass Sie den folgenden entsprechen: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. Fügen Sie in der customvisionanalyser -Klasse die folgenden Variablen hinzu: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;
    

    Hinweis

    Stellen Sie sicher, dass Sie den Vorhersage Schlüssel in die " prätionkey "-Variable und den Vorhersage Endpunkt in die " prätionendpoint "-VariableMake sure you insert your Prediction Key into the predictionKey variable and your Prediction Endpoint into the predictionEndpoint variable. Sie haben diese zuvor im Kurs in Notepad kopiert.You copied these to Notepad earlier in the course.

  7. Code für Awa() muss nun hinzugefügt werden, um die Instanzvariable zu initialisieren: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. Löschen Sie die Methoden " Start () " und " Update ()".Delete the methods Start() and Update().

  9. Fügen Sie als nächstes die Coroutine hinzu (mit der statischen getimageasbytearray () -Methode darunter), die die Ergebnisse der Analyse des Bilds erhält, das von der imagecapture -Klasse erfasst wird.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.

    Hinweis

    In der analyseimagecapture -Coroutine gibt es einen Aufrufen der sceneorganisator -Klasse, die Sie noch erstellen müssen.In the AnalyseImageCapture coroutine, there is a call to the SceneOrganiser class that you are yet to create. Deshalb sollten Sie diese Zeilen jetzt kommentiert lassen.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. Stellen Sie sicher, dass Sie die Änderungen in Visual Studio speichern, bevor Sie zu Unity zurückkehren.Be sure to save your changes in Visual Studio before returning to Unity.

Kapitel 7: Erstellen der customvisionobjects-KlasseChapter 7 - Create the CustomVisionObjects class

Die Klasse, die Sie jetzt erstellen, ist die customvisionobjects -Klasse.The class you will create now is the CustomVisionObjects class.

Dieses Skript enthält eine Reihe von Objekten, die von anderen Klassen zum Serialisieren und Deserialisieren der Aufrufe an die Custom Vision Service verwendet werden.This script contains a number of objects used by other classes to serialize and deserialize the calls made to the Custom Vision Service.

Warnung

Beachten Sie, dass Sie den Endpunkt beachten, den die Custom Vision Service bereitstellt, da die folgende JSON-Struktur für die Arbeit mit Custom Vision Vorhersage v 2.0eingerichtet wurde.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. Wenn Sie über eine andere Version verfügen, müssen Sie möglicherweise die folgende Struktur aktualisieren.If you have a different version, you may need to update the below structure.

So erstellen Sie diese Klasse:To create this class:

  1. Klicken Sie mit der rechten Maustaste in den Ordner > # Skripts, und klicken Sie dann auf Skript erstellen.Right-click inside the Scripts folder, then click Create > C# Script. Nennen Sie das Skript customvisionobjects.Call the script CustomVisionObjects.

  2. Doppelklicken Sie auf das neue customvisionobjects -Skript, um es in Visual Studio zu öffnen.Double-click on the new CustomVisionObjects script to open it with Visual Studio.

  3. Fügen Sie am Anfang der Datei die folgenden Namespaces hinzu:Add the following namespaces to the top of the file:

    using System;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Networking;
    
  4. Löschen Sie die Methoden " Start () " und " Update () " in der Klasse " customvisionobjects ". Diese Klasse sollte nun leer sein.Delete the Start() and Update() methods inside the CustomVisionObjects class; this class should now be empty.

  5. Fügen Sie die folgenden Klassen außerhalb der customvisionobjects -Klasse hinzu.Add the following classes outside the CustomVisionObjects class. Diese Objekte werden von der newtonsoft -Bibliothek verwendet, um die Antwortdaten zu serialisieren und zu deserialisieren: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; }
    }
    

Kapitel 8: Erstellen der voicerecognizer-KlasseChapter 8 - Create the VoiceRecognizer class

Diese Klasse erkennt die Spracheingabe des Benutzers.This class will recognize the voice input from the user.

So erstellen Sie diese Klasse:To create this class:

  1. Klicken Sie mit der rechten Maustaste in den Ordner > # Skripts, und klicken Sie dann auf Skript erstellen.Right-click inside the Scripts folder, then click Create > C# Script. Nennen Sie das Skript voicerecognizer.Call the script VoiceRecognizer.

  2. Doppelklicken Sie auf das neue voicerecognizer -Skript, um es in Visual Studio zu öffnen.Double-click on the new VoiceRecognizer script to open it with Visual Studio.

  3. Fügen Sie die folgenden Namespaces oberhalb der voicerecognizer -Klasse hinzu:Add the following namespaces above the VoiceRecognizer class:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.Windows.Speech;
    
  4. Fügen Sie dann die folgenden Variablen in der voicerecognizer -Klasse oberhalb der Start () -Methode hinzu: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. Fügen Sie die Methoden " Awa() " und " Start () " hinzu, bei denen die Benutzer Schlüsselwörter so eingerichtet werden, dass Sie beim Zuordnen eines Tags zu einem Bild erkannt werden: 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. Löschen Sie die Update () -Methode.Delete the Update() method.

  7. Fügen Sie den folgenden Handler hinzu, der immer dann aufgerufen wird, wenn die Spracheingabe erkannt wird: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. Stellen Sie sicher, dass Sie die Änderungen in Visual Studio speichern, bevor Sie zu Unity zurückkehren.Be sure to save your changes in Visual Studio before returning to Unity.

Hinweis

Machen Sie sich keine Sorgen um Code, der möglicherweise einen Fehler enthält, da Sie bald weitere Klassen bereitstellen werden, die diese beheben.Do not worry about code which might appear to have an error, as you will provide further classes soon, which will fix these.

Kapitel 9: Erstellen der customvisiontrainer-KlasseChapter 9 - Create the CustomVisionTrainer class

Diese Klasse verkettet eine Reihe von webaufrufen, um die Custom Vision Service zu trainieren.This class will chain a series of web calls to train the Custom Vision Service. Jeder-Befehl wird direkt oberhalb des Codes ausführlich erläutert.Each call will be explained in detail right above the code.

So erstellen Sie diese Klasse:To create this class:

  1. Klicken Sie mit der rechten Maustaste in den Ordner > # Skripts, und klicken Sie dann auf Skript erstellen.Right-click inside the Scripts folder, then click Create > C# Script. Nennen Sie das Skript customvisiontrainer.Call the script CustomVisionTrainer.

  2. Doppelklicken Sie auf das neue customvisiontrainer -Skript, um es in Visual Studio zu öffnen.Double-click on the new CustomVisionTrainer script to open it with Visual Studio.

  3. Fügen Sie die folgenden Namespaces oberhalb der customvisiontrainer -Klasse hinzu: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. Fügen Sie dann die folgenden Variablen in der customvisiontrainer -Klasse oberhalb der Start () -Methode hinzu.Then add the following variables inside the CustomVisionTrainer class, above the Start() method.

    Hinweis

    Die hier verwendete Schulungs-URL wird in der Dokumentation zum Custom Vision Training 1,2 bereitgestellt und hat eine Struktur von: 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}/
    Weitere Informationen finden Sie in der Referenz-API zu Custom Vision Training v 1.2.For more information, visit the Custom Vision Training v1.2 reference API.

    Warnung

    Beachten Sie, dass Sie den Endpunkt beachten, den der Custom Vision Service für den Trainingsmodus bereitstellt, da die JSON-Struktur (innerhalb der customvisionobjects -Klasse) für die Arbeit mit Custom Vision Training v 1.2eingerichtet wurde.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. Wenn Sie über eine andere Version verfügen, müssen Sie möglicherweise die Struktur der Objekte aktualisieren.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;
    

    Wichtig

    Stellen Sie sicher, dass Sie den Wert für den Dienst Schlüssel (Trainings Schlüssel) und den Projekt-ID -Wert hinzufügen, den Sie zuvor notiert haben. Dies sind die Werte, die Sie zuvor im Portal im Kurs erfasst haben (Kapitel 2, Schritt 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. Fügen Sie die folgenden Methoden " Start () " und " Awa() " hinzu.Add the following Start() and Awake() methods. Diese Methoden werden bei der Initialisierung aufgerufen und enthalten den Aufruf, um die Benutzeroberfläche einzurichten: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. Löschen Sie die Update () -Methode.Delete the Update() method. Diese Klasse wird nicht benötigt.This class will not need it.

  7. Fügen Sie die requesttagselection () -Methode hinzu.Add the RequestTagSelection() method. Diese Methode ist die erste, die aufgerufen wird, wenn ein Abbild aufgezeichnet und auf dem Gerät gespeichert wird. es kann nun an die Custom Vision Service übermittelt werden, um es zu trainieren.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. Diese Methode zeigt in der Trainings Benutzeroberfläche eine Reihe von Schlüsselwörtern an, mit denen der Benutzer das erfasste Bild markieren kann.This method displays, in the training UI, a set of keywords the user can use to tag the image that has been captured. Außerdem wird die voicerecognizer -Klasse darauf aufmerksam, dass Sie mit dem lauschen an den Benutzer für die Spracheingabe beginnt.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. Fügen Sie die verifytag () -Methode hinzu.Add the VerifyTag() method. Diese Methode empfängt die von der voicerecognizer -Klasse erkannte Spracheingabe und überprüft deren Gültigkeit und beginnt dann mit dem Trainings Vorgang.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. Fügen Sie die subentschärmagefortraining () -Methode hinzu.Add the SubmitImageForTraining() method. Mit dieser Methode wird der Custom Vision Service trainingprozess gestartet.This method will begin the Custom Vision Service training process. Der erste Schritt besteht darin, die Tag-ID aus dem Dienst abzurufen, der der überprüften Spracheingabe des Benutzers zugeordnet ist.The first step is to retrieve the Tag Id from the Service which is associated with the validated speech input from the user. Die Tag-ID wird dann zusammen mit dem Bild hochgeladen.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. Fügen Sie die Methode traincustomvisionproject () hinzu.Add the TrainCustomVisionProject() method. Nachdem das Bild übermittelt und markiert wurde, wird diese Methode aufgerufen.Once the image has been submitted and tagged, this method will be called. Es wird eine neue Iterations Vorlage erstellt, die mit allen vorherigen Bildern, die an den Dienst gesendet werden, sowie dem soeben hochgeladenen Image trainiert wird.It will create a new Iteration that will be trained with all the previous images submitted to the Service plus the image just uploaded. Nachdem das Training abgeschlossen ist, ruft diese Methode eine Methode auf, um die neu erstellte iterations Eigenschaft als Standard festzulegen, sodass der Endpunkt, den Sie für die Analyse verwenden, die letzte trainierte Iterations Methode ist.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. Fügen Sie die setdefaultiterations () -Methode hinzu.Add the SetDefaultIteration() method. Mit dieser Methode wird die zuvor erstellte und trainierte Iterations Methode als Standard festgelegt.This method will set the previously created and trained iteration as Default. Nachdem dieser Vorgang abgeschlossen ist, muss diese Methode die vorherige Iterationen löschen, die im Dienst vorhanden sind.Once completed, this method will have to delete the previous iteration existing in the Service. Zum Zeitpunkt der Erstellung dieses Kurses gibt es eine Beschränkung von maximal zehn (10) Iterationen, die gleichzeitig im Dienst vorhanden sein dürfen.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. Fügen Sie die deletepreviousiterations () -Methode hinzu.Add the DeletePreviousIteration() method. Diese Methode findet und löscht die vorherige nicht standardmäßige Iterationen: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. Die letzte Methode, die dieser Klasse hinzugefügt werden soll, ist die getimageasbytearray () -Methode, die für die Webaufrufe verwendet wird, um das in ein Bytearray erfasste Bild zu konvertieren.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. Stellen Sie sicher, dass Sie die Änderungen in Visual Studio speichern, bevor Sie zu Unity zurückkehren.Be sure to save your changes in Visual Studio before returning to Unity.

Kapitel 10: Erstellen der sceneorganisator-KlasseChapter 10 - Create the SceneOrganiser class

Diese Klasse führt Folgendes aus:This class will:

  • Erstellen Sie ein Cursor Objekt, das an die Hauptkamera angehängt werden soll.Create a Cursor object to attach to the Main Camera.

  • Erstellen Sie ein Bezeichnungs Objekt, das angezeigt wird, wenn der Dienst die Objekte der realen Welt erkennt.Create a Label object that will appear when the Service recognizes the real-world objects.

  • Richten Sie die Hauptkamera ein, indem Sie die entsprechenden Komponenten an Sie anfügen.Set up the Main Camera by attaching the appropriate components to it.

  • Wenn Sie sich im Analysemodus befinden, können Sie die Bezeichnungen zur Laufzeit im entsprechenden Raum relativ zur Position der Hauptkamera erzeugen und die vom Custom Vision Service empfangenen Daten anzeigen.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.

  • Erzeugen Sie im Trainingsmodus die Benutzeroberfläche, auf der die verschiedenen Phasen des Trainingsprozesses angezeigt werden.When in Training Mode, spawn the UI that will display the different stages of the training process.

So erstellen Sie diese Klasse:To create this class:

  1. Klicken Sie mit der rechten Maustaste in den Ordner > # Skripts, und klicken Sie dann auf Skript erstellen.Right-click inside the Scripts folder, then click Create > C# Script. Nennen Sie das Skript sceneorganisator.Name the script SceneOrganiser.

  2. Doppelklicken Sie auf das neue sceneorganisator -Skript, um es in Visual Studio zu öffnen.Double-click on the new SceneOrganiser script to open it with Visual Studio.

  3. Sie benötigen nur einen Namespace, und entfernen Sie die anderen aus der sceneorganisator -Klasse:You will only need one namespace, remove the others from above the SceneOrganiser class:

    using UnityEngine;
    
  4. Fügen Sie dann die folgenden Variablen in der sceneorganisator -Klasse oberhalb der Start () -Methode hinzu: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. Löschen Sie die Methoden " Start () " und " Update () ".Delete the Start() and Update() methods.

  6. Fügen Sie direkt unterhalb der Variablen die Awa() -Methode hinzu, die die Klasse initialisiert und die Szene einrichtet.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. Fügen Sie nun die Methode " samatecameracursor () " hinzu, die den Hauptkamera Cursor erstellt und positioniert, sowie die Methode "Methode () ", die das Objekt " Analyse Bezeichnung " erstellt.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. Fügen Sie die setcamerastatus () -Methode hinzu, die Nachrichten verarbeitet, die für das textnetz vorgesehen sind, das den Status der Kamera bereitstellt.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. Fügen Sie die Methoden placeanalysislabel () und settagstolastlabel () hinzu, die die Daten der Custom Vision Service in der Szene erzeugen und anzeigen.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. Fügen Sie abschließend die Methode " itatetrainingui () " hinzu, die die Benutzeroberfläche erzeugt, die die verschiedenen Phasen des Trainingsprozesses anzeigt, wenn sich die Anwendung im Trainingsmodus befindet.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. Diese Methode wird auch zum Erstellen des Kamera Status Objekts verwendet.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. Stellen Sie sicher, dass Sie die Änderungen in Visual Studio speichern, bevor Sie zu Unity zurückkehren.Be sure to save your changes in Visual Studio before returning to Unity.

Wichtig

Bevor Sie fortfahren, öffnen Sie die customvisionanalyser -Klasse, und heben Sie die Auskommentierung der folgenden Zeilen innerhalb der analyselastimageaufgezeichnet () -Methode auf: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);

Kapitel 11: Erstellen der imagecapture-KlasseChapter 11 - Create the ImageCapture class

Die nächste Klasse, die Sie erstellen, ist die imagecapture -Klasse.The next class you are going to create is the ImageCapture class.

Diese Klasse ist für Folgendes zuständig:This class is responsible for:

  • Erfassen eines Bilds mithilfe der hololens-Kamera und speichern im App -Ordner.Capturing an image using the HoloLens camera and storing it in the App Folder.

  • Behandlung von TAP-Gesten vom Benutzer.Handling Tap gestures from the user.

  • Beibehalten des Enumerationswerts, der bestimmt , ob die Anwendung im Analyse Modus oder im Trainings Modus ausgeführt wird.Maintaining the Enum value that determines if the application will run in Analysis mode or Training Mode.

So erstellen Sie diese Klasse:To create this class:

  1. Wechseln Sie zum Ordner " Scripts ", den Sie zuvor erstellt haben.Go to the Scripts folder you created previously.

  2. Klicken Sie mit der rechten Maustaste in den Ordner, und klicken Sie dann auf Create > C # Script.Right-click inside the folder, then click Create > C# Script. Benennen Sie das Skript mit imagecapture.Name the script ImageCapture.

  3. Doppelklicken Sie auf das neue imagecapture -Skript, um es in Visual Studio zu öffnen.Double-click on the new ImageCapture script to open it with Visual Studio.

  4. Ersetzen Sie die Namespaces am Anfang der Datei durch Folgendes: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. Fügen Sie dann die folgenden Variablen in der imagecapture -Klasse oberhalb der Start () -Methode hinzu: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. Der Code für die Methoden " Awake () " und " Start () " muss nun hinzugefügt werden: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. Implementieren Sie einen Handler, der aufgerufen wird, wenn eine Tap-Geste auftritt.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;
            }     
        }
    

    Hinweis

    Im Analyse Modus fungiert die taphandler -Methode als Switch zum Starten oder Abbrechen der Foto Erfassungs Schleife.In Analysis mode, the TapHandler method acts as a switch to start or stop the photo capture loop.

    Im Trainings Modus wird ein Bild von der Kamera aufgezeichnet.In Training mode, it will capture an image from the camera.

    Wenn der Cursor grün ist, bedeutet dies, dass die Kamera verfügbar ist, um das Bild zu übernehmen.When the cursor is green, it means the camera is available to take the image.

    Wenn der Cursor rot ist, bedeutet dies, dass die Kamera ausgelastet ist.When the cursor is red, it means the camera is busy.

  8. Fügen Sie die Methode hinzu, die die Anwendung verwendet, um den Bild Aufzeichnungsprozess zu starten und das Bild zu speichern.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. Fügen Sie die Handler hinzu, die aufgerufen werden, wenn das Foto aufgezeichnet wurde und für die Analyse bereit ist.Add the handlers that will be called when the photo has been captured and for when it is ready to be analyzed. Das Ergebnis wird dann in Abhängigkeit vom Modus, für den der Code festgelegt ist, an customvisionanalyser oder customvisiontrainer weitergeleitet.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. Stellen Sie sicher, dass Sie die Änderungen in Visual Studio speichern, bevor Sie zu Unity zurückkehren.Be sure to save your changes in Visual Studio before returning to Unity.

  11. Nachdem alle Skripts abgeschlossen sind, wechseln Sie zurück zum Unity-Editor, und klicken Sie dann auf die Klasse sceneorganisator aus dem Ordner Scripts auf das Hauptkamera Objekt im Bereich Hierarchie.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.

Kapitel 12: vor dem AufbauChapter 12 - Before building

Um eine gründliche Test Ihrer Anwendung durchzuführen, müssen Sie Sie auf Ihre hololens querladen.To perform a thorough test of your application you will need to sideload it onto your HoloLens.

Bevor Sie vorgehen, stellen Sie Folgendes sicher:Before you do, ensure that:

  • Alle in Kapitel 2 erwähnten Einstellungen sind richtig festgelegt.All the settings mentioned in the Chapter 2 are set correctly.

  • Alle Felder in der Hauptkamera, Inspektor Panel, sind ordnungsgemäß zugewiesen.All the fields in the Main Camera, Inspector Panel, are assigned properly.

  • Das Skript sceneorganisator ist an das Hauptkamera Objekt angefügt.The script SceneOrganiser is attached to the Main Camera object.

  • Stellen Sie sicher, dass Sie den Vorhersage Schlüssel in die Variable " vorhersag Schlüssel " einfügen.Make sure you insert your Prediction Key into the predictionKey variable.

  • Sie haben den Vorhersage Endpunkt in die " prätionendpoint "-Variable eingefügt.You have inserted your Prediction Endpoint into the predictionEndpoint variable.

  • Sie haben ihren Trainings Schlüssel in die Variable " trainingkey " der Klasse " customvisiontrainer " eingefügt.You have inserted your Training Key into the trainingKey variable, of the CustomVisionTrainer class.

  • Sie haben Ihre Projekt-ID in die ProjectId -Variable der customvisiontrainer -Klasse eingefügt.You have inserted your Project ID into the projectId variable, of the CustomVisionTrainer class.

Kapitel 13: Erstellen und querladen der AnwendungChapter 13 - Build and sideload your application

So beginnen Sie den Buildprozess:To begin the Build process:

  1. Wechseln Sie zu Datei > Buildeinstellungen.Go to File > Build Settings.

  2. Teil Strich Unity-C- # Projekte.Tick Unity C# Projects.

  3. Klicken Sie auf Erstellen.Click Build. Unity startet ein Datei-Explorer -Fenster, in dem Sie einen Ordner erstellen und auswählen müssen, in dem die App erstellt wird.Unity will launch a File Explorer window, where you need to create and then select a folder to build the app into. Erstellen Sie diesen Ordner jetzt, und nennen Sie ihn " App".Create that folder now, and name it App. Klicken Sie dann mit ausgewähltem App -Ordner auf Ordner auswählen.Then with the App folder selected, click on Select Folder.

  4. Unity startet das Projekt in den App -Ordner.Unity will begin building your project to the App folder.

  5. Nachdem die Erstellung von Unity abgeschlossen ist (Dies kann einige Zeit in Anspruch nehmen), wird ein Datei-Explorer -Fenster am Speicherort des Builds geöffnet (überprüfen Sie die Taskleiste, da Sie möglicherweise nicht immer über Ihrem Fenster angezeigt wird, sondern Sie über das Hinzufügen eines neuen Fensters benachrichtigt).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).

So stellen Sie auf hololens bereit:To deploy on HoloLens:

  1. Sie benötigen die IP-Adresse Ihrer hololens (für die Remote Bereitstellung) und, um sicherzustellen, dass sich Ihre hololens im Entwicklermodus befinden.You will need the IP Address of your HoloLens (for Remote Deploy), and to ensure your HoloLens is in Developer Mode. Gehen Sie dazu wie folgt vor:To do this:

    1. Öffnen Sie die Einstellungen, während Sie die hololens- Einstellungen durch tragen.Whilst wearing your HoloLens, open the Settings.

    2. Navigieren Sie zu Netzwerk & > Erweiterte Wi-Fi- > Optionen für das Internet.Go to Network & Internet > Wi-Fi > Advanced Options

    3. Notieren Sie sich die IPv4 -Adresse.Note the IPv4 address.

    4. Navigieren Sie als nächstes wieder zu Einstellungen, und aktualisieren Sie die & Sicherheit > für Entwickler .Next, navigate back to Settings, and then to Update & Security > For Developers

    5. Legen Sie den Entwicklermodus auf fest.Set Developer Mode On.

  2. Navigieren Sie zu Ihrem neuen Unity-Build ( App -Ordner), und öffnen Sie die Projektmappendatei mit Visual Studio.Navigate to your new Unity build (the App folder) and open the solution file with Visual Studio.

  3. Wählen Sie in der Projektmappenkonfiguration Debuggen.In the Solution Configuration select Debug.

  4. Wählen Sie auf der Projektmappenplattform die Option x86, Remote Computer aus.In the Solution Platform, select x86, Remote Machine. Sie werden aufgefordert, die IP-Adresse eines Remote Geräts (in diesem Fall die hololens) einzufügen, die Sie notiert haben.You will be prompted to insert the IP address of a remote device (the HoloLens, in this case, which you noted).

    Festlegen der IP-Adresse

  5. Wechseln Sie zum Menü Erstellen , und klicken Sie auf Lösung bereitstellen, um die Anwendung auf die hololens quer zuladen.Go to Build menu and click on Deploy Solution to sideload the application to your HoloLens.

  6. Ihre APP sollte nun in der Liste der installierten apps auf Ihren hololens angezeigt werden, die bereit sind, gestartet zu werden.Your app should now appear in the list of installed apps on your HoloLens, ready to be launched!

Hinweis

Legen Sie für die Bereitstellung auf dem immersiven Headset die Projektmappenplattform auf lokaler Computer fest, und legen Sie die Konfiguration auf Debuggen und x86 als Plattform fest.To deploy to immersive headset, set the Solution Platform to Local Machine, and set the Configuration to Debug, with x86 as the Platform. Stellen Sie dann auf dem lokalen Computer bereit, und wählen Sie dann Projekt Mappe bereitstellen aus.Then deploy to the local machine, using the Build menu item, selecting Deploy Solution.

So verwenden Sie die Anwendung:To use the application:

Um die APP-Funktionalität zwischen Trainings Modus und Vorhersage Modus zu wechseln, müssen Sie die appmode -Variable aktualisieren, die sich in der " Awa() "-Methode innerhalb der imagecapture -Klasse befindet.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;

oderor

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

Im Trainings Modus:In Training mode:

  • Sehen Sie sich Maus oder Tastatur an, und verwenden Sie die Tap-Geste.Look at Mouse or Keyboard and use the Tap gesture.

  • Als nächstes wird Text angezeigt, in dem Sie aufgefordert werden, ein Tag anzugeben.Next, text will appear asking you to provide a tag.

  • Sagen Sie entweder Maus oder Tastatur.Say either Mouse or Keyboard.

Im Vorhersage Modus:In Prediction mode:

  • Betrachten Sie ein Objekt, und verwenden Sie die Tap-Geste.Look at an object and use the Tap gesture.

  • Es wird Text angezeigt, der das erkannte Objekt mit der höchsten Wahrscheinlichkeit (normalisiert) bereitstellt.Text will appear providing the object detected, with the highest probability (this is normalized).

Kapitel 14: auswerten und verbessern des Custom Vision ModellsChapter 14 - Evaluate and improve your Custom Vision model

Um den Dienst genauer zu gestalten, müssen Sie das Modell, das für die Vorhersage verwendet wird, weiter trainieren.To make your Service more accurate, you will need to continue to train the model used for prediction. Dies erfolgt über die Verwendung der neuen Anwendung mit den Trainings -und Vorhersage Modi, bei denen letztere das Portal besuchen muss, was in diesem Kapitel behandelt wird.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. Bereiten Sie Ihr Portal mehrmals vor, um das Modell kontinuierlich zu verbessern.Be prepared to revisit your portal many times, to continually improve your model.

  1. Wechseln Sie erneut in Ihr Azure Custom Vision-Portal, und wählen Sie die Registerkarte Vorhersagen aus, sobald Sie in Ihrem Projekt sind (in der oberen Mitte der Seite):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):

    Registerkarte "Prognosen"

  2. Alle Images, die während der Ausführung Ihrer Anwendung an den Dienst gesendet wurden, werden angezeigt.You will see all the images which were sent to your Service whilst your application was running. Wenn Sie mit dem Mauszeiger auf die Bilder zeigen, erhalten Sie die Vorhersagen, die für das Image erstellt wurden:If you hover over the images, they will provide you with the predictions that were made for that image:

    Liste der Vorhersage Images

  3. Wählen Sie eines der Images aus, um es zu öffnen.Select one of your images to open it. Sobald das Bild geöffnet ist, werden die Vorhersagen für dieses Bild auf der rechten Seite angezeigt.Once open, you will see the predictions made for that image to the right. Wenn die Vorhersagen richtig waren und Sie dieses Bild dem Schulungs Modell Ihres dienstanders hinzufügen möchten, klicken Sie auf das Eingabefeld " Meine Tags ", und wählen Sie das Tag aus, das Sie zuordnen möchten.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. Wenn Sie fertig sind, klicken Sie unten rechts auf die Schaltfläche Speichern und schließen , und fahren Sie mit dem nächsten Bild fort.When you are finished, click the Save and close button to the bottom right, and continue on to the next image.

    Zu öffnende Bild auswählen

  4. Wenn Sie wieder zum Bild Raster zurückkehren, werden Sie feststellen, dass die Bilder, denen Sie Tags hinzugefügt haben (und gespeichert), entfernt werden.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. Wenn Sie Bilder suchen, für die Sie nicht über das markierte Element verfügen, können Sie Sie löschen, indem Sie auf den Tick dieses Bilds klicken (kann dies für mehrere Bilder tun) und dann in der oberen rechten Ecke der Raster Seite auf Löschen klicken.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. Im folgenden Popup Fenster können Sie auf Ja, löschen oder Nein klicken, um den Löschvorgang zu bestätigen bzw. abzubrechen.On the popup that follows, you can click either Yes, delete or No, to confirm the deletion or cancel it, respectively.

    Löschen von Images

  5. Wenn Sie den Vorgang fortsetzen möchten, klicken Sie oben rechts auf die grüne Schaltfläche " Train ".When you are ready to proceed, click the green Train button in the top right. Ihr Dienstmodell wird mit allen Images trainiert, die Sie jetzt bereitgestellt haben (wodurch es präziser wird).Your Service model will be trained with all the images which you have now provided (which will make it more accurate). Wenn das Training vollständig ist, klicken Sie erneut auf die Schaltfläche Standard erstellen , damit Ihre Vorhersage-URL weiterhin die aktuellste Iterationen des Dienes verwendet.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.

    Schulungsdienst Modell starten  Select Default-OptionStart training service model Select make default option

Ihre fertiggestellte Custom Vision-API-AnwendungYour finished Custom Vision API application

Herzlichen Glückwunsch, Sie haben eine Mixed Reality-App erstellt, die die Azure-Custom Vision-API nutzt, um reale Objekte zu erkennen, das Dienstmodell zu trainieren und sich über das gesehene Vertrauen zu zeigen.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.

Beispiel für ein fertiges Projekt

ZusatzübungenBonus exercises

Übung 1Exercise 1

Trainieren Sie Ihre Custom Vision Service , um weitere Objekte zu erkennen.Train your Custom Vision Service to recognize more objects.

Übung 2Exercise 2

Um zu erfahren, was Sie gelernt haben, führen Sie die folgenden Übungen aus:As a way to expand on what you have learned, complete the following exercises:

Spielen Sie einen Sound wieder, wenn ein Objekt erkannt wird.Play a sound when an object is recognized.

Übung 3Exercise 3

Verwenden Sie die API zum erneuten trainieren Ihres diensmit denselben Images, die von Ihrer APP analysiert werden, um den Dienst genauer zu gestalten (führen Sie sowohl Vorhersagen als auch Schulungen gleichzeitig aus).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).