using Microsoft.Kinect; using System; using System.ComponentModel; using System.Globalization; using System.IO; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; namespace KinectConnection { /// /// Classe représentant un flux d'image de profondeur pour la Kinect. /// Étend la classe KinectStream. /// public class DepthImageStream : KinectStream { /// /// Constante pour mapper la plage de profondeur à la plage de byte. /// private const int MapDepthToByte = 8000 / 256; /// /// Reader pour les données /// private DepthFrameReader depthFrameReader = null; /// /// Description du cadre (hauteur/largeur) /// private FrameDescription depthFrameDescription = null; /// /// Le bitmap permettant d'afficher l'image /// private WriteableBitmap depthBitmap = null; /// /// Stockage intermediare des données avant de convertir en couleurs /// private byte[] depthPixels = null; /// /// Obtient la source d'image de la classe. /// public override ImageSource Source { get { return this.depthBitmap; } } /// /// Initialise une nouvelle instance de la classe DepthImageStream. /// public DepthImageStream() : base() { // get FrameDescription from DepthFrameSource this.depthFrameDescription = this.KinectSensor.DepthFrameSource.FrameDescription; // allocate space to put the pixels being received and converted this.depthPixels = new byte[this.depthFrameDescription.Width * this.depthFrameDescription.Height]; // create the bitmap to display this.depthBitmap = new WriteableBitmap(this.depthFrameDescription.Width, this.depthFrameDescription.Height, 96.0, 96.0, PixelFormats.Gray8, null); } /// /// Démarre la lecture du flux de profondeur. /// public override void Start() { if (this.KinectSensor != null) { // open the reader for the depth frames this.depthFrameReader = this.KinectSensor.DepthFrameSource.OpenReader(); if (this.depthFrameReader != null) { // wire handler for frame arrival this.depthFrameReader.FrameArrived += this.Reader_FrameArrived; } } } /// /// Arrête la lecture du flux de profondeur. /// public override void Stop() { if (this.depthFrameReader != null) { this.depthFrameReader.FrameArrived -= this.Reader_FrameArrived; // Dispose the reader to free resources. // If we don't dispose manualy, the gc will do it for us, but we don't know when. this.depthFrameReader.Dispose(); this.depthFrameReader = null; } } /// /// Méthode appelée lors de l'arrivée d'un nouveau frame de profondeur. /// /// object sending the event /// event arguments private void Reader_FrameArrived(object sender, DepthFrameArrivedEventArgs e) { bool depthFrameProcessed = false; using (DepthFrame depthFrame = e.FrameReference.AcquireFrame()) { if (depthFrame != null) { // the fastest way to process the body index data is to directly access // the underlying buffer using (Microsoft.Kinect.KinectBuffer depthBuffer = depthFrame.LockImageBuffer()) { // verify data and write the color data to the display bitmap if (((this.depthFrameDescription.Width * this.depthFrameDescription.Height) == (depthBuffer.Size / this.depthFrameDescription.BytesPerPixel)) && (this.depthFrameDescription.Width == this.depthBitmap.PixelWidth) && (this.depthFrameDescription.Height == this.depthBitmap.PixelHeight)) { // Note: In order to see the full range of depth (including the less reliable far field depth) // we are setting maxDepth to the extreme potential depth threshold ushort maxDepth = ushort.MaxValue; this.ProcessDepthFrameData(depthBuffer.UnderlyingBuffer, depthBuffer.Size, depthFrame.DepthMinReliableDistance, maxDepth); depthFrameProcessed = true; } } } } if (depthFrameProcessed) { this.RenderDepthPixels(); } } /// /// Accède directement au tampon d'image sous-jacent du DepthFrame /// pour créer une bitmap affichable. /// Cette méthode nécessite l'option du compilateur "/unsafe" pour avoir directement accès /// à la mémoire native pointée par le pointer depthFrameData. /// /// Pointeur vers la DepthFrame image data /// Taille de la DepthFrame image data /// La plus fiable valeur minimale pour la frame /// La plus fiable valeur maximale pour la frame private unsafe void ProcessDepthFrameData(IntPtr depthFrameData, uint depthFrameDataSize, ushort minDepth, ushort maxDepth) { // la donnée du dephtFrame est une valeur de 16 bits ushort* frameData = (ushort*)depthFrameData; // traduit la profondeur en une representation visuelle for (int i = 0; i < (int)(depthFrameDataSize / this.depthFrameDescription.BytesPerPixel); ++i) { // obtenir la profondeur d'un pixel ushort depth = frameData[i]; // Pour convertir en bytes on doit traduire la profondeur en bytes // Des valeurs qui n'est pas dans la portée valide on met 0 this.depthPixels[i] = (byte)(depth >= minDepth && depth <= maxDepth ? (depth / MapDepthToByte) : 0); } } /// /// Rend les pixels de profondeur dans la bitmap. /// private void RenderDepthPixels() { this.depthBitmap.WritePixels( new Int32Rect(0, 0, this.depthBitmap.PixelWidth, this.depthBitmap.PixelHeight), this.depthPixels, this.depthBitmap.PixelWidth, 0); } } }