Sélectionner une page

Kinect

Kinect Azure + OpenCV + Unity = un mauvais cocktail de DLL

Computer vision | Electronique | IOT

Pour un projet récent de détection de balles jetées contre un mur j’ai voulu utiliser la nouvelle caméra de profondeur Kinect Azure. Le projet ayant pour but d’être intégré à un jeu j’ai souhaité tout coder sur Unity en utilisant aussi OpenCV Sharp pour l’analyse d’image.

Le début des ennuis

    J’ai commencé en prototypant ma pipeline de détection :

    1. Récupération des images couleurs et profondeur. 
    2. Transformation de l’image de profondeur en nuage de points.
    3. Changement de système de coordonnées entre caméra couleur et profondeur. 
    4. Changement de système de coordonnées entre la caméra couleur et le système de coordonnées de l’écran de projection (précédemment calculé grâce à la projection et analyse d’un chessboard). 
    5. Reproduction du nuage de points en une image de profondeur (2D). 
    6. Analyse d’image pour détecter des “blobs” qui sont mes balles touchant l’écran.

     

    Dès les premières étapes j’ai commencé à noter des ralentissements étonnant qui se corrigeait généralement en changeant la façon dont j’appelais les fonctions de la Kinect : si je devait faire une opération sur chaque pixel, appeler sur Unity les fonctions de la DLL de la Kinect à chaque pixel était très long. Si je passais un tableau complet de pixels, l’opération était beaucoup plus rapide (d’un facteur 10 à 50).

    On voit dans l’exemple ci-dessous un exemple très concret, avec la variable pointCloud de type Image qui vient de la DLL K4ADotNet de la Kinect. Si les valeurs sont stockées dans des variable avant d’exécuter les boucles, le temps d’exécution est bien plus rapide.

    private Mat ConvertPointCloudImageToMat(Image pointCloud)
    {
    
    
    
        for (int i = 0; i < pointCloud.HeightPixels; i++)
        {
            for (int j = 0; j < pointCloud.WidthPixels; j++)
            {
                 /// DO NOTHING
            }
        }
    }

    Temps d’exécution : 26ms

      private Mat ConvertPointCloudImageToMat(Image pointCloud)
      {
          int height = pointCloud.HeightPixels;
          int width = pointCloud.WidthPixels;
      
          for (int i = 0; i < height ; i++)
          {
              for (int j = 0; j < width ; j++)
              {
                   /// DO NOTHING
              }
          }
      }

      Temps d’exécution : 0.1ms

        Plus j’avançais plus je remarquais un problème similaire avec OpenCV, lors de multiplication de pixels sur les Matrix.

        Je compris enfin que le problème venait de Unity et sa gestion des DLL. Les appels aux fonctions des DLL sont très coûteux à cause d’important overhead. Il fait donc limiter au maximum les appels en essayant de “packager” les données à traiter pour les envoyer en un seul appel.

        Que faire alors ?

          Si vous avez beaucoup de traitement à faire avec la Kinect et même OpenCV, il est préférable de directement créer sa propre DLL dans laquelle les fonctionnalités les plus sensibles seront codées. Pour ma part je vais la faire en C++ car OpenCV et le SDK de la Kinect sont disponibles dans ce langage (et pas en C#).
          S’il y a peu de traitement, je vous conseillerai de bien analyser les temps d’exécution de vos fonctions avec une StopWatch par exemple, et de changer les format d’appels. Favoriser les tableaux de pixels et l’image par image au pixel par pixel. Aussi pensez à utiliser la fonction très rapide Marshall.Copy pour les Intr en Array.

          Voilà ci-dessous un autre exemple d’optimisation pour l’utilisation des Mat d’OpenCV. Il faut charger toutes les données dans un double[ ] et faire un Mat.put sur l’array complet. Les Matrix doivent être des bonnes dimensions au préalable. 

          private Mat ConvertPointCloudImageToMat(Image pointCloud)
          {
              int indx = 0;
              int height = pointCloud.HeightPixels;
              int width = pointCloud.WidthPixels;
              double[] data = new double[3];
          
              for (int i = 0; i < height; i++)
              {
                  for (int j = 0; j < width; j++)
                  {
                      indx = j * 3 + i * width * 3;
                      data[0] = pointCloudBuffer[indx] * 0.001f;
                      data[1] = pointCloudBuffer[indx + 1] * 0.001f;
                      data[2] = pointCloudBuffer[indx + 2] * 0.001f;
                      pointCloudMat.put(i, j, data);
                  }
              }
              return pointCloudMat;
          }

          Temps d’exécution : 80ms

            private Mat ConvertPointCloudImageToMat(Image pointCloud)
                    {
                        int indx = 0;
                        int height = pointCloud.HeightPixels;
                        int width = pointCloud.WidthPixels;
                        double[] data = new double[3* height* width];
            
                        for (int i = 0; i < pointCloudBuffer.Length; i+=3)
                        {
                                data[i] = pointCloudBuffer[i] * 0.001f;
                                data[i+1] = pointCloudBuffer[i+1] * 0.001f;
                                data[i+2] = pointCloudBuffer[i+2] * 0.001f;
                        }
                        pointCloudMat.put(0, 0, data);
                        return pointCloudMat;
                    }

            Temps d’exécution : 17ms

              Vous avez un projet ou besoin d’informations ? N’hésitez pas à nous solliciter !

                 contact@torrusvr.com

                 Bordeaux - Paris

              Développement d'expériences Immersives

              Technologies immersives

              Réalité Virtuelle (VR)
              Réalité Augmenté (AR)
              Metaverse
              Computer Vision
              Projection Mapping
              Jeux Vidéos

              Système embarqué

              Internet des objets (IOT)
              Industry 4.0
              Logiciel embarqué sur UC
              Conception de circuits électroniques (PCB)
              Gateway IOT

              Contact

              contact@torrusvr.com