middleware/Tracking/Gestures/CircleDetector.cs
changeset 17 fda26bfcabef
parent 15 4b78f179e7ce
child 27 6c08d4d7219e
equal deleted inserted replaced
16:a9ebacd6c089 17:fda26bfcabef
    24 using System.Linq;
    24 using System.Linq;
    25 using System.Text;
    25 using System.Text;
    26 using Microsoft.Kinect;
    26 using Microsoft.Kinect;
    27 using System.Windows.Media.Media3D;
    27 using System.Windows.Media.Media3D;
    28 using System.Drawing;
    28 using System.Drawing;
    29 
    29 using Trakers.Debug;
    30 namespace Trakers.MainModule.Gestures
    30 
       
    31 namespace Trakers.Tracking.Gestures
    31 {
    32 {
    32     public class CircleDetector : GestureDetector
    33     public class CircleDetector : GestureDetector
    33     {
    34     {
    34         public CircleDetector() : base()
    35         public CircleDetector(DebugWindow _debug) : base(_debug)
    35         {
    36         {
    36             gesturePeriod = (float)1;
    37             gesturePeriod = (float)1;
    37             indexesPerSecond = 30;
    38             indexesPerSecond = 30;
    38             indexesToCheck = (int)(gesturePeriod * indexesPerSecond);
    39             indexesToCheck = (int)(gesturePeriod * indexesPerSecond);
    39         }
    40         }
    41         /*
    42         /*
    42          * Lit les noeuds de l'historique du squelette afin de détecter un cercle.
    43          * Lit les noeuds de l'historique du squelette afin de détecter un cercle.
    43          * Règles :
    44          * Règles :
    44          * Se fait avec une main.
    45          * Se fait avec une main.
    45          * Chaque point est à la même distance du barycentre.
    46          * Chaque point est à la même distance du barycentre.
    46          * Traitement :
    47          * On regarde pour la main gauche.
    47          * On .
       
    48          */
    48          */
    49         public bool CheckForCircle()
    49         public bool CheckForLeftCircle()
    50         {
    50         {
       
    51             //Indique si la main gauche a décrit un cercle.
       
    52             bool leftHandDoCircle = true;
       
    53             
    51             //Crée un historique de squelette local, puisque l'historique est mis à jour toutes les ~1/30 s.
    54             //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);
    55             List<List<Joint>> localHistory = new List<List<Joint>>(history);
    53 
    56 
    54             //Si il n'y a pas assez de positions dans l'historique local pour vérifier le geste.
    57             //Si il n'y a pas assez de positions dans l'historique local pour vérifier le geste.
    55             if (localHistory.Count < indexesToCheck + 1)
    58             if (localHistory.Count < indexesToCheck + 1)
    56                 return false;
    59                 return false;
    57 
    60 
    58             //La distance de référence est ici la distance entre le milieu du dos et le milieu des épaules.
    61             //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);
    62             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).
    63             //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;
    64             SkeletonPoint startPointLeft = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position;
    62 
    65             
    63             //Barycentres pour les mains.
    66             //Barycentres pour les mains.
    64             PointF leftBarycenter = new PointF(0, 0);
    67             PointF leftBarycenter = new PointF(0, 0);
    65             PointF rightBarycenter = new PointF(0, 0);
       
    66             //Distances moyennes des points aux barycentres.
    68             //Distances moyennes des points aux barycentres.
    67             float averageDistToLeftBarycenter = 0;
    69             float averageDistToLeftBarycenter = 0;
    68             float averageDistToRightBarycenter = 0;
    70             
    69 
       
    70             //Index du point de départ dans la détection.
    71             //Index du point de départ dans la détection.
    71             int beginIndex = localHistory.Count - indexesToCheck;
    72             int beginIndex = localHistory.Count - indexesToCheck;
    72 
    73 
    73             //Calcul du barycentre de la main gauche.
    74             //Calcul du barycentre de la main gauche.
    74             for (int i = beginIndex; i > 0; i--)
    75             for (int i = beginIndex; i > 0; i--)
    76                 leftBarycenter.X += localHistory[i][(int)JointType.HandLeft].Position.X;
    77                 leftBarycenter.X += localHistory[i][(int)JointType.HandLeft].Position.X;
    77                 leftBarycenter.Y += localHistory[i][(int)JointType.HandLeft].Position.Y;
    78                 leftBarycenter.Y += localHistory[i][(int)JointType.HandLeft].Position.Y;
    78             }
    79             }
    79             leftBarycenter.X /= indexesToCheck;
    80             leftBarycenter.X /= indexesToCheck;
    80             leftBarycenter.Y /= indexesToCheck;
    81             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 
    82 
    91             //Estimation de la distance moyenne d'un point au barycentre gauche.
    83             //Estimation de la distance moyenne d'un point au barycentre gauche.
    92             for (int i = beginIndex; i > 0; i--)
    84             for (int i = beginIndex; i > 0; i--)
    93             {
    85             {
    94                 float ptX = localHistory[i][(int)JointType.HandLeft].Position.X;
    86                 float ptX = localHistory[i][(int)JointType.HandLeft].Position.X;
    95                 float ptY = localHistory[i][(int)JointType.HandLeft].Position.Y;
    87                 float ptY = localHistory[i][(int)JointType.HandLeft].Position.Y;
    96                 averageDistToLeftBarycenter += (float)Distance2D(ptX, leftBarycenter.X, ptY, leftBarycenter.Y);
    88                 averageDistToLeftBarycenter += (float)Distance2D(ptX, leftBarycenter.X, ptY, leftBarycenter.Y);
    97             }
    89             }
    98             averageDistToLeftBarycenter /= indexesToCheck;
    90             averageDistToLeftBarycenter /= indexesToCheck;
    99 
    91 
       
    92             //Pour les points, on suit l'algorithme.
       
    93 
       
    94             //Si la distance moyenne de chaque point de la main gauche au barycentre gauche est trop faible
       
    95             //Alors la main gauche n'a pas décrit de cercle.
       
    96             if (averageDistToLeftBarycenter < refDistance / 2)
       
    97                 leftHandDoCircle = false;
       
    98 
       
    99             //Indique si on a atteint le point d'arrivée pour la main gauche.
       
   100             bool endLeftReached = false;
       
   101 
       
   102             if(leftHandDoCircle)
       
   103                 for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
       
   104                 {
       
   105                     //Si la distance d'un point de la main gauche excède à la distance moyenne au barycentre gauche avec une erreur N
       
   106                     //OU si le point de départ de la main gauche est plus éloigné du point d'arrivée de la main gauche de N.
       
   107                     //Alors la main gauche n'a pas décrit de cercle.
       
   108                     float X = localHistory[i][(int)JointType.HandLeft].Position.X;
       
   109                     float Y = localHistory[i][(int)JointType.HandLeft].Position.Y;
       
   110 
       
   111                     //Si un point est proche du point de départ.
       
   112                     if(Distance2D(X, Y, startPointLeft.X, startPointLeft.Y) < refDistance / 5 && X != startPointLeft.X && Y != startPointLeft.Y)
       
   113                         endLeftReached = true;
       
   114 
       
   115                     if (Math.Abs((double)Distance2D(X, Y, leftBarycenter.X, leftBarycenter.Y) - averageDistToLeftBarycenter) > refDistance / 5)
       
   116                     {
       
   117                         leftHandDoCircle = false;
       
   118                         break;
       
   119                     }
       
   120 
       
   121                     //Si la main gauche a atteint une position proche de son point de départ.
       
   122                     if (endLeftReached)
       
   123                     {
       
   124                         //S'il y a trop peu de points
       
   125                         if (i - (localHistory.Count - indexesToCheck + 1) < (indexesToCheck / 2))
       
   126                             leftHandDoCircle = false;
       
   127                         break;
       
   128                     }
       
   129                 }
       
   130 
       
   131             //On supprime l'historique local.
       
   132             localHistory.Clear();
       
   133             //Si on est arrivé jusqu'ici, toutes les conditions pour un swipe left ont été remplies.
       
   134             return leftHandDoCircle;
       
   135         }
       
   136 
       
   137         /*
       
   138          * Lit les noeuds de l'historique du squelette afin de détecter un cercle.
       
   139          * Règles :
       
   140          * Se fait avec une main.
       
   141          * Chaque point est à la même distance du barycentre.
       
   142          * On regarde pour la main droite.
       
   143          */
       
   144         public bool CheckForRightCircle()
       
   145         {
       
   146             //Indique si la main droite a décrit un cercle.
       
   147             bool rightHandDoCircle = true;
       
   148 
       
   149             //Crée un historique de squelette local, puisque l'historique est mis à jour toutes les ~1/30 s.
       
   150             List<List<Joint>> localHistory = new List<List<Joint>>(history);
       
   151 
       
   152             //if (Math.Abs(Math.Abs(localHistory[0][(int)JointType.HandLeft].Position.X - localHistory[0][(int)JointType.HandRight].Position.X) - refDistance) < 10)
       
   153               //  Console.Out.WriteLine("REF");
       
   154 
       
   155             //Si il n'y a pas assez de positions dans l'historique local pour vérifier le geste.
       
   156             if (localHistory.Count < indexesToCheck + 1)
       
   157                 return false;
       
   158 
       
   159             //La distance de référence est ici la distance entre le milieu du dos et le milieu des épaules.
       
   160             refDistance = Math.Abs(localHistory[0][(int)JointType.Spine].Position.Y - localHistory[0][(int)JointType.ShoulderCenter].Position.Y);
       
   161             //On commence la position pour les indexesToCheck dernières postures (celle à l'index 0 étant la dernière).
       
   162             SkeletonPoint startPointRight = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position;
       
   163 
       
   164             //Barycentres pour la main droite.
       
   165             PointF rightBarycenter = new PointF(0, 0);
       
   166             //Distances moyennes des points aux barycentres.
       
   167             float averageDistToRightBarycenter = 0;
       
   168 
       
   169             //Index du point de départ dans la détection.
       
   170             int beginIndex = localHistory.Count - indexesToCheck;
       
   171 
       
   172             //Index du point d'arrivée.
       
   173             int endRightIndex = 0;
       
   174 
       
   175             //On cherche le point d'arrivée.
       
   176             /*for (int i = beginIndex; i > 0; i--)
       
   177             {
       
   178                 float X = localHistory[i][(int)JointType.HandRight].Position.X;
       
   179                 float Y = localHistory[i][(int)JointType.HandRight].Position.Y;
       
   180 
       
   181                 //Si un point est proche du point de départ.
       
   182                 if (Distance2D(X, Y, startPointRight.X, startPointRight.Y) < refDistance / 2 && X != startPointRight.X && Y != startPointRight.Y)
       
   183                 {
       
   184                     Console.Out.WriteLine("REACHED");
       
   185                     endRightIndex = i;
       
   186                     break;
       
   187                 }
       
   188             }*/
       
   189 
       
   190             /*//S'il n'y a pas assez de points.
       
   191             if (beginIndex - endRightIndex < indexesToCheck)
       
   192                 return false;*/
       
   193 
       
   194             //Calcul du barycentre de la main droite.
       
   195             for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
       
   196             {
       
   197                 rightBarycenter.X += localHistory[i][(int)JointType.HandRight].Position.X;
       
   198                 rightBarycenter.Y += localHistory[i][(int)JointType.HandRight].Position.Y;
       
   199             }
       
   200             rightBarycenter.X /= indexesToCheck;
       
   201             rightBarycenter.Y /= indexesToCheck;
       
   202 
   100             //Estimation de la distance moyenne d'un point au barycentre droit.
   203             //Estimation de la distance moyenne d'un point au barycentre droit.
   101             for (int i = beginIndex; i > 0; i--)
   204             for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
   102             {
   205             {
   103                 float ptX = localHistory[i][(int)JointType.HandRight].Position.X;
   206                 float ptX = localHistory[i][(int)JointType.HandRight].Position.X;
   104                 float ptY = localHistory[i][(int)JointType.HandRight].Position.Y;
   207                 float ptY = localHistory[i][(int)JointType.HandRight].Position.Y;
   105                 averageDistToRightBarycenter += (float)Distance2D(ptX, rightBarycenter.X, ptY, rightBarycenter.Y);
   208                 averageDistToRightBarycenter += (float)Distance2D(ptX, rightBarycenter.X, ptY, rightBarycenter.Y);
   106             }
   209             }
   107             averageDistToRightBarycenter /= indexesToCheck;
   210             averageDistToRightBarycenter /= indexesToCheck;
   108 
   211 
   109             //De la position p1 à pn, on suit l'algorithme.
   212             //Pour les points, on suit l'algorithme.
   110             for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
   213 
   111             {
   214             //Si la distance moyenne de chaque point de la main droite au barycentre droit est trop faible
   112                 //Si la position Y de la main est plus haute que la tête
   215             //Alors la main droite n'a pas décrit de cercle.
   113                 //OU si la position Y de la main est plus basse que la hanche
   216             if (averageDistToRightBarycenter < refDistance / 2)
   114                 //OU si la nouvelle position X de la main est à droite de la précédente
   217                 rightHandDoCircle = false;
   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
   218 
   116                 //Alors on retourne faux.
   219             float globalPercent = 0;
   117                 if (localHistory[i][(int)JointType.HandRight].Position.Y < localHistory[i][(int)JointType.Head].Position.Y ||
   220 
   118                 localHistory[i][(int)JointType.HandRight].Position.Y > localHistory[i][(int)JointType.HipCenter].Position.Y ||
   221             if (rightHandDoCircle)
   119                 localHistory[i][(int)JointType.HandRight].Position.X > localHistory[i - 1][(int)JointType.HandRight].Position.X ||
   222                 for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
   120                 Math.Abs(localHistory[i][(int)JointType.HandRight].Position.Y - startPoint.Y) > refDistance / 2)
   223                 {
   121                     return false;
   224                     //Si la distance moyenne de chaque point de la main droite au barycentre droit est trop faible
   122             }
   225                     //OU si la distance d'un point de la main droite excède à la distance moyenne au barycentre droit avec une erreur N
   123 
   226                     //OU si le point de départ de la main gauche est plus éloigné du point d'arrivée de la main gauche de N.
   124             //Si la distance horizontale du geste a été plus courte que la distance N
   227                     //Alors la main droite n'a pas décrit de cercle.
   125             //Alors on retourne faux.
   228 
   126             if (Math.Abs(localHistory[0][(int)JointType.HandRight].Position.X - localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X) < refDistance / 2)
   229                     float X = localHistory[i][(int)JointType.HandRight].Position.X;
   127                 return false;
   230                     float Y = localHistory[i][(int)JointType.HandRight].Position.Y;
   128 
   231                     float R = averageDistToRightBarycenter, r = (float)Math.Abs((double)Distance2D(X, Y, rightBarycenter.X, rightBarycenter.Y));
   129             //Si la dernière position de la main droite est sur le côté droit du corps
   232                     float percent = 0;
   130             //OU si la première position calculée de la main droite est sur le côté gauche du corps
   233 
   131             //Alors on retourne faux.
   234                     if (r < R)
   132             if (localHistory[localHistory.Count - 1][(int)JointType.HandRight].Position.X > localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X ||
   235                         percent = 100 * r / R;
   133                localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X < localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X)
   236                     else
   134                 return false;
   237                         percent = 100 * R / r;
       
   238 
       
   239                     globalPercent += percent;
       
   240 
       
   241                     /*if (Math.Abs((double)Distance2D(X, Y, rightBarycenter.X, rightBarycenter.Y) - averageDistToRightBarycenter) > refDistance / 5)
       
   242                     {
       
   243                         //Console.Out.WriteLine("FAIL");
       
   244                         return false;
       
   245                     }*/
       
   246                 }
       
   247 
       
   248             float res = ((float)globalPercent / indexesToCheck);
       
   249 
       
   250             Console.Out.WriteLine("p:" + ((float)globalPercent / indexesToCheck));
       
   251 
       
   252             if (res >= 50)
       
   253                 Console.In.Read();
   135 
   254 
   136             //On supprime l'historique local.
   255             //On supprime l'historique local.
   137             localHistory.Clear();
   256             localHistory.Clear();
   138             //Si on est arrivé jusqu'ici, toutes les conditions pour un swipe left ont été remplies.
   257             //Si on est arrivé jusqu'ici, toutes les conditions pour un swipe left ont été remplies.
   139             return true;
   258             return true;