Kinect SDK 1.5 - Comprendre les différents flux de données

31. May 2012 17:05 by Renaud in   //  Tags:   //   Comments (0)

Dans cet article on va se représenter de manière simple les données brutes que l’on peut utiliser lorsque l’on travaille avec le SDK Kinect pour Windows (à l’exception du flux audio que l’on va un peu mettre de côté pour le moment).

Il est intéressant de parler de ces différents flux et des données qu’ils transportent pour bien pouvoir utiliser la Kinect.

Les 3 flux

La Kinect possède (pour faire simple et toujours en excluant la partie audio) deux sources de données :

  • Un capteur de couleur.
  • Un capteur infrarouge.

Ces capteurs vont permettre de retourner 3 flux de données, dont deux sont plutôt similaires :

Les deux premiers fournissent des images de la scène (j’appelle scène ce qui se trouve dans le champ de vision de la Kinect), décrites de différentes manières :

  • ColorImageStream : chaque pixel de l’image est défini par sa couleur
  • DepthImageStream : chaque pixel de l’image est défini par sa profondeur

Le dernier flux est un peu différent puisqu’il est généré à partir des données dont la Kinect dispose. Il s’agit du :

  • SkeletonStream : fournit des infos sur les utilisateurs détectés par la Kinect

Les 3 photographies (frames)

Chacun de ces flux va nous permettre d’obtenir des photographies de la scène à un instant T. Dans le SDK Kinect, on parle alors de frames. Sans surprise, on va trouver un type de frame correspondant à chaque flux précédemment cité :

  • ColorImageFrame
  • DepthImageFrame
  • SkeletonFrame

SkeletonFrame

On va commencer par le SkeletonFrame, qui est sans doute le plus simple à expliquer. Un SkeletonFrame possède quelques propriétés parmi lesquelles Timestamp qui indique sa date de création, FrameNumber qui l’identifie par un entier. On a également une indication de où se trouve le sol dans un espace à 3 dimensions, le TrackingMode utilisé (debout ou assis). Et pour finir, une propriété SkeletonArrayLength retourne le nombre maximal d’utilisateurs qui peuvent être détectés en même temps. Pour le moment, cette valeur sera en fait toujours égale à 6. La Kinect est en effet capable de détecter jusqu’à six personnes en même temps (mais seulement deux d’entre elles seront détaillées).

Cette dernière propriété n’est pas inutile, parce qu’elle nous renseigne en fait la quantité de données qui est contenue dans une frame. Et on va en avoir besoin pour pouvoir utiliser l’unique méthode propre à la classe SkeletonFrame :

public void CopySkeletonDataTo ( Skeleton[] skeletonData )

Cette méthode est la clé à cette étape du développement. Elle va permettre de copier les données contenues dans l’objet SkeletonFrame vers un tableau de Skeleton. Un tableau de Skeleton (skeletonData) doit être passé à la méthode pour être rempli avec les données, et ce tableau doit être initialisé à la bonne taille !

Une fois les données copiées, on pourra libérer l’objet SkeletonFrame et travailler sur la copie des données que nous venons de faire.

ColorImageFrame et DepthImageFrame

Ces deux-là, encore une fois, sont similaires. Et pour cause, ils héritent de la même classe de base : ImageFrame. Comme évoqué précédemment, ces deux frames vont définir un ensemble de pixels. Dans la classe ImageFrame, on retrouve des propriétés telles que Width (largeur de l’image), Height (hauteur de l’image), BytesPerPixel (nombre d’octets utilisés pour décrire un pixel).

Les classes ColorImageFrame et DepthImageFrame possèdent toutes deux une propriété Format respectivement de type ColorImageFormat et DepthImageFormat. Ces types sont en fait des énumérations, qui spécifient les différents formats. Les noms des différentes valeurs sont assez explicites :

ColorImageFormat.RawYuvResolution640x480Fps15 
 RgbResolution1280x960Fps12 
 RgbResolution640x480Fps30 
 YuvResolution640x480Fps15 
 Undefined

Le ColorImageFormat spécifie l’encodage (ex : Rgb), la résolution (ex :  640x480), et la fréquence (ex : Fps30).

DepthImageFormat.Resolution320x240Fps30
 Resolution640x480Fps30
 Resolution80x60Fps30
 Undefined

Par contre, le DepthImageFormat spécifie uniquement la résolution et la fréquence.

Ces propriétés décrivent donc ce que représentent les données contenues dans chacune des frames.

De la même manière que pour le SkeletonFrame, il existe pour ColorImageFrame et DepthImageFrame une méthode permettant de copier les données contenues vers un tableau afin de les utiliser par la suite, ainsi qu’une propriété indiquant la taille de ce tableau : PixelDataLength.

ColorImageFrame.CopyPixelDataTo (byte[] colorPixelData)

Pour le ColorImageFrame, on va copier les données dans un tableau de byte. Chaque pixel sera représenté par plusieurs bytes en fonction de l’encodage, et le nombre total de pixel variera en fonction du format, et donc de la résolution choisie.Par exemple, le format Rgb utilise 4 bytes pour représenter un pixel. Avec une résolution de 640x480, on aura donc : 640 x 480 x 4 = 1228800 bytes.

On peut donc comprendre que Width * Height * BytesPerPixel = PixelDataLength.

DepthImageFrame.CopyPixelDataTo (short[] depthPixelData)

Dans le cas de DepthImageFrame, les données seront copiées dans un tableau de short (des entiers codés sur 16 bits). Dans ce cas-ci, un pixel équivaut à un short.

Les données brutes

Maintenant que nous avons des copies des données représentant la scène à un instant T, il serait intéressant de savoir quoi en faire. Et pour cela, il faut également savoir ce que représentent exactement ces données.

SkeletonStream : Des squelettes représentés par un tableau de Skeleton

Pour le SkeletonStream, c’est assez simple : on récupère toujours un tableau de 6 objets de type Skeleton. Chacun d’eux a un statut (SkeletonTrackingState) indiquant si l’objet représente un utilisateur détecté, et s’il est entièrement suivi (SkeletonTrackingState.Tracked) ou si l’on ne connait que sa position globale (SkeletonTrackingState.PositionOnly).

La quantité est donc toujours la même, mais leur état peut varier en fonction de la scène.

DepthImageStream : Des distances représentées par un tableau de short

Au niveau du DepthImageStream, c’est un peu plus complexe. En effet, en fonction de la résolution choisir pour le flux, la quantité de données sera différentes.

Vous savez déjà que chaque short du tableau représente un pixel dans la frame. La position d’un pixel dans la frame est définie par son abscisse et son ordonnée (X et Y). Le point d’origine est le coin supérieur gauche (0, 0). X représente la colonne, et Y la ligne.

Dans le tableau de short, les pixels sont représentés les uns à la suite des autres :

(0  , 0),
(1  , 0),
(2  , 0),
 ...    ,
(639, 0),
(0  , 1),
(1  , 1),
…

Pour avoir la valeur en short du pixel de position (X, Y), il faut donc calculer comme ceci :

depthPixelData[Y * width + X]

Il reste encore une petite astuce : la valeur du short ne correspond pas directement à la distance que vous attendez. En fait, sur les 16 bits utilisés par le short, seuls 13 (ceux de poids fort) sont utilisés pour représenter la distance !

Les 3 bits de poids faible servent à indiquer si le pixel en question représente un utilisateur et, si oui, l’indice de celui-ci (de 1 à 6). Notez que pour espérer obtenir une valeur ici, vous devez activer le SkeletonStream. Dans le cas contraire, la valeur des 3 bits sera toujours 0, ce qui signifie qu’aucun utilisateur n’a été détecté à cet endroit.

Vous pouvez très simplement récupérer les valeurs qui vous intéressent en manipulant les bits comme ceci :

short depth = (short)(depthPixelData[i] >> DepthImageFrame.PlayerIndexBitmaskWidth);

short playerIndex = depthPixelData[i] & DepthImageFrame.PlayerIndexBitmask;

ColorImageStream : Des couleurs représentés par un tableau de bytes

Pour le ColorImageStream, le cas est encore un peu différent. Non seulement le nombre de pixels (et donc la quantité de données) peut varier comme pour le DepthImageStream, mais en plus la manière dont est représenté chaque pixel est différente en fonction du format !

Vous savez déjà que la propriété BytesPerPixel indique le nombre d’octets utilisés pour représenter un pixel. Encore faut-il savoir à quoi servent chacun de ces octets.

Dans une image de type Bgr, il faut compter 4 octets pour un pixel. Un octet pour le bleu, un octet pour le vert, et un octet pour le rouge. Le dernier octet est généralement utilisé pour le canal alpha, qui indique le niveau de transparence. On parle alors de BGRA. La Kinect ne gère pas la transparence, et ce dernier octet sera toujours à 0.

Pour le format RawYUV, chaque pixel est codé sur 2 octets. Pour une image ayant la même résolution, le tableau de bytes fera donc la moitié en taille par rapport à une frame encodée en Bgr !


J'espère que cet article vous aura permis d'y voir plus clair ! Et surtout n'hésitez pas à revenir ici pour parler des projets que vous réalisez ! :)

Meet Windows Azure - En live au MIC!

26. May 2012 19:05 by Renaud in   //  Tags:   //   Comments (0)

Si vous ne savez pas quoi faire le jeudi 7 juin au soir, rejoingnez-moi et d'autres développeurs au Microsoft Innovation Center à Mons pour suivre l'event sur un grand écran et en bonne compagnie ! C'est gratuit et juste pour le plaisir de partager et de rencontrer du monde. Inscrivez-vous ici: http://events.mic-belgique.be/event/meet-windows-azure-live

 

      Meet Windows Azure         

 Scott Guthrie        

 

Le jeudi 7 juin prochain, Scott "The Gu" Guthrie (l'un des piliers dans le monde des développeurs .NET) fera une session à San Francisco qui parlera de Windows Azure et des dernières technologies Cloud

Vous comptiez regarder la session seul chez vous?

Venez plutôt passer la soirée avec nous au MIC à Mons ! Ce sera une bonne occasion pour rencontrer d'autres développeurs, discuter des nouveautés, et grignoter ou boire un verre en regardant la session sur grand écran ;)

Plus d'info sur l'event en lui-même: http://www.meetwindowsazure.com/

Le streaming live débute à 22h (belgique), mais vous êtes les bienvenus avant !  

Kinect SDK 1.5 - What's new ?

23. May 2012 15:52 by Renaud in   //  Tags:   //   Comments (0)

The new Kinect SDK for Windows went out two days ago! If you didn't get it yet, you can download it here: http://www.microsoft.com/en-us/kinectforwindows/develop/developer-downloads.aspx.

The Kinect team made an amazing job for this release, and there is a lot of new stuff to discover !

Don't worry for your current projects: everything you've done so far and which is working with the 1.0 version will still work with the new release. Some processes are now more efficient, such as the mapping between depth and color data (for example if you want to create an app to remove the background behind a user). There are also new features: the seated mode which allows the Kinect to track only 10 joints of the superior part of the human body (head, arms, ...), tracking is available in near modespeech recognition in french, and you also have the possibility to use face tracking based on the Candide-3 model which allows you to get information about the shape of the user's face and the facial expressions.

I'll write more detailed blog posts about those new features in the coming days with code samples!

Kinect SDK 1.5 - Quoi de neuf?

23. May 2012 12:05 by Renaud in   //  Tags:   //   Comments (0)

La version 1.5 du SDK Kinect est sortie ce lundi 21 mai. Si vous ne l'avez pas encore, vous pouvez la télécharger ici: http://www.microsoft.com/en-us/kinectforwindows/develop/developer-downloads.aspx.

La team Kinect a fait un travail énorme pour cette release, et il y a beaucoup de nouveautés à découvrir !

Premièrement il faut savoir que tout ce qui a été fait avec le version 1.0 fonctionne toujours en 1.5 ! Certains process ont été améliorés comme par exemple le mapping entre les données de profondeurs et de couleur (qu'on utilise notamment si l'on veut isoler l'image d'un joueur, sans tenir compte du background). De nouvelles fonctionnalités sont apparues: le mode seated ("assis") qui permet de tracker seulement 10 joints de la partie supérieur du corps humain (la tête, le tronc et les bras), le tracking en near mode, la reconnaissance vocale en français, et également une reconnaissance faciale basée sur le modèle Candide-3 qui permet d'obtenir des infos sur la forme et les expressions du visage.

Je vous posterai des articles plus détaillés sur les nouveautés dans les jours qui viennent avec des exemples de code !

TextBox

About the author

I'm a developer, blog writer, and author, mainly focused on Microsoft technologies (but not only Smile). I'm Microsoft MVP Client Development since July 2013.

Microsoft Certified Professional

I'm currently working as an IT Evangelist with an awesome team at the Microsoft Innovation Center Belgique, where I spend time and energy helping people to develop their projects. I also give training to enthusiastic developers and organize afterworks with the help of the Belgian community.

MIC Belgique

Take a look at my first book (french only): Développez en HTML 5 pour Windows 8

Développez en HTML5 pour Windows 8

Membre de l'association Fier d'être développeur

TextBox

Month List