Middleware :
User position events + detector (proximity).
More parameters, like proximity bounds.
/*
* Projet : TraKERS
* Module : MIDDLEWARE
* Sous-Module : Debug
* Classe : DebugWindow
*
* Auteur : alexandre.bastien@iri.centrepompidou.fr
*
* Fonctionnalités : Reçoit des notifications des sous-modules Tracking, Communication et Exception.
* Intéragit avec la fenêtre XAML de debug de façon à afficher un rendu visuel.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Drawing;
using System.Windows.Media.Media3D;
using Microsoft.Kinect;
using Coding4Fun.Kinect.Wpf;
using Trakers.Tracking;
using System.Threading;
using Trakers.Tracking.Events;
using Trakers.Tracking.Gestures;
using System.Resources;
using System.Reflection;
namespace Trakers.Debug
{
public partial class DebugWindow : Window
{
//Gestionnaire de ressources.
private ResourceManager rm;
//Membre permettant d'atteindre la classe KinectMain du sous-module Tracking.
private KinectMain kinectMain;
//Tableau contenant une image en couleurs.
private byte[] colorPixelData;
//Indique si la kinect est allumée/éteinte.
private bool on;
//Indique si la fenêtre de debug est actuellement en cours de fermeture.
private bool closing;
/*
* Constructeur : Affiche la fenêtre de debug en lui passant en paramètre une instanciation de la
* classe KinectMain.
* Au départ, la kinect est éteinte.
*/
public DebugWindow(KinectMain main)
{
rm = new ResourceManager("Trakers.Properties.resources", Assembly.GetExecutingAssembly());
InitializeComponent();
kinectMain = main;
on = false;
closing = false;
}
/*
* Getter pour le membre indiquant la fermeture de la fenêtre de debug.
*/
public bool isClosing()
{
return closing;
}
/*
* Est appelée à la fermeture de la fenêtre.
*/
private void Window_Closed(object sender, EventArgs e)
{
closing = true;
//On éteint la Kinect (pour éviter qu'elle reste allumée même lorsque le programme est éteint).
kinectMain.KinectClose();
}
/*
* Bouton ON/OFF.
*/
private void Switch_Click(object sender, RoutedEventArgs e)
{
//S'il valait faux, il vaut vrai maintenant et inversement.
on = !on;
//Si la kinect est allumée.
if (on)
{
//Il affiche OFF (pour éteindre la kinect).
Switch.Content = "OFF";
//On vide le label des exceptions.
ExceptionLbl.Content = "";
//On initialise la Kinect.
kinectMain.KinectInitialization();
}
else
{
//Il affiche ON (pour allumer la kinect).
Switch.Content = "ON";
//On remet à zéro tous les éléments du retour visuel.
R1.Fill = System.Windows.Media.Brushes.DarkGray;
R2.Fill = System.Windows.Media.Brushes.DarkGray;
R3.Fill = System.Windows.Media.Brushes.DarkGray;
R4.Fill = System.Windows.Media.Brushes.DarkGray;
DistanceLbl.Content = "Distance :";
LeftHand.Background = System.Windows.Media.Brushes.DarkGray;
LeftHand.Content = "";
RightHand.Background = System.Windows.Media.Brushes.DarkGray;
RightHand.Content = "";
DebugCanvas.Children.RemoveRange(1, DebugCanvas.Children.Count - 1);
//On éteint la Kinect.
kinectMain.KinectClose();
}
}
/*
* Récupère le flux video et met à jour le rendu visuel de debug.
*/
public void RefreshVideo(AllFramesReadyEventArgs e)
{
bool receivedData = false;
ColorImageFrame colorImageFrameData;
using (colorImageFrameData = e.OpenColorImageFrame())
{
//Si on ne reçoit pas de trames de la kinect.
if (colorImageFrameData == null)
{
//L'image est supprimée.
DebugImage.Source = null;
}
//Si le tableau stockant l'image en cours est nul.
if (colorPixelData == null)
//On alloue un nouveau tableau.
colorPixelData = new byte[colorImageFrameData.PixelDataLength];
else
{
//Sinon on met à jour le tableau en copiant le contenu de la trame dans le tableau.
colorImageFrameData.CopyPixelDataTo(colorPixelData);
receivedData = true;
}
}
//Si on a des données dans le tableau et que la kinect est allumée.
if (receivedData && on)
{
//Exemples de modifications de l'affichage :
//Zombies apocalypse.
//Black & White movie.
/*for (int i = 0; i < colorPixelData.Length; i += colorImageFrameData.BytesPerPixel)
{
byte gray = Math.Min(colorPixelData[i], colorPixelData[i + 1]);
gray = Math.Min(gray, colorPixelData[i + 2]);
colorPixelData[i] = gray;
colorPixelData[i + 1] = gray;
colorPixelData[i] = colorPixelData[i + 1];
colorPixelData[i + 1] = colorPixelData[i];
colorPixelData[i + 2] = (byte)~colorPixelData[i + 2];
}*/
//On met à jour l'image de la caméra.
DebugImage.Source = BitmapSource.Create(colorImageFrameData.Width, colorImageFrameData.Height, 96, 96, PixelFormats.Bgr32, null, colorPixelData, colorImageFrameData.Width * colorImageFrameData.BytesPerPixel);
DebugImage.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
DebugImage.VerticalAlignment = System.Windows.VerticalAlignment.Center;
DebugImage.Stretch = Stretch.Fill;
}
}
/*
* Affiche la distance de l'utilisateur dans le rendu visuel.
* Sous forme de nombre en m et de rectangles changeant de couleur en fonction de la distance.
*/
public void showDistance(float distance)
{
DistanceLbl.Content = "Distance : " + distance;
if (distance > 0 && distance < 1)
{
R1.Fill = System.Windows.Media.Brushes.Red;
R2.Fill = System.Windows.Media.Brushes.DarkGray;
R3.Fill = System.Windows.Media.Brushes.DarkGray;
R4.Fill = System.Windows.Media.Brushes.DarkGray;
}
else if (distance > 1 && distance < 2)
{
R1.Fill = System.Windows.Media.Brushes.DarkGray;
R2.Fill = System.Windows.Media.Brushes.Orange;
R3.Fill = System.Windows.Media.Brushes.DarkGray;
R4.Fill = System.Windows.Media.Brushes.DarkGray;
}
else if (distance > 2 && distance < 3)
{
R1.Fill = System.Windows.Media.Brushes.DarkGray;
R2.Fill = System.Windows.Media.Brushes.DarkGray;
R3.Fill = System.Windows.Media.Brushes.Yellow;
R4.Fill = System.Windows.Media.Brushes.DarkGray;
}
else if (distance > 3 && distance < 4)
{
R1.Fill = System.Windows.Media.Brushes.DarkGray;
R2.Fill = System.Windows.Media.Brushes.DarkGray;
R3.Fill = System.Windows.Media.Brushes.DarkGray;
R4.Fill = System.Windows.Media.Brushes.White;
}
}
public void showProximity(UserPositionEventArgs e)
{
}
/*
* Affiche la détection de la main droite via un label.
*/
public void showRightHandRect(bool show)
{
if (show)
RightHand.Background = System.Windows.Media.Brushes.Blue;
else
RightHand.Background = System.Windows.Media.Brushes.DarkGray;
}
/*
* Affiche la détection de la main gauche via un label.
*/
public void showLeftHandRect(bool show)
{
if (show)
LeftHand.Background = System.Windows.Media.Brushes.Blue;
else
LeftHand.Background = System.Windows.Media.Brushes.DarkGray;
}
/*
* Dessine les noeuds du squelette dans le rendu visuel.
*/
public void drawJoints(JointCollection joints, Skeleton first)
{
//On enlève tout élément du Canvas à part l'image, de manière à mettre à jour la position du squelette.
DebugCanvas.Children.RemoveRange(1, DebugCanvas.Children.Count - 1);
//Pour chaque noeud.
foreach (Joint joint in first.Joints)
{
//On crée une ellipse de taille 20 et de largeur 20.
Ellipse node = new Ellipse();
node.Height = 20;
node.Width = 20;
//S'il s'agit d'un noeud de tête, on le colorie en rouge, sinon en bleu.
if (joint.JointType == JointType.Head)
node.Fill = System.Windows.Media.Brushes.Red;
else if(joint.JointType == JointType.ShoulderCenter)
node.Fill = System.Windows.Media.Brushes.Green;
else if(joint.JointType == JointType.HipCenter)
node.Fill = System.Windows.Media.Brushes.Green;
else if (joint.JointType == JointType.HandRight)
node.Fill = System.Windows.Media.Brushes.Red;
else
node.Fill = System.Windows.Media.Brushes.Blue;
//On met à la bonne échelle les coordonnées des positions des noeuds.
Joint scaledJoint = Coding4Fun.Kinect.Wpf.SkeletalExtensions.ScaleTo(joint, 600, 400, 0.75f, 0.75f);
//On positionne le noeud dans le Canvas, et on l'ajoute.
Canvas.SetLeft(node, scaledJoint.Position.X);
Canvas.SetTop(node, scaledJoint.Position.Y);
DebugCanvas.Children.Add(node);
}
}
/*
* Dessine un os, en ayant en paramètres deux noeuds.
*/
public void drawBone(Joint j1, Joint j2)
{
//On crée une nouvelle ligne verte d'épaisseur 8 entre les deux noeuds et on l'ajoute au Canvas.
Line line = new Line();
line.Stroke = System.Windows.Media.Brushes.Green;
line.X1 = j1.Position.X;
line.X2 = j2.Position.X;
line.Y1 = j1.Position.Y;
line.Y2 = j2.Position.Y;
line.StrokeThickness = 8;
DebugCanvas.Children.Add(line);
ExceptionLbl.Content = DebugCanvas.Children.Count;
}
/*
* Dessine le squelette (ensemble des os), en ayant en paramètres tous les noeuds.
*/
public void showSkeleton(Joint hipCenter, Joint spine, Joint shoulderCenter, Joint head, Joint shoulderLeft, Joint elbowLeft, Joint wristLeft, Joint handLeft, Joint shoulderRight, Joint elbowRight, Joint wristRight, Joint handRight, Joint hipLeft, Joint kneeLeft, Joint ankleLeft, Joint footLeft, Joint hipRight, Joint kneeRight, Joint ankleRight, Joint footRight)
{
//On met les noeuds deux par deux en fonction de leur position dans le squelette.
drawBone(head, shoulderCenter);
drawBone(shoulderCenter, shoulderLeft);
drawBone(shoulderLeft, elbowLeft);
drawBone(elbowLeft, wristLeft);
drawBone(wristLeft, handLeft);
drawBone(shoulderCenter, shoulderRight);
drawBone(shoulderRight, elbowRight);
drawBone(elbowRight, wristRight);
drawBone(wristRight, handRight);
drawBone(shoulderCenter, spine);
drawBone(spine, hipCenter);
drawBone(hipCenter, hipLeft);
drawBone(hipLeft, kneeLeft);
drawBone(kneeLeft, ankleLeft);
drawBone(ankleLeft, footLeft);
drawBone(hipCenter, hipRight);
drawBone(hipRight, kneeRight);
drawBone(kneeRight, ankleRight);
drawBone(ankleRight, footRight);
}
/*
* Affiche la position de la main gauche dans le rendu visuel.
*/
public void showLeftHandCoord(String coord)
{
LeftHand.Content = coord;
}
/*
* Affiche la position de la main gauche dans le rendu visuel.
*/
public void showRightHandCoord(String coord)
{
RightHand.Content = coord;
}
public void showSwipe(SwipeEventArgs e)
{
if(e.direction == Tracking.Gestures.SwipeDetector.Direction.LEFT)
ExceptionLbl.Background = System.Windows.Media.Brushes.Red;
else if(e.direction == Tracking.Gestures.SwipeDetector.Direction.RIGHT)
ExceptionLbl.Background = System.Windows.Media.Brushes.Purple;
}
public void showPush(PushEventArgs e)
{
if (e.direction == Tracking.Gestures.PushDetector.Direction.PUSH)
{
if(e.hand == Tracking.Gestures.PushDetector.Hand.LEFT)
LeftHand.Background = System.Windows.Media.Brushes.White;
else if(e.hand == Tracking.Gestures.PushDetector.Hand.RIGHT)
RightHand.Background = System.Windows.Media.Brushes.White;
else
{
LeftHand.Background = System.Windows.Media.Brushes.White;
RightHand.Background = System.Windows.Media.Brushes.White;
}
}
else
{
if (e.hand == Tracking.Gestures.PushDetector.Hand.LEFT)
LeftHand.Background = System.Windows.Media.Brushes.Black;
else if (e.hand == Tracking.Gestures.PushDetector.Hand.RIGHT)
RightHand.Background = System.Windows.Media.Brushes.Black;
else
{
LeftHand.Background = System.Windows.Media.Brushes.Black;
RightHand.Background = System.Windows.Media.Brushes.Black;
}
}
}
/*
* Méthode associée à l'événement : Ouvrir la fenêtre de paramétrage via le menu.
*/
private void Parameters_Click(object sender, RoutedEventArgs e)
{
DebugParameters param = new DebugParameters(kinectMain);
try
{
param.ShowDialog();
}
catch (Exception)
{
ExceptionLbl.Content = rm.GetString("loadParamFail");
}
}
/*
* Méthode associée à l'événement : Quitter via le menu.
*/
private void Quit_Click(object sender, RoutedEventArgs e)
{
closing = true;
//On éteint la Kinect (pour éviter qu'elle reste allumée même lorsque le programme est éteint).
kinectMain.KinectClose();
Application.Current.Shutdown();
}
}
}