middleware/Tracking/Gestures/CircleDetector.cs
changeset 17 fda26bfcabef
parent 15 4b78f179e7ce
child 27 6c08d4d7219e
--- a/middleware/Tracking/Gestures/CircleDetector.cs	Wed Apr 04 10:51:21 2012 +0200
+++ b/middleware/Tracking/Gestures/CircleDetector.cs	Thu Apr 05 15:54:44 2012 +0200
@@ -26,12 +26,13 @@
 using Microsoft.Kinect;
 using System.Windows.Media.Media3D;
 using System.Drawing;
+using Trakers.Debug;
 
-namespace Trakers.MainModule.Gestures
+namespace Trakers.Tracking.Gestures
 {
     public class CircleDetector : GestureDetector
     {
-        public CircleDetector() : base()
+        public CircleDetector(DebugWindow _debug) : base(_debug)
         {
             gesturePeriod = (float)1;
             indexesPerSecond = 30;
@@ -43,11 +44,13 @@
          * Règles :
          * Se fait avec une main.
          * Chaque point est à la même distance du barycentre.
-         * Traitement :
-         * On .
+         * On regarde pour la main gauche.
          */
-        public bool CheckForCircle()
+        public bool CheckForLeftCircle()
         {
+            //Indique si la main gauche a décrit un cercle.
+            bool leftHandDoCircle = true;
+            
             //Crée un historique de squelette local, puisque l'historique est mis à jour toutes les ~1/30 s.
             List<List<Joint>> localHistory = new List<List<Joint>>(history);
 
@@ -58,15 +61,13 @@
             //La distance de référence est ici la distance entre le milieu du dos et le milieu des épaules.
             refDistance = Math.Abs(localHistory[0][(int)JointType.Spine].Position.Y - localHistory[0][(int)JointType.ShoulderCenter].Position.Y);
             //On commence la position pour les indexesToCheck dernières postures (celle à l'index 0 étant la dernière).
-            startPoint = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position;
-
+            SkeletonPoint startPointLeft = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position;
+            
             //Barycentres pour les mains.
             PointF leftBarycenter = new PointF(0, 0);
-            PointF rightBarycenter = new PointF(0, 0);
             //Distances moyennes des points aux barycentres.
             float averageDistToLeftBarycenter = 0;
-            float averageDistToRightBarycenter = 0;
-
+            
             //Index du point de départ dans la détection.
             int beginIndex = localHistory.Count - indexesToCheck;
 
@@ -79,15 +80,6 @@
             leftBarycenter.X /= indexesToCheck;
             leftBarycenter.Y /= indexesToCheck;
 
-            //Calcul du barycentre de la main droite.
-            for (int i = beginIndex; i > 0; i--)
-            {
-                rightBarycenter.X += localHistory[i][(int)JointType.HandRight].Position.X;
-                rightBarycenter.Y += localHistory[i][(int)JointType.HandRight].Position.Y;
-            }
-            rightBarycenter.X /= indexesToCheck;
-            rightBarycenter.Y /= indexesToCheck;
-
             //Estimation de la distance moyenne d'un point au barycentre gauche.
             for (int i = beginIndex; i > 0; i--)
             {
@@ -97,8 +89,119 @@
             }
             averageDistToLeftBarycenter /= indexesToCheck;
 
+            //Pour les points, on suit l'algorithme.
+
+            //Si la distance moyenne de chaque point de la main gauche au barycentre gauche est trop faible
+            //Alors la main gauche n'a pas décrit de cercle.
+            if (averageDistToLeftBarycenter < refDistance / 2)
+                leftHandDoCircle = false;
+
+            //Indique si on a atteint le point d'arrivée pour la main gauche.
+            bool endLeftReached = false;
+
+            if(leftHandDoCircle)
+                for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
+                {
+                    //Si la distance d'un point de la main gauche excède à la distance moyenne au barycentre gauche avec une erreur N
+                    //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.
+                    //Alors la main gauche n'a pas décrit de cercle.
+                    float X = localHistory[i][(int)JointType.HandLeft].Position.X;
+                    float Y = localHistory[i][(int)JointType.HandLeft].Position.Y;
+
+                    //Si un point est proche du point de départ.
+                    if(Distance2D(X, Y, startPointLeft.X, startPointLeft.Y) < refDistance / 5 && X != startPointLeft.X && Y != startPointLeft.Y)
+                        endLeftReached = true;
+
+                    if (Math.Abs((double)Distance2D(X, Y, leftBarycenter.X, leftBarycenter.Y) - averageDistToLeftBarycenter) > refDistance / 5)
+                    {
+                        leftHandDoCircle = false;
+                        break;
+                    }
+
+                    //Si la main gauche a atteint une position proche de son point de départ.
+                    if (endLeftReached)
+                    {
+                        //S'il y a trop peu de points
+                        if (i - (localHistory.Count - indexesToCheck + 1) < (indexesToCheck / 2))
+                            leftHandDoCircle = false;
+                        break;
+                    }
+                }
+
+            //On supprime l'historique local.
+            localHistory.Clear();
+            //Si on est arrivé jusqu'ici, toutes les conditions pour un swipe left ont été remplies.
+            return leftHandDoCircle;
+        }
+
+        /*
+         * Lit les noeuds de l'historique du squelette afin de détecter un cercle.
+         * Règles :
+         * Se fait avec une main.
+         * Chaque point est à la même distance du barycentre.
+         * On regarde pour la main droite.
+         */
+        public bool CheckForRightCircle()
+        {
+            //Indique si la main droite a décrit un cercle.
+            bool rightHandDoCircle = true;
+
+            //Crée un historique de squelette local, puisque l'historique est mis à jour toutes les ~1/30 s.
+            List<List<Joint>> localHistory = new List<List<Joint>>(history);
+
+            //if (Math.Abs(Math.Abs(localHistory[0][(int)JointType.HandLeft].Position.X - localHistory[0][(int)JointType.HandRight].Position.X) - refDistance) < 10)
+              //  Console.Out.WriteLine("REF");
+
+            //Si il n'y a pas assez de positions dans l'historique local pour vérifier le geste.
+            if (localHistory.Count < indexesToCheck + 1)
+                return false;
+
+            //La distance de référence est ici la distance entre le milieu du dos et le milieu des épaules.
+            refDistance = Math.Abs(localHistory[0][(int)JointType.Spine].Position.Y - localHistory[0][(int)JointType.ShoulderCenter].Position.Y);
+            //On commence la position pour les indexesToCheck dernières postures (celle à l'index 0 étant la dernière).
+            SkeletonPoint startPointRight = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position;
+
+            //Barycentres pour la main droite.
+            PointF rightBarycenter = new PointF(0, 0);
+            //Distances moyennes des points aux barycentres.
+            float averageDistToRightBarycenter = 0;
+
+            //Index du point de départ dans la détection.
+            int beginIndex = localHistory.Count - indexesToCheck;
+
+            //Index du point d'arrivée.
+            int endRightIndex = 0;
+
+            //On cherche le point d'arrivée.
+            /*for (int i = beginIndex; i > 0; i--)
+            {
+                float X = localHistory[i][(int)JointType.HandRight].Position.X;
+                float Y = localHistory[i][(int)JointType.HandRight].Position.Y;
+
+                //Si un point est proche du point de départ.
+                if (Distance2D(X, Y, startPointRight.X, startPointRight.Y) < refDistance / 2 && X != startPointRight.X && Y != startPointRight.Y)
+                {
+                    Console.Out.WriteLine("REACHED");
+                    endRightIndex = i;
+                    break;
+                }
+            }*/
+
+            /*//S'il n'y a pas assez de points.
+            if (beginIndex - endRightIndex < indexesToCheck)
+                return false;*/
+
+            //Calcul du barycentre de la main droite.
+            for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
+            {
+                rightBarycenter.X += localHistory[i][(int)JointType.HandRight].Position.X;
+                rightBarycenter.Y += localHistory[i][(int)JointType.HandRight].Position.Y;
+            }
+            rightBarycenter.X /= indexesToCheck;
+            rightBarycenter.Y /= indexesToCheck;
+
             //Estimation de la distance moyenne d'un point au barycentre droit.
-            for (int i = beginIndex; i > 0; i--)
+            for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
             {
                 float ptX = localHistory[i][(int)JointType.HandRight].Position.X;
                 float ptY = localHistory[i][(int)JointType.HandRight].Position.Y;
@@ -106,32 +209,48 @@
             }
             averageDistToRightBarycenter /= indexesToCheck;
 
-            //De la position p1 à pn, on suit l'algorithme.
-            for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
-            {
-                //Si la position Y de la main est plus haute que la tête
-                //OU si la position Y de la main est plus basse que la hanche
-                //OU si la nouvelle position X de la main est à droite de la précédente
-                //OU si la nouvelle position Y de la main est plus éloignée de la distance N par rapport à la première position Y
-                //Alors on retourne faux.
-                if (localHistory[i][(int)JointType.HandRight].Position.Y < localHistory[i][(int)JointType.Head].Position.Y ||
-                localHistory[i][(int)JointType.HandRight].Position.Y > localHistory[i][(int)JointType.HipCenter].Position.Y ||
-                localHistory[i][(int)JointType.HandRight].Position.X > localHistory[i - 1][(int)JointType.HandRight].Position.X ||
-                Math.Abs(localHistory[i][(int)JointType.HandRight].Position.Y - startPoint.Y) > refDistance / 2)
-                    return false;
-            }
+            //Pour les points, on suit l'algorithme.
+
+            //Si la distance moyenne de chaque point de la main droite au barycentre droit est trop faible
+            //Alors la main droite n'a pas décrit de cercle.
+            if (averageDistToRightBarycenter < refDistance / 2)
+                rightHandDoCircle = false;
+
+            float globalPercent = 0;
+
+            if (rightHandDoCircle)
+                for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
+                {
+                    //Si la distance moyenne de chaque point de la main droite au barycentre droit est trop faible
+                    //OU si la distance d'un point de la main droite excède à la distance moyenne au barycentre droit avec une erreur N
+                    //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.
+                    //Alors la main droite n'a pas décrit de cercle.
 
-            //Si la distance horizontale du geste a été plus courte que la distance N
-            //Alors on retourne faux.
-            if (Math.Abs(localHistory[0][(int)JointType.HandRight].Position.X - localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X) < refDistance / 2)
-                return false;
+                    float X = localHistory[i][(int)JointType.HandRight].Position.X;
+                    float Y = localHistory[i][(int)JointType.HandRight].Position.Y;
+                    float R = averageDistToRightBarycenter, r = (float)Math.Abs((double)Distance2D(X, Y, rightBarycenter.X, rightBarycenter.Y));
+                    float percent = 0;
+
+                    if (r < R)
+                        percent = 100 * r / R;
+                    else
+                        percent = 100 * R / r;
+
+                    globalPercent += percent;
 
-            //Si la dernière position de la main droite est sur le côté droit du corps
-            //OU si la première position calculée de la main droite est sur le côté gauche du corps
-            //Alors on retourne faux.
-            if (localHistory[localHistory.Count - 1][(int)JointType.HandRight].Position.X > localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X ||
-               localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X < localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X)
-                return false;
+                    /*if (Math.Abs((double)Distance2D(X, Y, rightBarycenter.X, rightBarycenter.Y) - averageDistToRightBarycenter) > refDistance / 5)
+                    {
+                        //Console.Out.WriteLine("FAIL");
+                        return false;
+                    }*/
+                }
+
+            float res = ((float)globalPercent / indexesToCheck);
+
+            Console.Out.WriteLine("p:" + ((float)globalPercent / indexesToCheck));
+
+            if (res >= 50)
+                Console.In.Read();
 
             //On supprime l'historique local.
             localHistory.Clear();