Mise en route avec Kinect et le traitement

Le capteur Kinect de Microsoft est un périphérique (conçu pour les PC XBox et Windows) qui fonctionne un peu comme une webcam. Cependant, en plus de fournir une image RVB, il fournit également une carte de profondeur. Signification pour chaque pixel vu par le capteur, le Kinect mesure la distance par rapport au capteur. Cela rend une variété de problèmes de vision par ordinateur comme la suppression de l’arrière-plan, la détection de blob, et plus facile et amusant!

Le capteur Kinect lui-même mesure uniquement la couleur et la profondeur. Cependant, une fois que ces informations sont sur votre ordinateur, beaucoup plus peut être fait comme le suivi « squelette » (c’est-à-dire la détection d’un modèle d’une personne et le suivi de ses mouvements). Pour effectuer le suivi du squelette, vous devrez utiliser le libray de traitement Kinect v2 de Thomas Lengling uniquement pour Windows. Cependant, si vous êtes sur un Mac et que vous ne voulez que des données brutes du Kinect, vous avez de la chance! Cette bibliothèque utilise les pilotes open source libfreenect et libfreenect2 pour accéder à ces données pour Mac OS X (prise en charge de Windows à venir).

De quel matériel ai-je besoin ?

Vous avez d’abord besoin d’un kinect « autonome ». Vous n’avez pas besoin d’acheter une Xbox.

  • Capteur Kinect autonome v1. Je crois que celui-ci est livré avec l’alimentation, vous n’avez donc pas besoin d’un adaptateur séparé répertorié ensuite. Cependant, si vous avez un kinect v1 fourni avec une XBox, il n’inclura pas l’alimentation du capteur Kinect.
  • Capteur Kinect autonome v2. Vous avez également probablement besoin de l’adaptateur Kinect pour Windows. Ne soyez pas jeté, bien qu’il soit dit Windows, cela vous permettra de le connecter à votre mac via USB. Enfin, vous voudrez également vous assurer que votre ordinateur prend en charge USB 3. La plupart des machines modernes le font, mais si vous n’êtes pas sûr, vous pouvez en savoir plus ici pour Mac OS X.

Quelques notes supplémentaires sur les différents modèles:

  • Kinect 1414: Il s’agit du kinect original et fonctionne avec la bibliothèque documentée sur cette page dans la série bêta de Processing 3.0.
  • Kinect 1473: Cela semble identique au 1414, mais il s’agit d’un modèle mis à jour. Cela devrait fonctionner avec cette bibliothèque, mais je n’en ai pas à tester. Veuillez me faire savoir si c’est le cas ou non!
  • Kinect pour Windows version 1:???? De l’aide ? Celui-ci fonctionne-t-il?
  • Kinect pour Windows version 2: C’est le tout nouveau Kinect avec toutes les fonctionnalités de la Xbox One Kinect. Fonctionne également avec cette bibliothèque!

SimpleOpenNI

Vous pouvez également envisager d’utiliser la bibliothèque SimpleOpenNI et lire le livre Making Things See de Greg Borenstein. OpenNI possède des fonctionnalités (suivi du squelette, reconnaissance des gestes, etc.) qui ne sont pas disponibles dans cette bibliothèque. Malheureusement, OpenNI a été récemment acheté par Apple et, alors que je pensais qu’il était fermé, il semble y avoir des efforts pour le faire revivre!. On ne sait pas quel sera l’avenir d’OpenNI et de SimpleOpenNI.

Je suis prêt à commencer dès maintenant

Le moyen le plus simple d’installer la bibliothèque consiste à utiliser le Gestionnaire de contributions de traitement Sketch → Importer des bibliothèques → Ajouter une bibliothèque et rechercher « Kinect ». Un bouton apparaîtra intitulé « installer ».Si vous souhaitez l’installer manuellement, téléchargez la version la plus récente et extrayez-la dans le dossier bibliothèques. Redémarrez le traitement, ouvrez l’un des exemples dans le dossier exemples et vous êtes prêt à partir!

Qu’est-ce que le traitement?

Processing est un langage de programmation et un environnement open source pour les personnes qui souhaitent créer des images, des animations et des interactions. Initialement développé pour servir de carnet de croquis logiciel et pour enseigner les bases de la programmation informatique dans un contexte visuel, le traitement est également devenu un outil pour générer du travail professionnel fini. Aujourd’hui, des dizaines de milliers d’étudiants, d’artistes, de designers, de chercheurs et d’amateurs utilisent le traitement pour l’apprentissage, le prototypage et la production.

Que faire si je ne veux pas utiliser le traitement?

Si vous êtes à l’aise avec C++, je vous suggère d’utiliser openFrameworks ou Cinder avec le Kinect. Ces environnements ont des fonctionnalités supplémentaires et vous pouvez également obtenir un avantage de vitesse C ++ lors du traitement des données de profondeur, etc.:

  • ofxKinect
  • CinderBlock Kinect
  • Plus de ressources de: Le projet OpenKinect

Quel code dois-je écrire?

La première chose à faire est d’inclure les instructions d’importation appropriées en haut de votre code:

import org.openkinect.processing.*;

Ainsi qu’une référence à un objet Kinect, i.e.

Kinect kinect;

Ensuite, dans setup(), vous pouvez initialiser cet objet kinect:

void setup() { kinect = new Kinect(this); kinect.initDevice();}

Si vous utilisez un Kinect v2, utilisez plutôt un objet Kinect2.

Kinect2 kinect2;void setup() { kinect2 = new Kinect2(this); kinect2.initDevice();}

Une fois cela fait, vous pouvez commencer à accéder aux données du capteur kinect. Actuellement, la bibliothèque met les données à votre disposition de cinq manières:

  • PImage (RGB) de la caméra vidéo kinect.
  • PImage (grayscale) de la caméra INFRAROUGE kinect.
  • PImage (grayscale) avec la luminosité de chaque pixel mappée à la profondeur (plus brillante = plus proche).
  • PImage (RGB) avec la teinte de chaque pixel mappée à la profondeur.
  • int array avec des données de profondeur brutes (11 nombres de bits entre 0 et 2048).

Regardons ceux-ci un à la fois. Si vous souhaitez utiliser le Kinect comme une ancienne webcam ordinaire, vous pouvez accéder à l’image vidéo en tant que PImage!

PImage img = kinect.getVideoImage();image(img, 0, 0);

Vous pouvez simplement demander cette image dans draw(), cependant, si vous pouvez également utiliser videoEvent() pour savoir quand une nouvelle image est disponible.

void videoEvent(Kinect k) { // There has been a video event!}

Si vous voulez l’image IR:

kinect.enableIR(true);

Avec kinect v1 ne peut pas obtenir à la fois l’image vidéo et l’image IR. Ils sont tous les deux renvoyés via getVideoImage(), donc celui qui a été le plus récemment activé est celui que vous obtiendrez. Cependant, avec le Kinect v2, ils sont tous deux disponibles en tant que méthodes distinctes:

PImage video = kinect2.getVideoImage();PImage ir = kinect2.getIrImage();

Maintenant, si vous voulez l’image de profondeur, vous pouvez demander l’image en niveaux de gris:

PImage img = kinect.getDepthImage();image(img, 0, 0);

Ainsi que les données de profondeur brutes:

int depth = kinect.getRawDepth();

Pour le kinect v1, les valeurs de profondeur brutes sont comprises entre 0 et 2048, pour le kinect v2, la plage est comprise entre 0 et 4500.

Pour l’image de profondeur de couleur, utilisez kinect.enableColorDepth(true);. Et tout comme avec l’image vidéo, il y a un événement de profondeur auquel vous pouvez accéder si nécessaire.

void depthEvent(Kinect k) { // There has been a depth event!}

Malheureusement, b / c la caméra RVB et la caméra IR ne sont pas physiquement situées au même endroit, il y a un problème de vision stéréo. Le pixel XY dans une image n’est pas le même XY dans une image d’un appareil photo d’un pouce à droite. La Kinect v2 offre ce qu’on appelle une image « enregistrée » qui aligne toutes les valeurs de profondeur avec celles de la caméra RVB. Cela peut être consulté comme suit:

PImage img = kinect2.getRegisteredImage()

Enfin, pour kinect v1 (mais pas v2), vous pouvez également ajuster l’angle de la caméra avec la méthode setTilt().

float angle = kinect.getTilt();angle = angle + 1;kinect.setTilt(angle);

Donc, voilà, voici toutes les fonctions utiles dont vous pourriez avoir besoin pour utiliser la bibliothèque de traitement kinect:

  • initDevice() — tout démarrer (vidéo, profondeur, IR)
  • activateDevice(int) – activez un périphérique spécifique lorsque plusieurs périphériques sont connectés
  • initVideo() — démarrer la vidéo uniquement
  • enableIR(boolean) — activer ou désactiver l’image de la caméra IR (v1 uniquement)
  • initDepth() — profondeur de démarrage uniquement
  • enableColorDepth(boolean) — activer ou désactiver les valeurs de profondeur en tant qu’image couleur
  • enableMirror(boolean) — miroir de l’image et des données de profondeur (v1 uniquement)
  • PImage getVideoImage() — saisissez l’image vidéo RVB (ou IR pour v1)
  • PImage getIrImage() — saisissez l’image IR (v2 uniquement)
  • PImage getDepthImage() — prenez la carte de profondeur image
  • PImage getRegisteredImage() — saisissez l’image de profondeur enregistrée (v2 uniquement)
  • int getRawDepth() — saisir les données de profondeur brutes
  • float getTilt() — obtenez l’angle du capteur de courant (entre 0 et 30 degrés) (v1 uniquement)
  • setTilt(float) — ajustez l’angle du capteur (entre 0 et 30 degrés) (v1 uniquement)

Pour tout le reste, vous pouvez également jeter un œil à la référence javadoc.

Exemples

Il existe quatre exemples de base pour v1 et v2.

Afficher des images RVB, IR et de profondeur

Code pour v1: RGBDepthTest

Code pour v2:RGBDepthTest2

Cet exemple utilise toutes les fonctions énumérées ci-dessus pour afficher les données du capteur kinect.

Plusieurs périphériques

v1 et v2 prennent en charge plusieurs kinect.

Code pour v1: MultiKinect

Code pour v2: MultiKinect2

Nuage de points

Code pour v1: PointCloud

Code pour v2: PointCloud

Ici, nous faisons quelque chose d’un peu plus chic. Premièrement, nous utilisons les capacités de traitement 3D pour dessiner des points dans l’espace. Vous voudrez vous familiariser avec translate(), rotate(), pushMatrix(), popMatrix(). Ce tutoriel est également un bon point de départ. De plus, l’exemple utilise un PVector pour décrire un point dans l’espace 3D. Plus ici: tutoriel PVector.

Le vrai travail de cet exemple, cependant, ne vient pas du tout de moi. Les valeurs de profondeur brutes du kinect ne sont pas directement proportionnelles à la profondeur physique. Au contraire, ils s’adaptent à l’inverse de la profondeur selon cette formule:

depthInMeters = 1.0 / (rawDepth * -0.0030711016 + 3.3309495161);

Plutôt que de faire ce calcul tout le temps, nous pouvons précalculer toutes ces valeurs dans une table de recherche car il n’y a que 2048 valeurs de profondeur.

float depthLookUp = new float;for (int i = 0; i < depthLookUp.length; i++) { depthLookUp = rawDepthToMeters(i);}float rawDepthToMeters(int depthValue) { if (depthValue < 2047) { return (float)(1.0 / ((double)(depthValue) * -0.0030711016 + 3.3309495161)); } return 0.0f;}

Merci à Matthew Fisher pour la formule ci-dessus. (Remarque: pour que les résultats soient plus précis, vous devez calibrer votre appareil kinect spécifique, mais la formule est assez proche pour moi, donc je m’en tiens à elle pour l’instant. En savoir plus sur l’étalonnage dans un instant.)

Enfin, nous pouvons tracer quelques points en fonction des valeurs de profondeur en mètres:

 for(int x = 0; x < w; x += skip) { for(int y = 0; y < h; y += skip) { int offset = x + y * kinect.width; // Convert kinect data to world xyz coordinate int rawDepth = depth; PVector v = depthToWorld(x, y, rawDepth); stroke(255); pushMatrix(); // Scale up by 200 float factor = 200; translate(v.x * factor, v.y * factor, factor-v.z * factor); // Draw a point point(0,0); popMatrix(); } }

Suivi des points moyen

La vraie magie du kinect réside dans ses capacités de vision par ordinateur. Avec des informations de profondeur, vous pouvez faire toutes sortes de choses amusantes comme dire: « l’arrière-plan dépasse les 5 pieds. Ignorez-le! »Sans profondeur, la suppression de l’arrière-plan implique toutes sortes de comparaisons minutieuses de pixels. Pour une démonstration rapide de cette idée, voici un exemple très basique qui calcule l’emplacement xy moyen de tous les pixels devant un seuil de profondeur donné.

Source pour v1 : AveragePointTracking

Source pour v2: AveragePointTracking2

Dans cet exemple, je déclare deux variables pour additionner tous les x et y appropriés et une variable pour garder une trace de combien il y en a.

float sumX = 0;float sumY = 0;float count = 0;

Ensuite, chaque fois que nous trouvons un point donné conforme à notre seuil, j’ajoute le x et le y à la somme:

 if (rawDepth < threshold) { sumX += x; sumY += y; count++; }

Lorsque nous avons terminé, nous calculons la moyenne et tirons un point!

if (count != 0) { float avgX = sumX / count; float avgY = sumY / count; fill(255, 0, 0); ellipse(avgX, avgY, 16, 16);}

Qu’est-ce qui manque ?

  • Tout est suivi via les problèmes github.

FAQ

  1. Quelles sont les ombres dans l’image de profondeur (v1)? Diagramme d’ombre Kinect
  2. Quelle est la plage de profondeur que le kinect peut voir? (v1) ~ 0,7-6 mètres ou 2,3-20 pieds. Notez que vous obtiendrez des pixels noirs (ou une valeur de profondeur brute de 2048) aux deux éléments trop éloignés et trop proches.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.