Motion capture avec Kinect
Programmation
Le SDK est téléchargeable ici. Pour utiliser Kinect pour Windows SDK dans votre application .Net, il suffit de référencer l’assembly Microsoft.Research.Kinect.dll.
On dispose alors de deux nouveaux espaces de noms : un pour l’accès aux flux vidéo et aux squelettes et un pour l’audio. Pour initialiser la librairie NUI, il faut instancier un objet de classe Runtime et définir les flux que l’on veut recevoir :
using Microsoft.Research.Kinect.Nui;
using Microsoft.Research.Kinect.Audio;
kinectRuntime = new Runtime();
kinectRuntime.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseColor);
|
Dans l'exemple ci-dessus, on demande d’initialiser la libraire avec le support du flux de profondeur, du flux vidéo et du suivi des squelettes.
Le buffer vidéo
Le buffer vidéo s'utilise en ouvrant un flux vers le capteur en précisant la résolution et le format.
Dans le code ci-dessous, la résolution demandée est de 640x480 avec un format de pixel en RGB. Il est également possible de demander une résolution de 1280x1024 (avec une baisse des performances) et un format de pixel en YUV. Pour savoir si une nouvelle image est disponible, il faut s'abonnant à l'évènement suivant de la librairie :
kinectRuntime.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
kinectRuntime.VideoFrameReady += kinectRuntime_VideoFrameReady;
|
Le buffer de profondeur
À côté du flux vidéo, le Kinect peut nous envoyer un flux issu du capteur infrarouge qui donne les informations de profondeurs. L’initialisation est comparable à celle du flux vidéo :
kinectRuntime.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex);
kinectRuntime.DepthFrameReady += kinectRuntime_DepthFrameReady;
|
Les données de profondeurs sont stockées sous la forme de tableaux d’entiers sur 16 bits. Le flux de profondeur peut être récupéré en 320x240 ou en 80x60. Sur les 16 bits de chaque pixel, les 13 bits de poids forts donnent la distance en millimètres de chaque pixel. Les 3 bits de poids faible donnent l’index de la personne présente (et cet index vaut 0 si le Kinect n’a détecté personne à cet endroit).
C'est ce flux qui permet de détecter des formes sur le flux vidéo du Kinect. Il est possible ainsi de suivre une main et de détecter les mouvements de doigts pour produire de nouveaux moyens d’interagir avec le PC.
Le suivi de squelettes
La particularité la plus importante du SDK est sa capacité à retrouver le squelette de joints des humains présents devant le capteur. Le SDK intègre un système de reconnaissance extrêmement rapide et ne nécessitant aucun apprentissage à l’utilisation.
La librairie NUI ne peut suivre que 2 squelettes au maximum. C’est la propriété TrackingState == SkeletntrackingState.Tracked qui définit si un squelette est ‘traqué’ ou non. Les squelettes qui ne sont pas suivis ne donnent que leur position. Quand Kinect suit précisément une personne, elle peut fournir au développeur un squelette formé de points clefs détectés sur la personne en question :
Comme on peut le voir sur ce schéma de l’homme de Vitruve, il y a 20 joints qui sont détectés et suivis par la librairie NUI. Pour obtenir les meilleurs résultats, il faut que l’on se tienne à une distance comprise entre 1,2 et 3,5 mètres. Au-delà de ces limites, la précision du capteur et de la librairie NIU décroît rapidement. Il n’est donc pas possible de suivre correctement un utilisateur assis face à son ordinateur.
Chaque joint possède une propriété Position qui est défini par un vecteur4 : (x, y, z, w).
Les trois premiers attributs définissent la position dans l’espace du joint en rapport à la caméra de Kinect (l’espace du squelette). Le dernier attribut (w) donne le niveau de qualité (entre 0 et 1) de l’information. Cela permet de filtrer et de ne prendre que les données dont la librairie est quasi-sure. Chaque squelette porte une propriété TrackingID qui reste la même sur chaque frame. Cela permet de repérer de manière unique les squelettes à chaque appel. Chaque joint est identifié par un enum pour définir sa position de référence (Main, Tête, etc.)
Pour activer le support du suivi des squelettes, il faut activer le flux de profondeur. Le parcourir l’ensemble des squelettes détectés par le système peut se faire de la façon suivante :
void kinectRuntime_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) {
|
Une fois que le code de récupération du squelette est en place, c’est à votre imagination de jouer pour proposer les applications du futur. Il est ainsi possible de chercher des gestures pour piloter les applications ou bien encore à faire de la réalité augmentée. Cependant, il faut créer des gesture qui ne rentrent pas en conflit avec des gestes naturels. Il est aussi difficile de reconnaître une gesture que d’éviter d’en reconnaître une.
Le flux audio
Kinect est livré avec un groupe de quatre microphones qui permettent de capturer du son avec une très bonne qualité, arrivant en 16khz et en mono 16bits. Ils intègrent un processeur de traitement du signal (DSP) permettant de supprimer le bruit de fond et d’annuler les effets d’écho. Pour tout cela, il suffit d’instancier un objet de classe KinectAudioSource :
var source = new KinectAudioSource {SystemMode = SystemMode.OptibeamArrayOnly};
|
De plus, toujours grâce à son groupe de microphones, Kinect peut fournir la direction de la source sonore qu’il enregistre. On appelle cela du beamforming. Il devient alors par exemple possible de savoir qui parle dans une réunion (ou au moins de quelle direction vient la voix). Kinect pour Windows SDK sait également servir de source aux API Microsoft.Speech et ainsi il devient possible de faire de la reconnaissance vocale de ce que capture le SDK.
En ce qui concerne les filtres antiécho et réductions du bruit, la classe KinectAudioSource permet de contrôler les algorithmes pour obtenir les résultats attendus.
Pour plus d'information sur la mise en place de la capture audio, voir les références.