Réalité mixte - Azure - Cours 302b : Vision personnaliséeMR and Azure 302b: Custom vision


Notes

Les tutoriels Mixed Reality Academy ont été conçus pour les appareils HoloLens (1re génération) et les casques immersifs de réalité mixte.The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. Nous estimons qu’il est important de laisser ces tutoriels à la disposition des développeurs qui recherchent encore des conseils pour développer des applications sur ces appareils.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. Notez que ces tutoriels ne sont pas mis à jour avec les derniers ensembles d’outils ou interactions utilisés pour HoloLens 2.These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. Ils sont fournis dans le but de fonctionner sur les appareils pris en charge.They will be maintained to continue working on the supported devices. Une nouvelle série de didacticiels sera publiée à l’avenir qui vous montrera comment développer pour HoloLens 2.There will be a new series of tutorials that will be posted in the future that will demonstrate how to develop for HoloLens 2. Cet avis sera mis à jour avec un lien vers ces didacticiels lors de leur publication.This notice will be updated with a link to those tutorials when they are posted.


Dans ce cours, vous allez apprendre à reconnaître du contenu visuel personnalisé dans une image fournie, à l’aide des fonctionnalités d’Azure Custom Vision dans une application de réalité mixte.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.

Ce service vous permet d’effectuer l’apprentissage d’un modèle de Machine Learning à l’aide d’images d’objet.This service will allow you to train a machine learning model using object images. Vous utiliserez ensuite le modèle formé pour reconnaître des objets similaires, fournis par la capture de l’appareil photo de Microsoft HoloLens ou un appareil photo connecté à votre PC pour les casques immersifs (VR).You will then use the trained model to recognize similar objects, as provided by the camera capture of Microsoft HoloLens or a camera connected to your PC for immersive (VR) headsets.

résultat du cours

Azure Custom Vision est un service cognitive de Microsoft qui permet aux développeurs de créer des classifieurs d’images personnalisées.Azure Custom Vision is a Microsoft Cognitive Service which allows developers to build custom image classifiers. Ces classifieurs peuvent ensuite être utilisés avec de nouvelles images pour reconnaître, ou classer, des objets dans cette nouvelle image.These classifiers can then be used with new images to recognize, or classify, objects within that new image. Le service fournit un portail en ligne simple et facile à utiliser pour simplifier le processus.The Service provides a simple, easy to use, online portal to streamline the process. Pour plus d’informations, consultez la page service vision personnalisée Azure.For more information, visit the Azure Custom Vision Service page.

À la fin de ce cours, vous disposerez d’une application de réalité mixte qui pourra fonctionner en deux modes :Upon completion of this course, you will have a mixed reality application which will be able to work in two modes:

  • Mode d’analyse: configuration manuelle du service vision personnalisée en chargeant des images, en créant des balises et en formant une formation au service pour reconnaître différents objets (dans ce cas, la souris et le clavier).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). Vous allez ensuite créer une application HoloLens qui capturera les images à l’aide de l’appareil photo et essayez de reconnaître ces objets dans le monde réel.You will then create a HoloLens app that will capture images using the camera, and try to recognize those objects in the real world.

  • Mode d’apprentissage: vous allez implémenter le code qui activera un « mode d’apprentissage » dans votre application.Training Mode: you will implement code that will enable a "Training Mode" in your app. Le mode d’apprentissage vous permet de capturer des images à l’aide de l’appareil photo HoloLens, de charger les images capturées dans le service et d’effectuer l’apprentissage du modèle de vision personnalisée.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.

Ce cours vous apprend à obtenir les résultats de la Service Vision personnalisée dans un exemple d’application basée sur Unity.This course will teach you how to get the results from the Custom Vision Service into a Unity-based sample application. Il vous faudra appliquer ces concepts à une application personnalisée que vous pouvez générer.It will be up to you to apply these concepts to a custom application you might be building.

Prise en charge des appareilsDevice support

CoursCourse HoloLensHoloLens Casques immersifsImmersive headsets
Réalité mixte - Azure - Cours 302b : Vision personnaliséeMR and Azure 302b: Custom vision ✔️✔️ ✔️✔️

Notes

Bien que ce cours se concentre principalement sur HoloLens, vous pouvez également appliquer ce que vous allez apprendre dans ce cours à des casques pour Windows Mixed Reality (VR).While this course primarily focuses on HoloLens, you can also apply what you learn in this course to Windows Mixed Reality immersive (VR) headsets. Étant donné que les casques immersifs ne disposent pas de caméras accessibles, vous aurez besoin d’une caméra externe connectée à votre PC.Because immersive (VR) headsets do not have accessible cameras, you will need an external camera connected to your PC. À mesure que vous suivez le cours, vous verrez des remarques sur les modifications que vous devrez peut-être utiliser pour prendre en charge les écouteurs immersifs (VR).As you follow along with the course, you will see notes on any changes you might need to employ to support immersive (VR) headsets.

PrérequisPrerequisites

Notes

Ce didacticiel est conçu pour les développeurs qui ont une expérience de base avec Unity et C#.This tutorial is designed for developers who have basic experience with Unity and C#. Sachez également que les conditions préalables et les instructions écrites dans ce document représentent les éléments qui ont été testés et vérifiés au moment de la rédaction (juillet 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). Vous êtes libre d’utiliser le logiciel le plus récent, tel qu’indiqué dans l’article installer les outils , bien qu’il ne soit pas supposé que les informations de ce cours correspondent parfaitement à ce que vous trouverez dans les logiciels plus récents que ceux répertoriés ci-dessous.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.

Nous vous recommandons d’utiliser le matériel et les logiciels suivants pour ce cours :We recommend the following hardware and software for this course:

Avant de commencerBefore you start

  1. Pour éviter de rencontrer des problèmes lors de la création de ce projet, il est fortement recommandé de créer le projet mentionné dans ce didacticiel dans un dossier racine ou dans un dossier racine (les chemins de dossiers longs peuvent entraîner des problèmes au moment de la génération).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. Configurez et testez votre HoloLens.Set up and test your HoloLens. Si vous avez besoin de la prise en charge de la configuration de votre HoloLens, consultez l’article Configuration de hololens.If you need support setting up your HoloLens, make sure to visit the HoloLens setup article.
  3. Il est judicieux d’effectuer un réglage de l’étalonnage et du capteur au début du développement d’une nouvelle application HoloLens (parfois, il peut être utile d’effectuer ces tâches pour chaque utilisateur).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).

Pour obtenir de l’aide sur l’étalonnage, veuillez suivre ce lien vers l’article d’étalonnage HoloLens.For help on Calibration, please follow this link to the HoloLens Calibration article.

Pour obtenir de l’aide sur le réglage du capteur, veuillez suivre ce lien vers l’article sur le paramétrage du capteur HoloLens.For help on Sensor Tuning, please follow this link to the HoloLens Sensor Tuning article.

Chapitre 1-portail Service Vision personnaliséeChapter 1 - The Custom Vision Service Portal

Pour utiliser le service vision personnalisée dans Azure, vous devez configurer une instance du service qui sera mise à la disposition de votre application.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. Tout d’abord, accédez à la page principale service vision personnalisée.First, navigate to the Custom Vision Service main page.

  2. Cliquez sur le bouton prise en main .Click on the Get Started button.

    Prise en main de Service Vision personnalisée

  3. Connectez-vous au portail service vision personnalisée .Sign in to the Custom Vision Service Portal.

    Se connecter au portail

    Notes

    Si vous n’avez pas encore de compte Azure, vous devez en créer un.If you do not already have an Azure account, you will need to create one. Si vous suivez ce didacticiel dans une situation de classe ou de laboratoire, demandez à votre formateur ou à l’un des prostructors de vous aider à configurer votre nouveau compte.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. Une fois que vous êtes connecté pour la première fois, vous êtes invité à entrer dans le panneau des conditions d’accès .Once you are logged in for the first time, you will be prompted with the Terms of Service panel. Cliquez sur la case à cocher pour accepter les termes du contrat.Click on the checkbox to agree to the terms. Cliquez ensuite sur J’accepte.Then click on I agree.

    Conditions d'utilisation

  5. Une fois les conditions accordées, vous accédez à la section projets du portail.Having agreed to the Terms, you will be navigated to the Projects section of the Portal. Cliquez sur nouveau projet.Click on New Project.

    Création d’un projet

  6. Un onglet s’affiche sur le côté droit, ce qui vous invite à spécifier certains champs pour le projet.A tab will appear on the right-hand side, which will prompt you to specify some fields for the project.

    1. Insérez un nom pour votre projet.Insert a Name for your project.

    2. Insérez une Description de votre projet (facultatif).Insert a Description for your project (optional).

    3. Choisissez un groupe de ressources ou créez-en un.Choose a Resource Group or create a new one. Un groupe de ressources permet de surveiller, de contrôler l’accès, de configurer et de gérer la facturation d’un regroupement de ressources Azure.A resource group provides a way to monitor, control access, provision and manage billing for a collection of Azure assets. Il est recommandé de conserver tous les services Azure associés à un seul projet (par exemple, ces cours) dans un groupe de ressources commun.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. Définir les types de projets sur classificationSet the Project Types to Classification

    5. Définissez les domaines comme étant généraux.Set the Domains as General.

      Définir les domaines

      Si vous souhaitez en savoir plus sur les groupes de ressources Azure, consultez l’article du groupe de ressources.If you wish to read more about Azure Resource Groups, please visit the resource group article.

  7. Une fois que vous avez terminé, cliquez sur créer un projet, vous serez redirigé vers la page service vision personnalisée, projet.Once you are finished, click on Create project, you will be redirected to the Custom Vision Service, project page.

Chapitre 2-formation de votre projet Custom VisionChapter 2 - Training your Custom Vision project

Une fois dans le portail Custom Vision, votre objectif principal est de former votre projet à la reconnaissance d’objets spécifiques dans les images.Once in the Custom Vision portal, your primary objective is to train your project to recognize specific objects in images. Vous avez besoin d’au moins cinq (5) images, même si dix (10) sont préférables pour chaque objet que vous souhaitez que votre application reconnaisse.You need at least five (5) images, though ten (10) is preferred, for each object that you would like your application to recognize. Vous pouvez utiliser les images fournies dans ce cours (une souris d’ordinateur et un clavier).You can use the images provided with this course (a computer mouse and a keyboard).

Pour former votre projet Service Vision personnalisée :To train your Custom Vision Service project:

  1. Cliquez sur le + bouton en regard de balises.Click on the + button next to Tags.

    Ajouter une balise

  2. Ajoutez le nom de l’objet que vous souhaitez reconnaître.Add the name of the object you would like to recognize. Cliquez sur Save(Enregistrer).Click on Save.

    Ajouter un nom d’objet et enregistrer

  3. Vous remarquerez que votre balise a été ajoutée (vous devrez peut-être recharger votre page pour qu’elle apparaisse).You will notice your Tag has been added (you may need to reload your page for it to appear). Cliquez sur la case à cocher en regard de votre nouvelle balise, si elle n’est pas déjà activée.Click the checkbox alongside your new tag, if it is not already checked.

    Activer la nouvelle balise

  4. Cliquez sur Ajouter des images au centre de la page.Click on Add Images in the center of the page.

    Ajouter des images

  5. Cliquez sur Parcourir les fichiers locaux et recherchez, puis sélectionnez les images que vous souhaitez télécharger, avec un minimum de cinq (5).Click on Browse local files, and search, then select, the images you would like to upload, with the minimum being five (5). N’oubliez pas que toutes ces images doivent contenir l’objet que vous êtes en train de former.Remember all of these images should contain the object which you are training.

    Notes

    Vous pouvez sélectionner plusieurs images à la fois, à télécharger.You can select several images at a time, to upload.

  6. Une fois que vous pouvez voir les images dans l’onglet, sélectionnez la balise appropriée dans la zone mes balises .Once you can see the images in the tab, select the appropriate tag in the My Tags box.

    Sélectionner des balises

  7. Cliquez sur charger les fichiers.Click on Upload files. Le chargement des fichiers va commencer.The files will begin uploading. Une fois que vous avez confirmé le téléchargement, cliquez sur terminé.Once you have confirmation of the upload, click Done.

    Charger des fichiers

  8. Répétez le même processus pour créer une nouvelle balise nommée Keyboard et chargez les photos appropriées pour celle-ci.Repeat the same process to create a new Tag named Keyboard and upload the appropriate photos for it. Veillez à ne pas vérifier la souris une fois que vous avez créé les nouvelles balises, afin d’afficher la fenêtre Ajouter des images .Make sure to uncheck Mouse once you have created the new tags, so to show the Add images window.

  9. Une fois que les deux balises sont configurées, cliquez sur train, et la première itération d’apprentissage commencera la génération.Once you have both Tags set up, click on Train, and the first training iteration will start building.

    Activer l’itération d’apprentissage

  10. Une fois qu’elle est créée, vous pouvez voir deux boutons nommés créer par défaut et URL de prédiction.Once it's built, you'll be able to see two buttons called Make default and Prediction URL. Cliquez d’abord sur créer par défaut , puis sur URL de prédiction.Click on Make default first, then click on Prediction URL.

    Définir l’URL de prédiction par défaut

    Notes

    L’URL du point de terminaison qui est fournie à partir de ce, est définie sur l' itération qui a été marquée comme valeur par défaut.The endpoint URL which is provided from this, is set to whichever Iteration has been marked as default. Par conséquent, si vous effectuez ultérieurement une nouvelle itération et la mettez à jour par défaut, vous n’aurez pas besoin de modifier votre code.As such, if you later make a new Iteration and update it as default, you will not need to change your code.

  11. Une fois que vous avez cliqué sur URL de prédiction, ouvrez le bloc-notes, puis copiez et collez l' URL et la clé de prédiction, afin de pouvoir la récupérer lorsque vous en aurez besoin ultérieurement dans le code.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.

    Copier et coller une URL et Prediction-Key

  12. Cliquez sur le roue dentée en haut à droite de l’écran.Click on the Cog at the top right of the screen.

    Cliquer sur l’icône de roue dentée pour ouvrir les paramètres

  13. Copiez la clé de formation et collez-la dans un bloc-notes, pour une utilisation ultérieure.Copy the Training Key and paste it into a Notepad, for later use.

    Copier la clé de formation

  14. Copiez également votre ID de projet, puis collez-le dans votre fichier bloc-notes pour une utilisation ultérieure.Also copy your Project Id, and also paste it into your Notepad file, for later use.

    Copier l’ID du projet

Chapitre 3-configurer le projet UnityChapter 3 - Set up the Unity project

Ce qui suit est une configuration classique pour le développement avec une réalité mixte, et, par conséquent, est un bon modèle pour d’autres projets.The following is a typical set up for developing with mixed reality, and as such, is a good template for other projects.

  1. Ouvrez Unity et cliquez sur nouveau.Open Unity and click New.

    Créer un projet Unity

  2. Vous devez maintenant fournir un nom de projet Unity.You will now need to provide a Unity project name. Insérez AzureCustomVision.Insert AzureCustomVision. Assurez-vous que le modèle de projet est défini sur 3D.Make sure the project template is set to 3D. Définissez l' emplacement approprié pour vous (n’oubliez pas que les répertoires racine sont mieux adaptés).Set the Location to somewhere appropriate for you (remember, closer to root directories is better). Ensuite, cliquez sur créer un projet.Then, click Create project.

    Configurer les paramètres du projet

  3. Si Unity est ouvert, il est conseillé de vérifier que l' éditeur de script par défaut est défini sur Visual Studio.With Unity open, it is worth checking the default Script Editor is set to Visual Studio. Accédez à modifier les > Préférences , puis à partir de la nouvelle fenêtre, accédez à outils externes.Go to Edit > Preferences and then from the new window, navigate to External Tools. Remplacez l' éditeur de script externe par Visual Studio 2017.Change External Script Editor to Visual Studio 2017. Fermez la fenêtre Préférences .Close the Preferences window.

    Configurer les outils externes

  4. Accédez ensuite à fichier > paramètres de build et sélectionnez plateforme Windows universelle, puis cliquez sur le bouton changer de plateforme pour appliquer votre sélection.Next, go to File > Build Settings and select Universal Windows Platform, then click on the Switch Platform button to apply your selection.

    Configurer les paramètres de buildConfigure build settings

  5. Tout en conservant les paramètres de génération de > de fichiers et assurez-vous que :While still in File > Build Settings and make sure that:

    1. L' appareil cible est défini sur HoloLensTarget Device is set to HoloLens

      Pour les casques immersifs, définissez appareil cible sur n’importe quel appareil.For the immersive headsets, set Target Device to Any Device.

    2. Le type de build est D3DBuild Type is set to D3D

    3. Le SDK est configuré sur le dernier installéSDK is set to Latest installed

    4. Version de Visual Studio définie sur le dernier installéVisual Studio Version is set to Latest installed

    5. La génération et l’exécution sont définies sur l' ordinateur localBuild and Run is set to Local Machine

    6. Enregistrez la scène et ajoutez-la à la Build.Save the scene and add it to the build.

      1. Pour ce faire, sélectionnez Ajouter des scènes ouvertes.Do this by selecting Add Open Scenes. Une fenêtre d’enregistrement s’affiche.A save window will appear.

        Ajouter une scène ouverte à la liste de builds

      2. Créez un dossier pour cela, ainsi que toute nouvelle scène, puis sélectionnez le bouton nouveau dossier pour créer un nouveau dossier, puis nommez-le scenes.Create a new folder for this, and any future, scene, then select the New folder button, to create a new folder, name it Scenes.

        Créer un dossier de scènes

      3. Ouvrez le dossier scenes nouvellement créé, puis dans le champ nom de fichier : , tapez CustomVisionScene, puis cliquez sur Enregistrer.Open your newly created Scenes folder, and then in the File name: text field, type CustomVisionScene, then click on Save.

        Nom du nouveau fichier de scène

        Sachez que vous devez enregistrer vos scènes Unity dans le dossier ressources , car elles doivent être associées au projet Unity.Be aware, you must save your Unity scenes within the Assets folder, as they must be associated with the Unity project. La création du dossier scenes (et d’autres dossiers similaires) est un moyen classique de structurer un projet Unity.Creating the scenes folder (and other similar folders) is a typical way of structuring a Unity project.

    7. Les paramètres restants, dans paramètres de build, doivent être laissés par défaut pour le moment.The remaining settings, in Build Settings, should be left as default for now.

      Paramètres de build par défaut

  6. Dans la fenêtre paramètres de build , cliquez sur le bouton Paramètres du lecteur pour ouvrir le panneau correspondant dans l’espace où se trouve l' inspecteur .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. Dans ce volet, quelques paramètres doivent être vérifiés :In this panel, a few settings need to be verified:

    1. Sous l’onglet autres paramètres :In the Other Settings tab:

      1. La version du runtime de script doit être expérimentale (.net 4,6 équivalent), ce qui déclenche la nécessité de redémarrer l’éditeur.Scripting Runtime Version should be Experimental (.NET 4.6 Equivalent), which will trigger a need to restart the Editor.

      2. Le backend de script doit être .netScripting Backend should be .NET

      3. Le niveau de compatibilité de l’API doit être .net 4,6API Compatibility Level should be .NET 4.6

      Définir l’API compantiblity

    2. Dans l’onglet paramètres de publication , sous fonctionnalités, activez la case à cocher :Within the Publishing Settings tab, under Capabilities, check:

      1. InternetClientInternetClient

      2. WebcamWebcam

      3. MicrophoneMicrophone

      Configurer les paramètres de publication

    3. Plus bas dans le volet, dans les paramètres XR (situés sous paramètres de publication), cochez la réalité virtuelle prise en charge, assurez-vous que le Kit de développement logiciel (SDK) Windows Mixed Reality est ajouté.Further down the panel, in XR Settings (found below Publish Settings), tick Virtual Reality Supported, make sure the Windows Mixed Reality SDK is added.

    Configurer les paramètres XR

  8. De retour dans les paramètres de build les # projets Unit C ne sont plus grisés ; cochez la case en regard de cette option.Back in Build Settings Unity C# Projects is no longer greyed out; tick the checkbox next to this.

  9. Fermez la fenêtre Build Settings.Close the Build Settings window.

  10. Enregistrez votre scène et votre projet (fichier > enregistrer la scène/le fichier > enregistrer le projet).Save your Scene and project (FILE > SAVE SCENE / FILE > SAVE PROJECT).

Chapitre 4-importation de la DLL Newtonsoft dans UnityChapter 4 - Importing the Newtonsoft DLL in Unity

Important

Si vous souhaitez ignorer le composant Unity Set up de ce cours et continuer directement dans le code, n’hésitez pas à télécharger ce fichier Azure-Mr-302b. pour Unity, à l’importer dans votre projet en tant que package personnalisé, puis à passer au chapitre 6.If you wish to skip the Unity Set up component of this course, and continue straight into code, feel free to download this Azure-MR-302b.unitypackage, import it into your project as a Custom Package, and then continue from Chapter 6.

Ce cours requiert l’utilisation de la bibliothèque Newtonsoft , que vous pouvez ajouter en tant que dll à vos ressources.This course requires the use of the Newtonsoft library, which you can add as a DLL to your assets. Le package contenant cette bibliothèque peut être téléchargé à partir de ce lien.The package containing this library can be downloaded from this Link. Pour importer la bibliothèque Newtonsoft dans votre projet, utilisez le package Unity fourni avec ce cours.To import the Newtonsoft library into your project, use the Unity Package which came with this course.

  1. Ajoutez le fichier . pour Unity à Unity à l’aide de l’option de menu *Assets > > Custom package personnalisé du package d'*importation* de ressources* .Add the .unitypackage to Unity by using the Assets > Import Package > Custom Package menu option.

  2. Dans la zone importer le package Unity qui s’affiche, vérifiez que tous les plug-ins sous (et y compris) sont sélectionnés.In the Import Unity Package box that pops up, ensure everything under (and including) Plugins is selected.

    Importer tous les éléments de package

  3. Cliquez sur le bouton Importer pour ajouter les éléments à votre projet.Click the Import button to add the items to your project.

  4. Accédez au dossier Newtonsoft sous plug-ins dans la vue projet et sélectionnez l' Newtonsoft.Jsdans le plug-in.Go to the Newtonsoft folder under Plugins in the project view and select the Newtonsoft.Json plugin.

    Sélectionner le plug-in Newtonsoft

  5. Après avoir sélectionné le Newtonsoft.Jssur le plug-in , assurez-vous que toutes les plateformes sont décochées, vérifiez que WSAPlayer est également désactivé, puis cliquez sur appliquer.With the Newtonsoft.Json plugin selected, ensure that Any Platform is unchecked, then ensure that WSAPlayer is also unchecked, then click Apply. Cela vous permet de vérifier que les fichiers sont correctement configurés.This is just to confirm that the files are configured correctly.

    Configurer le plug-in Newtonsoft

    Notes

    Le marquage de ces plug-ins permet de les configurer pour qu’ils soient utilisés uniquement dans l’éditeur Unity.Marking these plugins configures them to only be used in the Unity Editor. Il y en a un ensemble différent dans le dossier WSA qui sera utilisé une fois que le projet est exporté d’Unity.There are a different set of them in the WSA folder which will be used after the project is exported from Unity.

  6. Ensuite, vous devez ouvrir le dossier WSA , dans le dossier Newtonsoft .Next, you need to open the WSA folder, within the Newtonsoft folder. Vous verrez une copie du même fichier que celui que vous venez de configurer.You will see a copy of the same file you just configured. Sélectionnez le fichier, puis, dans l’inspecteur, vérifiez queSelect the file, and then in the inspector, ensure that

    • Aucune plateforme n’est désactivéeAny Platform is unchecked
    • seul WSAPlayer est activéonly WSAPlayer is checked
    • L’option ne pas traiter le processus est activéeDont process is checked

    Configurer les paramètres de plateforme de plug-in Newtonsoft

Chapitre 5-Configuration de l’appareil photoChapter 5 - Camera setup

  1. Dans le panneau hiérarchie, sélectionnez l' appareil photo principal.In the Hierarchy Panel, select the Main Camera.

  2. Une fois sélectionné, vous pouvez voir tous les composants de la caméra principale dans le panneau Inspecteur.Once selected, you will be able to see all the components of the Main Camera in the Inspector Panel.

    1. L’objet Camera doit être nommé Camera main (Notez l’orthographe !)The camera object must be named Main Camera (note the spelling!)

    2. La balise principale de l’appareil photo doit être définie sur MainCamera (Notez l’orthographe !)The Main Camera Tag must be set to MainCamera (note the spelling!)

    3. Vérifiez que la position de la transformation est définie sur 0, 0, 0Make sure the Transform Position is set to 0, 0, 0

    4. Affectez à effacer les indicateurs la couleur unie (ignorer ce point pour le casque immersif).Set Clear Flags to Solid Color (ignore this for immersive headset).

    5. Définissez la couleur d' arrière-plan du composant Camera sur Black, alpha 0 (Code hex : #00000000) (ignorez-le pour le casque immersif).Set the Background Color of the camera Component to Black, Alpha 0 (Hex Code: #00000000) (ignore this for immersive headset).

    Configurer les propriétés du composant d’appareil photo

Chapitre 6-créer la classe CustomVisionAnalyser.Chapter 6 - Create the CustomVisionAnalyser class.

À ce stade, vous êtes prêt à écrire du code.At this point you are ready to write some code.

Vous allez commencer par la classe CustomVisionAnalyser .You will begin with the CustomVisionAnalyser class.

Notes

Les appels au service vision personnalisée effectués dans le code ci-dessous sont effectués à l’aide de l' API REST Custom vision.The calls to the Custom Vision Service made in the code shown below are made using the Custom Vision REST API. À l’aide de ce guide, vous allez apprendre à implémenter et à utiliser cette API (utile pour comprendre comment implémenter des éléments similaires).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). Sachez que Microsoft propose un Kit de développement logiciel (SDK) service vision personnalisée qui peut également être utilisé pour effectuer des appels au service.Be aware, that Microsoft offers a Custom Vision Service SDK that can also be used to make calls to the Service. Pour plus d’informations, consultez l’article du Kit de développement logiciel (SDK) service vision personnalisée .For more information visit the Custom Vision Service SDK article.

Cette classe est chargée des opérations suivantes :This class is responsible for:

  • Chargement de la dernière image capturée sous la forme d’un tableau d’octets.Loading the latest image captured as an array of bytes.

  • Envoi du tableau d’octets à votre instance Azure service vision personnalisée à des fins d’analyse.Sending the byte array to your Azure Custom Vision Service instance for analysis.

  • Réception de la réponse sous forme de chaîne JSON.Receiving the response as a JSON string.

  • La désérialisation de la réponse et le passage de la prédiction résultante à la classe SceneOrganiser , qui s’occupera du mode d’affichage de la réponse.Deserializing the response and passing the resulting Prediction to the SceneOrganiser class, which will take care of how the response should be displayed.

Pour créer cette classe :To create this class:

  1. Cliquez avec le bouton droit sur le dossier Asset situé dans le panneau Projet, puis cliquez sur créer un dossier >.Right-click in the Asset Folder located in the Project Panel, then click Create > Folder. Appelez le dossier scripts.Call the folder Scripts.

    Créer un dossier de scripts

  2. Double-cliquez sur le dossier que vous venez de créer pour l’ouvrir.Double-click on the folder just created, to open it.

  3. Cliquez avec le bouton droit dans le dossier, puis cliquez sur créer un > # script C.Right-click inside the folder, then click Create > C# Script. Nommez le script CustomVisionAnalyser.Name the script CustomVisionAnalyser.

  4. Double-cliquez sur le nouveau script CustomVisionAnalyser pour l’ouvrir avec Visual Studio.Double-click on the new CustomVisionAnalyser script to open it with Visual Studio.

  5. Mettez à jour les espaces de noms en haut de votre fichier pour qu’ils correspondent à ce qui suit :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. Dans la classe CustomVisionAnalyser , ajoutez les variables suivantes :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;
    

    Notes

    Veillez à insérer votre clé de prédiction dans la variable PredictionKey et votre point de terminaison de prédiction dans la variable predictionEndpoint .Make sure you insert your Prediction Key into the predictionKey variable and your Prediction Endpoint into the predictionEndpoint variable. Vous les avez copiées dans le bloc-notes plus tôt dans le cours.You copied these to Notepad earlier in the course.

  7. Le code pour éveillé () doit maintenant être ajouté pour initialiser la variable d’instance :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. Supprimez les méthodes Start () et Update ().Delete the methods Start() and Update().

  9. Ensuite, ajoutez la Coroutine (avec la méthode statique GetImageAsByteArray () en dessous de celle-ci), qui obtiendra les résultats de l’analyse de l’image capturée par la classe ImageCapture .Next, add the coroutine (with the static GetImageAsByteArray() method below it), which will obtain the results of the analysis of the image captured by the ImageCapture class.

    Notes

    Dans la Coroutine AnalyseImageCapture , il y a un appel à la classe SceneOrganiser que vous êtes encore en cours de création.In the AnalyseImageCapture coroutine, there is a call to the SceneOrganiser class that you are yet to create. Par conséquent, laissez ces lignes commentées pour l’instant.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. Veillez à enregistrer vos modifications dans Visual Studio avant de revenir à Unity.Be sure to save your changes in Visual Studio before returning to Unity.

Chapitre 7-créer la classe CustomVisionObjectsChapter 7 - Create the CustomVisionObjects class

La classe que vous allez créer est maintenant la classe CustomVisionObjects .The class you will create now is the CustomVisionObjects class.

Ce script contient un certain nombre d’objets utilisés par d’autres classes pour sérialiser et désérialiser les appels passés au service vision personnalisée.This script contains a number of objects used by other classes to serialize and deserialize the calls made to the Custom Vision Service.

Avertissement

Il est important de noter le point de terminaison que la Service Vision personnalisée vous fournit, car la structure JSON ci-dessous a été configurée pour fonctionner avec Custom vision prédiction v 2.0.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. Si vous disposez d’une version différente, vous devrez peut-être mettre à jour la structure ci-dessous.If you have a different version, you may need to update the below structure.

Pour créer cette classe :To create this class:

  1. Cliquez avec le bouton droit dans le dossier scripts , puis cliquez sur créer un > # script C.Right-click inside the Scripts folder, then click Create > C# Script. Appelez le script CustomVisionObjects.Call the script CustomVisionObjects.

  2. Double-cliquez sur le nouveau script CustomVisionObjects pour l’ouvrir avec Visual Studio.Double-click on the new CustomVisionObjects script to open it with Visual Studio.

  3. Ajoutez les espaces de noms suivants au début du fichier :Add the following namespaces to the top of the file:

    using System;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Networking;
    
  4. Supprimez les méthodes Start () et Update () à l’intérieur de la classe CustomVisionObjects ; Cette classe doit maintenant être vide.Delete the Start() and Update() methods inside the CustomVisionObjects class; this class should now be empty.

  5. Ajoutez les classes suivantes en dehors de la classe CustomVisionObjects .Add the following classes outside the CustomVisionObjects class. Ces objets sont utilisés par la bibliothèque Newtonsoft pour sérialiser et désérialiser les données de réponse :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; }
    }
    

Chapitre 8-créer la classe VoiceRecognizerChapter 8 - Create the VoiceRecognizer class

Cette classe reconnaît la saisie vocale de l’utilisateur.This class will recognize the voice input from the user.

Pour créer cette classe :To create this class:

  1. Cliquez avec le bouton droit dans le dossier scripts , puis cliquez sur créer un > # script C.Right-click inside the Scripts folder, then click Create > C# Script. Appelez le script VoiceRecognizer.Call the script VoiceRecognizer.

  2. Double-cliquez sur le nouveau script VoiceRecognizer pour l’ouvrir avec Visual Studio.Double-click on the new VoiceRecognizer script to open it with Visual Studio.

  3. Ajoutez les espaces de noms suivants au-dessus de la classe VoiceRecognizer :Add the following namespaces above the VoiceRecognizer class:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.Windows.Speech;
    
  4. Ajoutez ensuite les variables suivantes à l’intérieur de la classe VoiceRecognizer , au-dessus de la méthode Start () :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. Ajoutez les méthodes éveillé () et Start () , dont la dernière configurera les Mots clés utilisateur pour qu’ils soient reconnus lors de l’Association d’une balise à une image :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. Supprimez la méthode Update () .Delete the Update() method.

  7. Ajoutez le gestionnaire suivant, qui est appelé chaque fois que l’entrée vocale est reconnue :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. Veillez à enregistrer vos modifications dans Visual Studio avant de revenir à Unity.Be sure to save your changes in Visual Studio before returning to Unity.

Notes

Ne vous inquiétez pas du code qui peut sembler avoir une erreur, car vous fournirez bientôt d’autres classes, ce qui les corrigera.Do not worry about code which might appear to have an error, as you will provide further classes soon, which will fix these.

Chapitre 9-créer la classe CustomVisionTrainerChapter 9 - Create the CustomVisionTrainer class

Cette classe chaînera une série d’appels Web pour former l' service vision personnalisée.This class will chain a series of web calls to train the Custom Vision Service. Chaque appel sera expliqué en détail juste au-dessus du code.Each call will be explained in detail right above the code.

Pour créer cette classe :To create this class:

  1. Cliquez avec le bouton droit dans le dossier scripts , puis cliquez sur créer un > # script C.Right-click inside the Scripts folder, then click Create > C# Script. Appelez le script CustomVisionTrainer.Call the script CustomVisionTrainer.

  2. Double-cliquez sur le nouveau script CustomVisionTrainer pour l’ouvrir avec Visual Studio.Double-click on the new CustomVisionTrainer script to open it with Visual Studio.

  3. Ajoutez les espaces de noms suivants au-dessus de la classe CustomVisionTrainer :Add the following namespaces above the CustomVisionTrainer class:

    using Newtonsoft.Json;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using UnityEngine;
    using UnityEngine.Networking;
    
  4. Ajoutez ensuite les variables suivantes à l’intérieur de la classe CustomVisionTrainer , au-dessus de la méthode Start () .Then add the following variables inside the CustomVisionTrainer class, above the Start() method.

    Notes

    L’URL de formation utilisée ici est fournie dans la documentation Custom vision formation 1,2 et présente la structure suivante : 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}/
    Pour plus d’informations, consultez l' API de référence de Custom vision formation v 1.2.For more information, visit the Custom Vision Training v1.2 reference API.

    Avertissement

    Il est important de noter le point de terminaison que la Service Vision personnalisée vous fournit pour le mode d’apprentissage, car la structure JSON utilisée (dans la classe CustomVisionObjects ) a été configurée pour fonctionner avec Custom vision formation v 1.2.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. Si vous disposez d’une version différente, vous devrez peut-être mettre à jour la structure des objets .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;
    

    Important

    Veillez à ajouter la valeur de clé de service (clé de formation) et la valeur d' ID de projet , que vous avez notée précédemment ; Il s’agit des valeurs que vous avez collectées à partir du portail plus haut dans le cours (chapitre 2, étape 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. Ajoutez les méthodes Start () et éveillé () suivantes.Add the following Start() and Awake() methods. Ces méthodes sont appelées lors de l’initialisation et contiennent l’appel pour configurer l’interface utilisateur :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. Supprimez la méthode Update () .Delete the Update() method. Cette classe n’en a pas besoin.This class will not need it.

  7. Ajoutez la méthode RequestTagSelection () .Add the RequestTagSelection() method. Cette méthode est la première à être appelée lorsqu’une image a été capturée et stockée dans l’appareil et qu’elle est maintenant prête à être envoyée à la service vision personnalisée pour l’effectuer.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. Cette méthode affiche, dans l’interface utilisateur de formation, un ensemble de mots clés que l’utilisateur peut utiliser pour baliser l’image capturée.This method displays, in the training UI, a set of keywords the user can use to tag the image that has been captured. Elle alerte également la classe VoiceRecognizer pour commencer à écouter l’utilisateur pour l’entrée vocale.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. Ajoutez la méthode VerifyTag () .Add the VerifyTag() method. Cette méthode recevra l’entrée vocale reconnue par la classe VoiceRecognizer et vérifiera sa validité, puis commencera le processus d’apprentissage.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. Ajoutez la méthode SubmitImageForTraining () .Add the SubmitImageForTraining() method. Cette méthode démarre le processus de formation Service Vision personnalisée.This method will begin the Custom Vision Service training process. La première étape consiste à récupérer l' ID de balise à partir du service associé à l’entrée vocale validée de l’utilisateur.The first step is to retrieve the Tag Id from the Service which is associated with the validated speech input from the user. L' ID de balise sera ensuite téléchargé avec l’image.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. Ajoutez la méthode TrainCustomVisionProject () .Add the TrainCustomVisionProject() method. Une fois que l’image a été envoyée et balisée, cette méthode est appelée.Once the image has been submitted and tagged, this method will be called. Il créera une nouvelle itération qui sera formée avec toutes les images précédentes soumises au service, ainsi que l’image qui vient d’être téléchargée.It will create a new Iteration that will be trained with all the previous images submitted to the Service plus the image just uploaded. Une fois l’apprentissage terminé, cette méthode appellera une méthode pour définir l' itération nouvellement créée par défaut, afin que le point de terminaison que vous utilisez pour l’analyse soit la dernière itération formée.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. Ajoutez la méthode SetDefaultIteration () .Add the SetDefaultIteration() method. Cette méthode définit l’itération précédemment créée et formée comme valeur par défaut.This method will set the previously created and trained iteration as Default. Une fois l’opération terminée, cette méthode devra supprimer l’itération précédente existante dans le service.Once completed, this method will have to delete the previous iteration existing in the Service. Au moment de la rédaction de ce cours, il existe une limite de dix (10) itérations maximum autorisées à exister simultanément dans le service.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. Ajoutez la méthode DeletePreviousIteration () .Add the DeletePreviousIteration() method. Cette méthode recherche et supprime l’itération précédente non définie par défaut :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. La dernière méthode à ajouter dans cette classe est la méthode GetImageAsByteArray () , utilisée sur les appels Web pour convertir l’image capturée dans un tableau d’octets.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. Veillez à enregistrer vos modifications dans Visual Studio avant de revenir à Unity.Be sure to save your changes in Visual Studio before returning to Unity.

Chapitre 10-créer la classe SceneOrganiserChapter 10 - Create the SceneOrganiser class

Cette classe effectuera les opérations suivantes :This class will:

  • Créez un objet curseur à attacher à l’appareil photo principal.Create a Cursor object to attach to the Main Camera.

  • Créez un objet étiquette qui s’affiche lorsque le service reconnaît les objets réels.Create a Label object that will appear when the Service recognizes the real-world objects.

  • Configurez la caméra principale en y joignant les composants appropriés.Set up the Main Camera by attaching the appropriate components to it.

  • En mode analyse, générez les étiquettes au moment de l’exécution, dans l’espace universel approprié par rapport à la position de la caméra principale, puis affichez les données reçues de la service vision personnalisée.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.

  • En mode d’apprentissage, générez l’interface utilisateur qui affichera les différentes étapes du processus d’apprentissage.When in Training Mode, spawn the UI that will display the different stages of the training process.

Pour créer cette classe :To create this class:

  1. Cliquez avec le bouton droit dans le dossier scripts , puis cliquez sur créer un > # script C.Right-click inside the Scripts folder, then click Create > C# Script. Nommez le script SceneOrganiser.Name the script SceneOrganiser.

  2. Double-cliquez sur le nouveau script SceneOrganiser pour l’ouvrir avec Visual Studio.Double-click on the new SceneOrganiser script to open it with Visual Studio.

  3. Vous n’aurez besoin que d’un seul espace de noms, supprimez les autres au-dessus de la classe SceneOrganiser :You will only need one namespace, remove the others from above the SceneOrganiser class:

    using UnityEngine;
    
  4. Ajoutez ensuite les variables suivantes à l’intérieur de la classe SceneOrganiser , au-dessus de la méthode Start () :Then add the following variables inside the SceneOrganiser class, above the Start() method:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static SceneOrganiser Instance;
    
        /// <summary>
        /// The cursor object attached to the 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. Supprimez les méthodes Start () et Update () .Delete the Start() and Update() methods.

  6. Juste en dessous des variables, ajoutez la méthode éveillé () , qui initialisera la classe et configurera la scène.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. Ajoutez à présent la méthode CreateCameraCursor () qui crée et positionne le curseur principal de l’appareil photo, et la méthode CreateLabel () , qui crée l’objet étiquette d’analyse .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. Ajoutez la méthode SetCameraStatus () , qui gérera les messages destinés à la maille de texte qui fournit l’état de l’appareil photo.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. Ajoutez les méthodes PlaceAnalysisLabel () et SetTagsToLastLabel () , qui génèrent et affichent les données de la service vision personnalisée dans la scène.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. Enfin, ajoutez la méthode CreateTrainingUI () , qui générera l’interface utilisateur en affichant les différentes étapes du processus d’apprentissage lorsque l’application est en mode d’apprentissage.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. Cette méthode est également exploitable pour créer l’objet d’état de l’appareil photo.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. Veillez à enregistrer vos modifications dans Visual Studio avant de revenir à Unity.Be sure to save your changes in Visual Studio before returning to Unity.

Important

Avant de continuer, ouvrez la classe CustomVisionAnalyser et, dans la méthode AnalyseLastImageCaptured () , supprimez les marques de commentaire des lignes suivantes :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);

Chapitre 11-créer la classe ImageCaptureChapter 11 - Create the ImageCapture class

La classe suivante que vous allez créer est la classe ImageCapture .The next class you are going to create is the ImageCapture class.

Cette classe est chargée des opérations suivantes :This class is responsible for:

  • Capture d’une image à l’aide de la caméra HoloLens et stockage dans le dossier de l' application .Capturing an image using the HoloLens camera and storing it in the App Folder.

  • Gestion des gestes TAP de l’utilisateur.Handling Tap gestures from the user.

  • Maintien de la valeur enum qui détermine si l’application s’exécutera en mode d' analyse ou en mode d' apprentissage .Maintaining the Enum value that determines if the application will run in Analysis mode or Training Mode.

Pour créer cette classe :To create this class:

  1. Accédez au dossier scripts que vous avez créé précédemment.Go to the Scripts folder you created previously.

  2. Cliquez avec le bouton droit dans le dossier, puis cliquez sur créer > # script C.Right-click inside the folder, then click Create > C# Script. Nommez le script ImageCapture.Name the script ImageCapture.

  3. Double-cliquez sur le nouveau script ImageCapture pour l’ouvrir avec Visual Studio.Double-click on the new ImageCapture script to open it with Visual Studio.

  4. Remplacez les espaces de noms en haut du fichier par les éléments suivants :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. Ajoutez ensuite les variables suivantes à l’intérieur de la classe ImageCapture , au-dessus de la méthode Start () :Then add the following variables inside the ImageCapture class, above the Start() method:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static ImageCapture Instance;
    
        /// <summary>
        /// Keep counts of the taps for image renaming
        /// </summary>
        private int captureCount = 0;
    
        /// <summary>
        /// Photo Capture object
        /// </summary>
        private PhotoCapture photoCaptureObject = null;
    
        /// <summary>
        /// Allows gestures recognition in HoloLens
        /// </summary>
        private GestureRecognizer recognizer;
    
        /// <summary>
        /// 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. Vous devez maintenant ajouter le code des méthodes éveillés () et Start () :Code for Awake() and Start() methods now needs to be added:

        /// <summary>
        /// Called on initialization
        /// </summary>
        private void Awake()
        {
            Instance = this;
    
            // Change this flag to switch between Analysis Mode and Training Mode 
            AppMode = AppModes.Training;
        }
    
        /// <summary>
        /// Runs at initialization right after Awake method
        /// </summary>
        void Start()
        {
            // Clean up the LocalState folder of this application from all photos stored
            DirectoryInfo info = new DirectoryInfo(Application.persistentDataPath);
            var fileInfo = info.GetFiles();
            foreach (var file in fileInfo)
            {
                try
                {
                    file.Delete();
                }
                catch (Exception)
                {
                    Debug.LogFormat("Cannot delete file: ", file.Name);
                }
            } 
    
            // Subscribing to the HoloLens API gesture recognizer to track user gestures
            recognizer = new GestureRecognizer();
            recognizer.SetRecognizableGestures(GestureSettings.Tap);
            recognizer.Tapped += TapHandler;
            recognizer.StartCapturingGestures();
    
            SceneOrganiser.Instance.SetCameraStatus("Ready");
        }
    
  7. Implémentez un gestionnaire qui sera appelé quand un mouvement TAP se produit.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;
            }     
        }
    

    Notes

    En mode analyse , la méthode TapHandler agit comme un commutateur pour démarrer ou arrêter la boucle de capture photo.In Analysis mode, the TapHandler method acts as a switch to start or stop the photo capture loop.

    En mode d' apprentissage , une image est capturée à partir de l’appareil photo.In Training mode, it will capture an image from the camera.

    Lorsque le curseur est vert, cela signifie que l’appareil photo est disponible pour prendre l’image.When the cursor is green, it means the camera is available to take the image.

    Lorsque le curseur est rouge, cela signifie que l’appareil photo est occupé.When the cursor is red, it means the camera is busy.

  8. Ajoutez la méthode utilisée par l’application pour démarrer le processus de capture d’image et stocker l’image.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. Ajoutez les gestionnaires qui seront appelés lorsque la photo a été capturée et le moment où elle sera prête à être analysée.Add the handlers that will be called when the photo has been captured and for when it is ready to be analyzed. Le résultat est ensuite transmis à CustomVisionAnalyser ou CustomVisionTrainer selon le mode sur lequel le code est défini.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. Veillez à enregistrer vos modifications dans Visual Studio avant de revenir à Unity.Be sure to save your changes in Visual Studio before returning to Unity.

  11. Maintenant que tous les scripts ont été exécutés, revenez dans l’éditeur Unity, puis cliquez et faites glisser la classe SceneOrganiser du dossier scripts vers l’objet Camera principal dans le panneau hiérarchie.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.

Chapitre 12-avant générationChapter 12 - Before building

Pour effectuer un test minutieux de votre application, vous devez l’chargement sur votre HoloLens.To perform a thorough test of your application you will need to sideload it onto your HoloLens.

Avant cela, assurez-vous que :Before you do, ensure that:

  • Tous les paramètres mentionnés dans le Chapitre 2 sont correctement définis.All the settings mentioned in the Chapter 2 are set correctly.

  • Tous les champs de l' appareil photo principal, du panneau Inspecteur, sont correctement affectés.All the fields in the Main Camera, Inspector Panel, are assigned properly.

  • Le script SceneOrganiser est attaché à l’objet Camera principal .The script SceneOrganiser is attached to the Main Camera object.

  • Veillez à insérer votre clé de prédiction dans la variable predictionKey .Make sure you insert your Prediction Key into the predictionKey variable.

  • Vous avez inséré votre point de terminaison de prédiction dans la variable predictionEndpoint .You have inserted your Prediction Endpoint into the predictionEndpoint variable.

  • Vous avez inséré votre clé de formation dans la variable trainingKey de la classe CustomVisionTrainer .You have inserted your Training Key into the trainingKey variable, of the CustomVisionTrainer class.

  • Vous avez inséré votre ID de projet dans la variable ProjectId de la classe CustomVisionTrainer .You have inserted your Project ID into the projectId variable, of the CustomVisionTrainer class.

Chapitre 13-créer et chargement votre applicationChapter 13 - Build and sideload your application

Pour commencer le processus de génération :To begin the Build process:

  1. Accédez à fichier > paramètres de build.Go to File > Build Settings.

  2. # Projets Tick Unity C.Tick Unity C# Projects.

  3. Cliquez sur Générer.Click Build. Unity lance une fenêtre de l' Explorateur de fichiers , dans laquelle vous devez créer, puis sélectionner un dossier dans lequel générer l’application.Unity will launch a File Explorer window, where you need to create and then select a folder to build the app into. Créez ce dossier maintenant, puis nommez-le application.Create that folder now, and name it App. Ensuite, avec le dossier d' application sélectionné, cliquez sur Sélectionner un dossier.Then with the App folder selected, click on Select Folder.

  4. Unity commence à générer votre projet dans le dossier de l' application .Unity will begin building your project to the App folder.

  5. Une fois la génération de Unity terminée (cela peut prendre un certain temps), une fenêtre de l' Explorateur de fichiers s’ouvre à l’emplacement de votre Build (Vérifiez la barre des tâches, car elle ne s’affiche pas toujours au-dessus de votre Windows, mais vous informera de l’ajout d’une nouvelle fenêtre).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).

Pour effectuer un déploiement sur HoloLens :To deploy on HoloLens:

  1. Vous aurez besoin de l’adresse IP de votre HoloLens (pour le déploiement à distance) et vérifiez que votre HoloLens est en mode développeur.You will need the IP Address of your HoloLens (for Remote Deploy), and to ensure your HoloLens is in Developer Mode. Pour ce faire :To do this:

    1. Tout en portant votre HoloLens, ouvrez les paramètres.Whilst wearing your HoloLens, open the Settings.

    2. Accéder au réseau & > Options avancées de Wi-Fi > Advanced Options InternetGo to Network & Internet > Wi-Fi > Advanced Options

    3. Notez l’adresse IPv4 .Note the IPv4 address.

    4. Ensuite, revenez aux paramètres, puis pour mettre à jour & sécurité > pour les développeursNext, navigate back to Settings, and then to Update & Security > For Developers

    5. Définissez le mode développeur sur.Set Developer Mode On.

  2. Accédez à votre nouvelle build Unity (le dossier de l' application ) et ouvrez le fichier solution avec Visual Studio.Navigate to your new Unity build (the App folder) and open the solution file with Visual Studio.

  3. Dans la configuration de la solution, sélectionnez Déboguer.In the Solution Configuration select Debug.

  4. Dans la plateforme de la solution, sélectionnez x86, ordinateur distant.In the Solution Platform, select x86, Remote Machine. Vous serez invité à insérer l' adresse IP d’un périphérique distant (le HoloLens, dans ce cas, que vous avez noté).You will be prompted to insert the IP address of a remote device (the HoloLens, in this case, which you noted).

    Configurer l’adresse IP

  5. Accédez au menu générer , puis cliquez sur déployer la solution pour chargement l’application à votre HoloLens.Go to Build menu and click on Deploy Solution to sideload the application to your HoloLens.

  6. Votre application doit maintenant apparaître dans la liste des applications installées sur votre HoloLens, prête à être lancée.Your app should now appear in the list of installed apps on your HoloLens, ready to be launched!

Notes

Pour effectuer un déploiement sur un casque immersif, définissez la plateforme de la solution sur ordinateur local et définissez la configuration sur Déboguer, avec x86 comme plateforme.To deploy to immersive headset, set the Solution Platform to Local Machine, and set the Configuration to Debug, with x86 as the Platform. Déployez ensuite sur l’ordinateur local, à l’aide de l’élément de menu générer , en sélectionnant déployer la solution.Then deploy to the local machine, using the Build menu item, selecting Deploy Solution.

Pour utiliser l’application :To use the application:

Pour basculer la fonctionnalité de l’application entre le mode d' apprentissage et le mode de prédiction , vous devez mettre à jour la variable AppMode , située dans la méthode éveillé () située dans la classe ImageCapture .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;

ouor

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

En mode d' apprentissage :In Training mode:

  • Regardez la souris ou le clavier et utilisez le mouvement TAP.Look at Mouse or Keyboard and use the Tap gesture.

  • Ensuite, du texte s’affiche pour vous demander de fournir une balise.Next, text will appear asking you to provide a tag.

  • Disons la souris ou le clavier.Say either Mouse or Keyboard.

En mode de prédiction :In Prediction mode:

  • Examinez un objet et utilisez le mouvement TAP.Look at an object and use the Tap gesture.

  • Du texte s’affiche pour indiquer l’objet détecté, avec la probabilité la plus élevée (cette opération est normalisée).Text will appear providing the object detected, with the highest probability (this is normalized).

Chapitre 14-évaluer et améliorer votre modèle de Custom VisionChapter 14 - Evaluate and improve your Custom Vision model

Pour améliorer la précision de votre service, vous devrez continuer à former le modèle utilisé pour la prédiction.To make your Service more accurate, you will need to continue to train the model used for prediction. Pour ce faire, vous pouvez utiliser votre nouvelle application, à la fois avec les modes de formation et de prédiction , avec ceux qui vous demandent de visiter le portail, ce qui est abordé dans ce chapitre.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. Préparez-vous à revisiter votre portail plusieurs fois, afin d’améliorer continuellement votre modèle.Be prepared to revisit your portal many times, to continually improve your model.

  1. Accédez à nouveau à votre portail Azure Custom Vision et, une fois que vous êtes dans votre projet, sélectionnez l’onglet prédictions (à partir du centre en haut de la page) :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):

    Onglet sélectionner des prédictions

  2. Vous verrez toutes les images qui ont été envoyées à votre service pendant l’exécution de votre application.You will see all the images which were sent to your Service whilst your application was running. Si vous pointez sur les images, elles vous fourniront les prédictions qui ont été effectuées pour cette image :If you hover over the images, they will provide you with the predictions that were made for that image:

    Liste des images de prédiction

  3. Sélectionnez l’une de vos images pour l’ouvrir.Select one of your images to open it. Une fois ouvert, vous verrez les prédictions effectuées pour cette image à droite.Once open, you will see the predictions made for that image to the right. Si les prédictions sont correctes et que vous souhaitez ajouter cette image au modèle d’apprentissage de votre service, cliquez sur la zone de texte mes balises , puis sélectionnez la balise que vous souhaitez associer.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. Lorsque vous avez terminé, cliquez sur le bouton enregistrer et fermer en bas à droite, puis passez à l’image suivante.When you are finished, click the Save and close button to the bottom right, and continue on to the next image.

    Sélectionner l’image à ouvrir

  4. Une fois que vous revenez à la grille des images, vous remarquerez que les images auxquelles vous avez ajouté des balises (et enregistrées) seront supprimées.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. Si vous trouvez des images dont vous pensez que vous n’avez pas besoin de votre élément balisé, vous pouvez les supprimer en cliquant sur le bouton de l’image (cette opération peut s’effectuer pour plusieurs images), puis en cliquant sur supprimer dans le coin supérieur droit de la page de grille.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. Dans le menu contextuel qui suit, vous pouvez cliquer sur Oui, supprimer ou non pour confirmer la suppression ou l’annuler, respectivement.On the popup that follows, you can click either Yes, delete or No, to confirm the deletion or cancel it, respectively.

    Supprimer des images

  5. Lorsque vous êtes prêt à continuer, cliquez sur le bouton vert train en haut à droite.When you are ready to proceed, click the green Train button in the top right. Votre modèle de service sera formé avec toutes les images que vous avez fournies (ce qui le rendra plus précis).Your Service model will be trained with all the images which you have now provided (which will make it more accurate). Une fois l’apprentissage terminé, veillez à cliquer une fois de plus sur le bouton créer par défaut , afin que votre URL de prédiction continue à utiliser l’itération la plus récente de votre service.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.

    Démarrer le modèle de service de formation  Sélectionnez l’option créer par défautStart training service model Select make default option

Votre application API Custom Vision terminéeYour finished Custom Vision API application

Félicitations, vous avez créé une application de réalité mixte qui tire parti de l’API Azure Custom Vision pour reconnaître des objets réels, former le modèle de service et afficher la confiance de ce qui a été observé.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.

Exemple de projet terminé

Exercices bonusBonus exercises

Exercice 1Exercise 1

Formez votre service vision personnalisée pour qu’il reconnaisse plus d’objets.Train your Custom Vision Service to recognize more objects.

Exercice 2Exercise 2

Pour vous familiariser avec ce que vous avez appris, effectuez les exercices suivants :As a way to expand on what you have learned, complete the following exercises:

Émettre un signal sonore lorsqu’un objet est reconnu.Play a sound when an object is recognized.

Exercice 3Exercise 3

Utilisez l’API pour reformer votre service avec les mêmes images que celles que votre application analyse, afin de rendre le service plus précis (effectuer la prédiction et la formation simultanément).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).