diff -r a9ebacd6c089 -r fda26bfcabef middleware/Tracking/Gestures/CircleDetector.cs --- 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> localHistory = new List>(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> localHistory = new List>(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();