middleware/src/Tracking/KinectMain.cs
changeset 0 6fefd4afe506
child 3 92f19af39024
equal deleted inserted replaced
-1:000000000000 0:6fefd4afe506
       
     1 /*
       
     2  * Projet : KINECT PROJECTS
       
     3  * Module : MIDDLEWARE
       
     4  * Sous-Module : Tracking
       
     5  * Classe : KinectMain
       
     6  * 
       
     7  * Auteur : alexandre.bastien@iri.centrepompidou.fr
       
     8  * 
       
     9  * Fonctionnalités : Récupère les trames de données de la Kinect, les squelettes détectés via le SDK 1.0 de Microsoft.
       
    10  * Interprète ces trames de façon à afficher le flux vidéo couleurs, et récupérer la distance de l'utilisateur et les
       
    11  * noeuds de son squelette. Lance des événements lorsque la main gauche/droite entre dans/quitte le champ.
       
    12  * Envoie des données au sous-module de debug de manière a afficher un retour visuel sur la position de l'utilisateur,
       
    13  * son squelette, la détection de ses mains.
       
    14  */
       
    15 
       
    16 using System;
       
    17 using System.Collections.Generic;
       
    18 using System.Linq;
       
    19 using System.Text;
       
    20 using System.Windows;
       
    21 using System.Windows.Controls;
       
    22 using System.Windows.Data;
       
    23 using System.Windows.Documents;
       
    24 using System.Windows.Input;
       
    25 using System.Windows.Media;
       
    26 using System.Windows.Media.Imaging;
       
    27 using System.Windows.Navigation;
       
    28 using System.Windows.Shapes;
       
    29 using System.Drawing;
       
    30 using System.Windows.Media.Media3D;
       
    31 using Microsoft.Kinect;
       
    32 
       
    33 using Coding4Fun.Kinect.Wpf;
       
    34 using System.ComponentModel;
       
    35 
       
    36 using Trakers.Debug;
       
    37 using Tuio;
       
    38 using Trakers.Communication;
       
    39 using System.IO;
       
    40 using Trakers.Tracking.Gestures;
       
    41 using Trakers.Tracking.Events;
       
    42 using System.Configuration;
       
    43 using Kinect.Toolbox;
       
    44 
       
    45 namespace Trakers.Tracking
       
    46 {
       
    47     //Il s'agit des fonctions permettant d'appeler les fonctions des événements Main droite/gauche entre/quitte le champ.
       
    48     public delegate void LeftHandTrackedHandler(object o, LeftHandTrackedEventArgs e);
       
    49     public delegate void RightHandTrackedHandler(object o, RightHandTrackedEventArgs e);
       
    50     public delegate void LeftHandQuitHandler(object o, LeftHandQuitEventArgs e);
       
    51     public delegate void RightHandQuitHandler(object o, RightHandQuitEventArgs e);
       
    52     //Il s'agit des fonctions permettant d'appeler les fonctions des événements Swipe left/right/up/down.
       
    53     public delegate void SwipeHandler(object o, SwipeEventArgs e);
       
    54 
       
    55     public class KinectMain
       
    56     {
       
    57         //Fenêtre de debug.
       
    58         private Debug.DebugWindow debug;
       
    59         //Squelettes (Il y en a 6 par défaut).
       
    60         private Skeleton[] skeletons;
       
    61         //Caméra infrarouge (sensor) de la Kinect.
       
    62         private KinectSensor kinectSensor;
       
    63 
       
    64         //Détecteur de gestes.
       
    65         private SwipeDetector swipeDetector;
       
    66 
       
    67         //Distances min/max délimitant le champ de recherche.
       
    68         private float minDistHands;
       
    69         private float maxDistHands;
       
    70 
       
    71         //Serveur TUIO pour la connexion du Middleware vers le Front Atelier.
       
    72         private Server server;
       
    73 
       
    74         //Les événements des mains pour la recherche.
       
    75         public static event LeftHandTrackedHandler LeftHandTrackedEvent;
       
    76         public static event RightHandTrackedHandler RightHandTrackedEvent;
       
    77         public static event LeftHandQuitHandler LeftHandQuitEvent;
       
    78         public static event RightHandQuitHandler RightHandQuitEvent;
       
    79         //Les événements swipe.
       
    80         public static event SwipeHandler SwipeEvent;
       
    81             
       
    82         //Voici les ID des noeuds d'un squelette.
       
    83         private int hipCenterID = 0, spineID = 1, shoulderCenterID = 2, headID = 3;
       
    84         private int shoulderLeftID = 4, elbowLeftID = 5, wristLeftID = 6, handLeftID = 7;
       
    85         private int shoulderRightID = 8, elbowRightID = 9, wristRightID = 10, handRightID = 11;
       
    86         private int hipLeftID = 12, kneeLeftID = 13, ankleLeftID = 14, footLeftID = 15;
       
    87         private int hipRightID = 16, kneeRightID = 17, ankleRightID = 18, footRightID = 19;
       
    88 
       
    89         /*
       
    90         *  Initialisation de la classe principale.
       
    91         *  Affiche l'écran de debug dans lequel on voit la distance à la Kinect,
       
    92         *  les mains détectées et le squelette de l'utilisateur.
       
    93         */
       
    94         public KinectMain()
       
    95         {
       
    96             //On crée la fenêtre de debug.
       
    97             debug = new Debug.DebugWindow(this);
       
    98             
       
    99             //On crée le détecteur de gestes.
       
   100             swipeDetector = new SwipeDetector();
       
   101 
       
   102             //On tente de charger les paramètres du fichier params.ini.
       
   103             //Si on n'y arrive pas, on affiche une erreur et on charge les paramètres par défaut.
       
   104             if (!loadParameters())
       
   105             {
       
   106                 debug.ExceptionLbl.Content = "Impossible de charger les paramètres. Paramètres par défaut.";
       
   107                 //Distances de détection des mains par défaut pour la recherche (ici de 1m à 2m de la Kinect).
       
   108                 minDistHands = (float)1.0;
       
   109                 maxDistHands = (float)1.5;
       
   110             }
       
   111             else if (maxDistHands <= 0 || minDistHands <= 0 || maxDistHands > 4 || minDistHands > 4 || minDistHands >= maxDistHands)
       
   112             {
       
   113                 debug.ExceptionLbl.Content = "Paramètres incorrects. Paramètres par défaut.";
       
   114                 //Distances de détection des mains par défaut pour la recherche (ici de 1m à 2m de la Kinect).
       
   115                 minDistHands = (float)1.0;
       
   116                 maxDistHands = (float)1.5;
       
   117             }
       
   118 
       
   119             //On affiche la fenêtre de debug.
       
   120             try
       
   121             {
       
   122                 debug.ShowDialog();
       
   123             }
       
   124             catch(Exception){}
       
   125         }
       
   126 
       
   127         /*
       
   128         *  Initialisation du sensor de la Kinect.
       
   129         */
       
   130         public void KinectInitialization()
       
   131         {
       
   132             try
       
   133             {
       
   134                 //On sélectionne la première kinect détectée.
       
   135                 kinectSensor = KinectSensor.KinectSensors.FirstOrDefault(s => s.Status == KinectStatus.Connected);
       
   136                 //La caméra couleur est activée avec une résolution 640x480 et un framerate de 30 FPS.
       
   137                 kinectSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
       
   138                 //La caméra de profondeur est activée.
       
   139                 kinectSensor.DepthStream.Enable();
       
   140                 //Le squelette est activé.
       
   141                 kinectSensor.SkeletonStream.Enable();
       
   142 
       
   143                 //Quand le Middleware reçoit des trames de la Kinect, on va dans cette fonction.
       
   144                 kinectSensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(AllFramesReady);
       
   145 
       
   146                 //On démarre la Kinect.
       
   147                 kinectSensor.Start();
       
   148                 debug.ExceptionLbl.Content = "";
       
   149             }
       
   150             catch (System.Exception)
       
   151             {
       
   152                 debug.ExceptionLbl.Content = "Kinect non connectée.";
       
   153             }
       
   154 
       
   155             //Pour les événements main gauche/droite entre dans/quitte le champ, on a 4 listeners.
       
   156             //Fonction appelée lorsque la main gauche entre dans le champ de recherche.
       
   157             LeftHandTrackedListener leftHandTrackedListener = new LeftHandTrackedListener();
       
   158             LeftHandTrackedEvent += new LeftHandTrackedHandler(leftHandTrackedListener.ShowOnScreen);
       
   159 
       
   160             //Fonction appelée lorsque la main droite entre dans le champ de recherche.
       
   161             RightHandTrackedListener rightHandTrackedListener = new RightHandTrackedListener();
       
   162             RightHandTrackedEvent += new RightHandTrackedHandler(rightHandTrackedListener.ShowOnScreen);
       
   163 
       
   164             //Fonction appelée lorsque la main gauche quitte le champ de recherche.
       
   165             LeftHandQuitListener leftHandQuitListener = new LeftHandQuitListener();
       
   166             LeftHandQuitEvent += new LeftHandQuitHandler(leftHandQuitListener.ShowOnScreen);
       
   167 
       
   168             //Fonction appelée lorsque la main droite quitte le champ de recherche.
       
   169             RightHandQuitListener rightHandQuitListener = new RightHandQuitListener();
       
   170             RightHandQuitEvent += new RightHandQuitHandler(rightHandQuitListener.ShowOnScreen);
       
   171 
       
   172             //Fonction appelée lorsque l'utilisateur effectue un swipe right.
       
   173             SwipeEventListener swipeListener = new SwipeEventListener();
       
   174             SwipeEvent += new SwipeHandler(swipeListener.ShowOnScreen);
       
   175 
       
   176             //On connecte le serveur à l'adresse locale sur le port 80.
       
   177             server = new Server("127.0.0.1", 80);
       
   178         }
       
   179 
       
   180         /*
       
   181         *  Fermeture du sensor de la Kinect.
       
   182         */
       
   183         public void KinectClose()
       
   184         {
       
   185             try
       
   186             {
       
   187                 //On stoppe la Kinect.
       
   188                 kinectSensor.Stop();
       
   189                 //On met a zero l'image d'affichage et le serveur.
       
   190                 debug.DebugImage.Source = null;
       
   191                 //server = null;
       
   192                 debug.ExceptionLbl.Content = "";
       
   193             }
       
   194             catch (System.Exception)
       
   195             {
       
   196                 debug.ExceptionLbl.Content = "Kinect non connectée.";
       
   197             }
       
   198         }
       
   199 
       
   200         /*
       
   201         *  Récupère le premier squelette.
       
   202         */
       
   203         Skeleton GetFirstSkeleton(AllFramesReadyEventArgs e)
       
   204         {
       
   205             using (SkeletonFrame skeletonFrameData = e.OpenSkeletonFrame())
       
   206             {
       
   207                 if (skeletonFrameData == null)
       
   208                     return null;
       
   209                 if ((skeletons == null) || (skeletons.Length != skeletonFrameData.SkeletonArrayLength))
       
   210                     skeletons = new Skeleton[skeletonFrameData.SkeletonArrayLength];
       
   211                 skeletonFrameData.CopySkeletonDataTo(skeletons);
       
   212 
       
   213                 //On obtient le premier skelette.
       
   214                 Skeleton first = (from s in skeletons where s.TrackingState == SkeletonTrackingState.Tracked select s).FirstOrDefault();
       
   215 
       
   216                 return first;
       
   217             }
       
   218         }
       
   219 
       
   220         /*
       
   221         *  Récupère le squelette le plus proche.
       
   222         */
       
   223         Skeleton GetNearestSkeleton(AllFramesReadyEventArgs e)
       
   224         {
       
   225             using (SkeletonFrame skeletonFrameData = e.OpenSkeletonFrame())
       
   226             {
       
   227                 if (skeletonFrameData == null)
       
   228                     return null;
       
   229                 if ((skeletons == null) || (skeletons.Length != skeletonFrameData.SkeletonArrayLength))
       
   230                     skeletons = new Skeleton[skeletonFrameData.SkeletonArrayLength];
       
   231                 skeletonFrameData.CopySkeletonDataTo(skeletons);
       
   232 
       
   233                 Skeleton s;
       
   234                 float minDist = (float)-1.0;
       
   235                 int minID = 0;
       
   236                     
       
   237                 //Pour tous les squelettes.
       
   238                 for(int i = 0 ; i < skeletons.Count() ; i++)
       
   239                 {
       
   240                     s = skeletons.ElementAt(i);
       
   241                     //S'il est tracké.
       
   242                     if(s.TrackingState == SkeletonTrackingState.Tracked)
       
   243                     {
       
   244                         //On récupère sa position et on obtient la distance min et l'ID du squelette qui est à la distance min.
       
   245                         float dist = skeletons.ElementAt(i).Position.Z;
       
   246                         if (minDist == -1)
       
   247                         {
       
   248                             minDist = dist;
       
   249                             minID = i;
       
   250                         }
       
   251                         else if(minDist > dist)
       
   252                         {
       
   253                             minDist = dist;
       
   254                             minID = i;
       
   255                         }
       
   256                     }
       
   257                 }
       
   258 
       
   259                 //On renvoie le skelette le plus proche.
       
   260                 return skeletons.ElementAt(minID);
       
   261             }
       
   262         }
       
   263 
       
   264         /*
       
   265         *  Récupère le squelette le plus proche.
       
   266         */
       
   267         private void AllFramesReady(object sender, AllFramesReadyEventArgs e)
       
   268         {
       
   269             //On ne calcule rien si la fenêtre de debug se ferme.
       
   270             if (debug.isClosing())
       
   271                 return;
       
   272 
       
   273             //On met à jour la vidéo de debug.
       
   274             debug.RefreshVideo(e);
       
   275             //On récupère le premier squelette tracké.
       
   276             //Skeleton first = GetFirstSkeleton(e);
       
   277             //On récupère le plus proche squelette tracké.
       
   278             Skeleton first = GetNearestSkeleton(e);
       
   279             //Si celui-ci n’est pas nul
       
   280             if (first == null)
       
   281                 return;
       
   282 
       
   283             //Si ce squelette est tracké (donc suivi et reconnu par la camera)
       
   284             if (first.TrackingState == SkeletonTrackingState.Tracked)
       
   285             {
       
   286                 //Ensemble des noeuds du squelette.
       
   287                 Joint hipCenter = getJoint(first, hipCenterID), spine = getJoint(first, spineID), shoulderCenter = getJoint(first, shoulderCenterID), head = getJoint(first, headID);
       
   288                 Joint shoulderLeft = getJoint(first, shoulderLeftID), elbowLeft = getJoint(first, elbowLeftID), wristLeft = getJoint(first, wristLeftID), handLeft = getJoint(first, handLeftID);
       
   289                 Joint shoulderRight = getJoint(first, shoulderRightID), elbowRight = getJoint(first, elbowRightID), wristRight = getJoint(first, wristRightID), handRight = getJoint(first, handRightID);
       
   290                 Joint hipLeft = getJoint(first, hipLeftID), kneeLeft = getJoint(first, kneeLeftID), ankleLeft = getJoint(first, ankleLeftID), footLeft = getJoint(first, footLeftID);
       
   291                 Joint hipRight = getJoint(first, hipRightID), kneeRight = getJoint(first, kneeRightID), ankleRight = getJoint(first, ankleRightID), footRight = getJoint(first, footRightID);
       
   292 
       
   293                 //On construit l'historique des postures.
       
   294                 /*List<Joint> joints = new List<Joint>();
       
   295                 joints.Clear();
       
   296                 joints.Add(footRight);
       
   297                 joints.Add(ankleRight);
       
   298                 joints.Add(kneeRight);
       
   299                 joints.Add(hipRight);
       
   300                 joints.Add(footLeft);
       
   301                 joints.Add(ankleLeft);
       
   302                 joints.Add(kneeLeft);
       
   303                 joints.Add(hipLeft);
       
   304                 joints.Add(handRight);
       
   305                 joints.Add(wristRight);
       
   306                 joints.Add(elbowRight);
       
   307                 joints.Add(shoulderRight);
       
   308                 joints.Add(handLeft);
       
   309                 joints.Add(wristLeft);
       
   310                 joints.Add(elbowLeft);
       
   311                 joints.Add(shoulderLeft);
       
   312                 joints.Add(head);
       
   313                 joints.Add(shoulderCenter);
       
   314                 joints.Add(spine);
       
   315                 joints.Add(hipCenter);
       
   316                 swipeDetector.UpdateSkeletonHistory(joints);*/
       
   317 
       
   318                 SkeletonDisplayManager sdm = new SkeletonDisplayManager(kinectSensor, debug.DebugCanvas);
       
   319                 //sdm.Draw();
       
   320 
       
   321                 //On obtient sa distance à la Kinect.
       
   322                 float distance = first.Position.Z;
       
   323 
       
   324                 //On affiche la distance dans le debug.
       
   325                 debug.showDistance(distance);
       
   326 
       
   327                 //Si la main gauche est dans le champ, on lance l'événement approprié.
       
   328                 if (handLeft.Position.Z < maxDistHands && handLeft.Position.Z > minDistHands)
       
   329                 {
       
   330                     LeftHandTrackedEventArgs leftHandTrackedEvent = new LeftHandTrackedEventArgs(handLeft, handLeft.Position.Z, debug, server);
       
   331                     OnLeftHandTrackedEvent(leftHandTrackedEvent);
       
   332                 }
       
   333                 //Si la main gauche quitte le champ, on lance l'événement approprié.
       
   334                 else
       
   335                 {
       
   336                     LeftHandQuitEventArgs leftHandQuitEvent = new LeftHandQuitEventArgs(handLeft, handLeft.Position.Z, debug, server);
       
   337                     OnLeftHandQuitEvent(leftHandQuitEvent);
       
   338                 }
       
   339                 //Si la main droite est dans le champ, on lance l'événement approprié.
       
   340                 if (handRight.Position.Z < maxDistHands && handRight.Position.Z > minDistHands)
       
   341                 {
       
   342                     RightHandTrackedEventArgs rightHandTrackedEvent = new RightHandTrackedEventArgs(handRight, handRight.Position.Z, debug, server);
       
   343                     OnRightHandTrackedEvent(rightHandTrackedEvent);
       
   344                 }
       
   345                 //Si la main droite quitte le champ, on lance l'événement approprié.
       
   346                 else
       
   347                 {
       
   348                     RightHandQuitEventArgs rightHandQuitEvent = new RightHandQuitEventArgs(handRight, handRight.Position.Z, debug, server);
       
   349                     OnRightHandQuitEvent(rightHandQuitEvent);
       
   350                 }
       
   351                 
       
   352                 //Si l'utilisateur effectue un swipe left.
       
   353                 if (swipeDetector.CheckForSwipeLeft())
       
   354                 {
       
   355                     SwipeEventArgs swipeEvent = new SwipeEventArgs(debug, server, SwipeDetector.Direction.LEFT);
       
   356                     OnSwipeEvent(swipeEvent);
       
   357                 }
       
   358 
       
   359 
       
   360                 //Dessine le squelette dans le debug.
       
   361                 //debug.drawJoints(first.Joints, first);
       
   362                 //debug.showSkeleton(hipCenter, spine, shoulderCenter, head, shoulderLeft, elbowLeft, wristLeft, handLeft, shoulderRight, elbowRight, wristRight, handRight, hipLeft, kneeLeft, ankleLeft, footLeft, hipRight, kneeRight, ankleRight, footRight);
       
   363             }
       
   364         }
       
   365 
       
   366         /*
       
   367         *  Change l'échelle des coordonnées d'un noeud pour qu'en X et Y il corresponde à la résolution et en Z à la distance à la Kinect.
       
   368         */
       
   369         public Joint getJoint(Skeleton ske, int jointID)
       
   370         {
       
   371             return Coding4Fun.Kinect.Wpf.SkeletalExtensions.ScaleTo(ske.Joints.ElementAt(jointID), 600, 400, 0.75f, 0.75f);
       
   372         }
       
   373 
       
   374         /*
       
   375         *  Initialise l'événement et fait appel aux fonctions du listener quand la main gauche entre dans le champ.
       
   376         */
       
   377         public static void OnLeftHandTrackedEvent(LeftHandTrackedEventArgs e)
       
   378         {
       
   379             if (LeftHandTrackedEvent != null)
       
   380                 LeftHandTrackedEvent(new object(), e);
       
   381         }
       
   382 
       
   383         /*
       
   384         *  Initialise l'événement et fait appel aux fonctions du listener quand la main droite entre dans le champ.
       
   385         */
       
   386         public static void OnRightHandTrackedEvent(RightHandTrackedEventArgs e)
       
   387         {
       
   388             if (RightHandTrackedEvent != null)
       
   389                 RightHandTrackedEvent(new object(), e);
       
   390         }
       
   391 
       
   392         /*
       
   393         *  Initialise l'événement et fait appel aux fonctions du listener quand la main gauche quitte le champ.
       
   394         */
       
   395         public static void OnLeftHandQuitEvent(LeftHandQuitEventArgs e)
       
   396         {
       
   397             if (LeftHandQuitEvent != null)
       
   398                 LeftHandQuitEvent(new object(), e);
       
   399         }
       
   400 
       
   401         /*
       
   402         *  Initialise l'événement et fait appel aux fonctions du listener quand la main droite quitte le champ.
       
   403         */
       
   404         public static void OnRightHandQuitEvent(RightHandQuitEventArgs e)
       
   405         {
       
   406             if (RightHandQuitEvent != null)
       
   407                 RightHandQuitEvent(new object(), e);
       
   408         }
       
   409 
       
   410         /*
       
   411         *  Initialise l'événement et fait appel aux fonctions du listener quand l'utilisateur effectue un swipe right.
       
   412         */
       
   413         public static void OnSwipeEvent(SwipeEventArgs e)
       
   414         {
       
   415             if (SwipeEvent != null)
       
   416                 SwipeEvent(new object(), e);
       
   417         }
       
   418 
       
   419         /*
       
   420         *  Initialise l'événement et fait appel aux fonctions du listener quand l'utilisateur effectue un swipe up.
       
   421         */
       
   422         /*public static void OnSwipeUpEvent(SwipeUpEventArgs e)
       
   423         {
       
   424             if (SwipeUpEvent != null)
       
   425                 SwipeUpEvent(new object(), e);
       
   426         }*/
       
   427 
       
   428         /*
       
   429         *  Initialise l'événement et fait appel aux fonctions du listener quand l'utilisateur effectue un swipe down.
       
   430         */
       
   431         /*public static void OnSwipeDownEvent(SwipeDownEventArgs e)
       
   432         {
       
   433             if (SwipeDownEvent != null)
       
   434                 SwipeDownEvent(new object(), e);
       
   435         }*/
       
   436 
       
   437         /*
       
   438         *  Méthode de chargement des paramètres (position du champ de recherche...).
       
   439         */
       
   440         public bool loadParameters()
       
   441         {
       
   442             try
       
   443             {
       
   444                 minDistHands = float.Parse(ConfigurationManager.AppSettings["searchMinDistance"]);
       
   445                 maxDistHands = float.Parse(ConfigurationManager.AppSettings["searchMaxDistance"]);
       
   446             }
       
   447             catch (Exception)
       
   448             {
       
   449                 return false;
       
   450             }
       
   451 
       
   452             return true;
       
   453         }
       
   454     }
       
   455 }