/// <summary> /// Classifies the specified input data. /// </summary> /// <param name="inputData">The input data.</param> /// <returns>a classification result containing name and parameter of the recognized gesture if /// recognition succeeds, null otherwise.</returns> public IClassificationResult Classify(TrackedGesture inputData) { IClassificationResult result = null; //RecognizePinchGesture(inputData); if (inputData.Count == 0) { return(result); } //if (result == null) //{ // result = RecognizeSemiPinchGesture(inputData); //} if (result == null) { result = RecognizeBlurryPinchGesture(inputData); } if (result == null) { result = RecognizeBlurryLineGesture(inputData); } if (result == null) { result = RecognizeBlurryCircleGesture(inputData); } if (result == null) { result = RecognizeXFingerDragging(inputData.FrameList, 3); } System.Diagnostics.Debug.WriteLine("recognized: " + (result == null ? "nothing" : result.ToString())); return(result); }
private IClassificationResult RecognizeBlurryCircleGesture(TrackedGesture inputData) { String resultString = null; if (!CheckTokenCriterion(inputData.FrameList, 1)) { return(null); } int startPointIndex = FindFirstFrameIndexWithCorrectCount(inputData.FrameList, 1, true); int endPointIndex = FindFirstFrameIndexWithCorrectCount(inputData.FrameList, 1, false); if (startPointIndex == -1 || endPointIndex == -1) { return(null); } Vertex startPoint = new Vertex(inputData.FrameList[startPointIndex][0].x, inputData.FrameList[startPointIndex][0].y); Vertex endPoint = new Vertex(inputData.FrameList[endPointIndex][0].x, inputData.FrameList[endPointIndex][0].y); //search endpoint es point with max distance from start point Size dim; var centre = GetCentre(inputData.FrameList, out dim); //centre of all blobs if (MetricDistances.EuclideanDistance(centre, startPoint) > MetricDistances.EuclideanDistance(startPoint, endPoint)) { int endPointBlobIndex = GetBlobMaxDistantFromPointIndex(inputData.FrameList, startPoint, out endPointIndex); } if (CheckCircleFormKriterion(inputData.FrameList)) { if (CheckForFullCircle(inputData.FrameList, startPoint, endPoint)) { resultString = "circle"; } else { resultString = "semi circle"; } } else { return(null); } return(new ClassificationResult( resultString, 100.0, new Sample[] { new Sample(DateTime.Now, startPoint) }, new KeyValuePair <String, double>("direction", GetCircleDirection(inputData.FrameList) ? 1.0 : -1.0), new KeyValuePair <String, Size>("dimensions", dim) )); }
public virtual IClassificationResult FinishEvaluation(bool clear) { IClassificationResult classificationResult = null; if (blobTracker != null) { TrackedGesture trackedGesture = blobTracker.TrackedBlobs; RecognitionMode = false; if (blobTracker.Trajectories.Count > 0) { Console.WriteLine("Gesture trajectories to evaluate:" + blobTracker.Trajectories.Count); List <IClassificationResult> oldResults = new List <IClassificationResult>(); // foreach (IClassify classifier in classifiers){ for (int i = 0; i < classifiers.Count; i++) { IClassify classifier = classifiers[i]; if (classifier != null) { classificationResult = classifier.Classify(blobTracker.FrameList, blobTracker.Trajectories); if (classificationResult != null) { if (classificationResult.Probability > ProbabilityThreshold) { break; } else { oldResults.Add(classificationResult); } } } } // no result was taken directly, so find the first one with the highest probability if (oldResults != null && oldResults.Count > 0) { foreach (var result in oldResults) { if (classificationResult == null || result.Probability > classificationResult.Probability) { classificationResult = result; } } } } if (clear) { blobTracker.InitiateTracking(); } } return(classificationResult); }
/// <summary> /// Checks for tap gestures. /// </summary> /// <param className="clusteredSamples">The clustered samples.</param> /// <returns>Number of Taps detected, -1 if no tap gesture could be recognized.</returns> private int CheckForTapGestures(TrackedGesture inputData, ref Vertex tapedPos) { tapedPos[0] = -1; if (inputData == null || inputData.Count == 0) { return(-1); } var frameList = inputData.FrameList; int framesWithBlobs = 0; int taps = 1; int frameCounter = 0; foreach (var frame in frameList) { if (frame.Count > 1) { return(-1); } if (frame.Count == 1) { framesWithBlobs++; if (!(frame[0].cx < MAXTAPDISTANCE && frame[0].cy < MAXTAPDISTANCE)) //to big blobs { return(-1); } if (tapedPos[0] != -1.0 && MetricDistances.EuclideanDistance(tapedPos, new Vertex(frame[0].x, frame[0].y)) > MAXTAPDISTANCE) //to much moving while tapping { return(-1); } if (tapedPos[0] < 0.0) { tapedPos = new Vertex(frame[0].x, frame[0].y); //first tap contact is tap position } } else //frame without blobs -> touch left surface { if (frameCounter != 0 && frameCounter != frameList.Length - 1) { taps++; } } ++frameCounter; } return(taps); }
private IClassificationResult RecognizeBlurryLineGesture(TrackedGesture inputData) { if (!CheckTokenCriterion(inputData.FrameList, 1)) { return(null); } Vertex startPoint, endPoint; int startPointIndex = FindFirstFrameIndexWithCorrectCount(inputData.FrameList, 1, true); int endPointIndex = FindFirstFrameIndexWithCorrectCount(inputData.FrameList, 1, false); Touch t = inputData.FrameList[startPointIndex][0]; startPoint = new Vertex(t.x, t.y); int maxDistantBlobFrameIndex; //search endpoint es point with max distance from start point //accounts for misleading data and offers robust identification of lines with disadvantage of //more wrong positive classifications int maxDistantBlobIndex = GetBlobMaxDistantFromPointIndex(inputData.FrameList, startPoint, out maxDistantBlobFrameIndex); if (startPointIndex == -1 || endPointIndex == -1 || startPointIndex == endPointIndex || maxDistantBlobFrameIndex == -1) { return(null); } t = inputData.FrameList[endPointIndex][0]; endPoint = new Vertex(t.x, t.y); IClassificationResult result = null; if (CheckMaxDistanceFromLineKriterion(inputData.FrameList, startPoint, endPoint, MAXDISTFROMLINE) && MetricDistances.EuclideanDistance(startPoint, endPoint) > MINLINELENGTH) { //return RecognizeDirectionalLine(startPoint, endPoint); result = new ClassificationResult("line", 100.0, new Sample[] { new Sample(DateTime.Now, startPoint), new Sample(DateTime.Now, endPoint) }, new KeyValuePair <String, double>("angle", GetAngle(startPoint, endPoint))); } return(result); }
/// <summary> /// Checks for tap gestures. /// </summary> /// <param className="inputData">The input data .</param> /// <returns>Number of Taps detected, -1 if no tap gesture could be recognized.</returns>F:\Material\Gesture_Source\Gesten\Classifiers\DTWClassifier.cs private int CheckForTapGestures2(TrackedGesture inputData, ref Vertex tapedPos) { tapedPos[0] = -1; if (inputData == null || inputData.Count == 0) { return(-1); } var frameList = inputData.FrameList; int framesWithBlobs = 0; int taps = 1; foreach (var frame in frameList) { if (frame.Count > 1) { return(-1); } if (frame.Count == 1) { framesWithBlobs++; if (!(frame[0].DimX < maxTapDistance && frame[0].DimY < maxTapDistance)) //to big blobs { return(-1); } if (tapedPos[0] != -1.0 && MetricDistances.EuclideanDistance(tapedPos, new Vertex(frame[0].X, frame[0].Y)) > maxTapDistance) //to much moving while tapping { return(-1); } if (tapedPos[0] < 0.0) { tapedPos = new Vertex(frame[0].X, frame[0].Y); //first tap contact is tap position } } else //frame without blobs -> touch left surface { taps++; } } return(taps); }
public IClassificationResult FinishEvaluation() { TrackedGesture trackedGesture = blobTracker.TrackedBlobs; IClassificationResult classificationResult = null; RecognitionMode = false; foreach (IClassify classifier in classifiers) { classificationResult = classifier.Classify(trackedGesture); if (classificationResult != null) { blobTracker.InitiateTracking(); return(classificationResult); } } blobTracker.InitiateTracking(); return(classificationResult); }
/// <summary> /// Classifies the specified gesture. /// </summary> /// <param name="gesture">The gesture.</param> /// <returns></returns> public IClassificationResult Classify(TrackedGesture gesture) { int result; Vertex tappedPos = new Vertex(); if (gesture.Count == 0) { return(null); } //if (gesture.Count == 1) { result = CheckForTapGestures(gesture, ref tappedPos); } //else { result = CheckForTapGesturesMT(gesture, ref tapedPos); } if (result == -1) { return(null); } String resultString = "tap"; return(new ClassificationResult(resultString, 100.0, new Sample[] { new Sample(DateTime.Now, tappedPos) }, new KeyValuePair <String, double>("taps", result))); }
private IClassificationResult RecognizeBlurryPinchGesture(TrackedGesture inputData) { double maxTapDistance = 2; double startDist = double.MinValue, endDist = double.MinValue; Sample startNode1 = new Sample(), startNode2 = new Sample(); bool semi1 = true; bool semi2 = true; //check for min blob relation int equalToX = 0, lessThanX = 0, moreThanX = 0; int i = 0; while (i < inputData.FrameList.Length) { if (inputData.FrameList[i].Count == 2) { equalToX++; //store the first two blobs occurring together as start blobs for the pinch gesture if (startDist < 0.0) { //if more than 1/3 of the frames belongs to single line movement, than it is no pinch anymore if (i <= inputData.FrameList.Length / 3) { //first fingers start contact for the pinch startNode1 = new Sample( inputData.FrameList[i].TimeStamp, inputData.FrameList[i][0].x, inputData.FrameList[i][0].y); //second fingers start contact for the pinch startNode2 = new Sample( inputData.FrameList[i].TimeStamp, inputData.FrameList[i][1].x, inputData.FrameList[i][1].y); //pinching fingers distance at the beginning startDist = MetricDistances.EuclideanDistance(startNode1, startNode2); } } //check for a steady first finger (blobs stay close to first contact of one finger) semi1 = semi1 && ( (Math.Abs(startNode1[0] - inputData.FrameList[i][0].x) < maxTapDistance && Math.Abs(startNode1[1] - inputData.FrameList[i][0].y) < maxTapDistance ) || (Math.Abs(startNode1[0] - inputData.FrameList[i][1].x) < maxTapDistance && Math.Abs(startNode1[1] - inputData.FrameList[i][1].y) < maxTapDistance ) ); //check for a steady second finger (blobs stay close to first contact of one finger) semi2 = semi2 && ( (Math.Abs(startNode2[0] - inputData.FrameList[i][0].x) < maxTapDistance && Math.Abs(startNode2[1] - inputData.FrameList[i][0].y) < maxTapDistance ) || (Math.Abs(startNode2[0] - inputData.FrameList[i][1].x) < maxTapDistance && Math.Abs(startNode2[1] - inputData.FrameList[i][1].y) < maxTapDistance ) ); } else { //count cases of more or less than two blobs in one frame //can be caused by performing another gesture, flickering or touch unsensitive modules if (inputData.FrameList[i].Count > 2) { moreThanX++; } else { lessThanX++; } } i++; } //if there are to many frames with less or more than two blobs, reject pinch gesture assumption if ((double)equalToX / (lessThanX + moreThanX) < MINBLOBRELATION) { return(null); } //get last frame with two blobs for finding end positions of both fingers i = inputData.FrameList.Length - 1; while (endDist < 0.0 && i >= 0) { //check if last frame with two fingers contact is within last third of frame-range //if more than 1/3 of the frames belongs to single line movement, than it is no pinch anymore if (i >= inputData.FrameList.Length * 2 / 3 && inputData.FrameList[i].Count == 2) { IVertex endPoint1 = new Vertex(inputData.FrameList[i][0].x, inputData.FrameList[i][0].y); IVertex endPoint2 = new Vertex(inputData.FrameList[i][1].x, inputData.FrameList[i][1].y); endDist = MetricDistances.EuclideanDistance(endPoint1, endPoint2); if (startDist > endDist) { endPoint1 = startNode1; endPoint2 = startNode2; } //if to much scattering of blobs along a given line between the outmost two fingers contact, reject pinch gesture assumption if (!CheckMaxDistanceFromLineKriterion(inputData.FrameList, endPoint1, endPoint2, MAXDISTFROMLINE)) { return(null); } } i--; } //get direction out of change of start to end distances between the two fingers contacts bool direction = startDist > endDist; //pinch or reverse pinch // GestureToken token = ConnectTokens(inputData); // if (!CheckMaxDistanceFromLineKriterion(token, 2 * MAXDISTFROMLINE)) { return null; } bool pinch = startDist > 0.0 && endDist > 0.0 && ((direction ? (startDist / endDist) : endDist / startDist) > 0.5); return(!pinch ? null : new ClassificationResult( (semi2 || semi1) ? "one finger pinch" : "pinch", 1.0, new Sample[] { semi1?startNode1: (semi2 ? startNode2 : new Sample(startNode2.TimeStamp, (startNode1[0] + startNode2[0]) / 2, (startNode1[1] + startNode2[1]) / 2)) }, new KeyValuePair <String, double>("expanding", (direction) ? -1.0 : 1.0))); }