middleware/Tracking/Gestures/CircleDetector.cs
changeset 15 4b78f179e7ce
child 17 fda26bfcabef
equal deleted inserted replaced
14:10d5199d9874 15:4b78f179e7ce
       
     1 /*
       
     2 * This file is part of the TraKERS\Middleware package.
       
     3 *
       
     4 * (c) IRI <http://www.iri.centrepompidou.fr/>
       
     5 *
       
     6 * For the full copyright and license information, please view the LICENSE_MIDDLEWARE
       
     7 * file that was distributed with this source code.
       
     8 */
       
     9 
       
    10 /*
       
    11  * Projet : TraKERS
       
    12  * Module : MIDDLEWARE
       
    13  * Sous-Module : Tracking/Gestures
       
    14  * Classe : CircleDetector
       
    15  * 
       
    16  * Auteur : alexandre.bastien@iri.centrepompidou.fr
       
    17  * 
       
    18  * Fonctionnalités : Permet de détecter si l'utilisateur a effectué un cercle, en se basant sur
       
    19  * des règles appliquées à la positions des noeuds dans le temps.
       
    20  */
       
    21 
       
    22 using System;
       
    23 using System.Collections.Generic;
       
    24 using System.Linq;
       
    25 using System.Text;
       
    26 using Microsoft.Kinect;
       
    27 using System.Windows.Media.Media3D;
       
    28 using System.Drawing;
       
    29 
       
    30 namespace Trakers.MainModule.Gestures
       
    31 {
       
    32     public class CircleDetector : GestureDetector
       
    33     {
       
    34         public CircleDetector() : base()
       
    35         {
       
    36             gesturePeriod = (float)1;
       
    37             indexesPerSecond = 30;
       
    38             indexesToCheck = (int)(gesturePeriod * indexesPerSecond);
       
    39         }
       
    40 
       
    41         /*
       
    42          * Lit les noeuds de l'historique du squelette afin de détecter un cercle.
       
    43          * Règles :
       
    44          * Se fait avec une main.
       
    45          * Chaque point est à la même distance du barycentre.
       
    46          * Traitement :
       
    47          * On .
       
    48          */
       
    49         public bool CheckForCircle()
       
    50         {
       
    51             //Crée un historique de squelette local, puisque l'historique est mis à jour toutes les ~1/30 s.
       
    52             List<List<Joint>> localHistory = new List<List<Joint>>(history);
       
    53 
       
    54             //Si il n'y a pas assez de positions dans l'historique local pour vérifier le geste.
       
    55             if (localHistory.Count < indexesToCheck + 1)
       
    56                 return false;
       
    57 
       
    58             //La distance de référence est ici la distance entre le milieu du dos et le milieu des épaules.
       
    59             refDistance = Math.Abs(localHistory[0][(int)JointType.Spine].Position.Y - localHistory[0][(int)JointType.ShoulderCenter].Position.Y);
       
    60             //On commence la position pour les indexesToCheck dernières postures (celle à l'index 0 étant la dernière).
       
    61             startPoint = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position;
       
    62 
       
    63             //Barycentres pour les mains.
       
    64             PointF leftBarycenter = new PointF(0, 0);
       
    65             PointF rightBarycenter = new PointF(0, 0);
       
    66             //Distances moyennes des points aux barycentres.
       
    67             float averageDistToLeftBarycenter = 0;
       
    68             float averageDistToRightBarycenter = 0;
       
    69 
       
    70             //Index du point de départ dans la détection.
       
    71             int beginIndex = localHistory.Count - indexesToCheck;
       
    72 
       
    73             //Calcul du barycentre de la main gauche.
       
    74             for (int i = beginIndex; i > 0; i--)
       
    75             {
       
    76                 leftBarycenter.X += localHistory[i][(int)JointType.HandLeft].Position.X;
       
    77                 leftBarycenter.Y += localHistory[i][(int)JointType.HandLeft].Position.Y;
       
    78             }
       
    79             leftBarycenter.X /= indexesToCheck;
       
    80             leftBarycenter.Y /= indexesToCheck;
       
    81 
       
    82             //Calcul du barycentre de la main droite.
       
    83             for (int i = beginIndex; i > 0; i--)
       
    84             {
       
    85                 rightBarycenter.X += localHistory[i][(int)JointType.HandRight].Position.X;
       
    86                 rightBarycenter.Y += localHistory[i][(int)JointType.HandRight].Position.Y;
       
    87             }
       
    88             rightBarycenter.X /= indexesToCheck;
       
    89             rightBarycenter.Y /= indexesToCheck;
       
    90 
       
    91             //Estimation de la distance moyenne d'un point au barycentre gauche.
       
    92             for (int i = beginIndex; i > 0; i--)
       
    93             {
       
    94                 float ptX = localHistory[i][(int)JointType.HandLeft].Position.X;
       
    95                 float ptY = localHistory[i][(int)JointType.HandLeft].Position.Y;
       
    96                 averageDistToLeftBarycenter += (float)Distance2D(ptX, leftBarycenter.X, ptY, leftBarycenter.Y);
       
    97             }
       
    98             averageDistToLeftBarycenter /= indexesToCheck;
       
    99 
       
   100             //Estimation de la distance moyenne d'un point au barycentre droit.
       
   101             for (int i = beginIndex; i > 0; i--)
       
   102             {
       
   103                 float ptX = localHistory[i][(int)JointType.HandRight].Position.X;
       
   104                 float ptY = localHistory[i][(int)JointType.HandRight].Position.Y;
       
   105                 averageDistToRightBarycenter += (float)Distance2D(ptX, rightBarycenter.X, ptY, rightBarycenter.Y);
       
   106             }
       
   107             averageDistToRightBarycenter /= indexesToCheck;
       
   108 
       
   109             //De la position p1 à pn, on suit l'algorithme.
       
   110             for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
       
   111             {
       
   112                 //Si la position Y de la main est plus haute que la tête
       
   113                 //OU si la position Y de la main est plus basse que la hanche
       
   114                 //OU si la nouvelle position X de la main est à droite de la précédente
       
   115                 //OU si la nouvelle position Y de la main est plus éloignée de la distance N par rapport à la première position Y
       
   116                 //Alors on retourne faux.
       
   117                 if (localHistory[i][(int)JointType.HandRight].Position.Y < localHistory[i][(int)JointType.Head].Position.Y ||
       
   118                 localHistory[i][(int)JointType.HandRight].Position.Y > localHistory[i][(int)JointType.HipCenter].Position.Y ||
       
   119                 localHistory[i][(int)JointType.HandRight].Position.X > localHistory[i - 1][(int)JointType.HandRight].Position.X ||
       
   120                 Math.Abs(localHistory[i][(int)JointType.HandRight].Position.Y - startPoint.Y) > refDistance / 2)
       
   121                     return false;
       
   122             }
       
   123 
       
   124             //Si la distance horizontale du geste a été plus courte que la distance N
       
   125             //Alors on retourne faux.
       
   126             if (Math.Abs(localHistory[0][(int)JointType.HandRight].Position.X - localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X) < refDistance / 2)
       
   127                 return false;
       
   128 
       
   129             //Si la dernière position de la main droite est sur le côté droit du corps
       
   130             //OU si la première position calculée de la main droite est sur le côté gauche du corps
       
   131             //Alors on retourne faux.
       
   132             if (localHistory[localHistory.Count - 1][(int)JointType.HandRight].Position.X > localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X ||
       
   133                localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X < localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X)
       
   134                 return false;
       
   135 
       
   136             //On supprime l'historique local.
       
   137             localHistory.Clear();
       
   138             //Si on est arrivé jusqu'ici, toutes les conditions pour un swipe left ont été remplies.
       
   139             return true;
       
   140         }
       
   141 
       
   142         public double Distance2D(float x1, float x2, float y1, float y2)
       
   143         {
       
   144             return Math.Sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
       
   145         }
       
   146     }
       
   147 }