public NBestList Recognize(ArrayList points) // candidate points { // resample to a common number of points points = Utils.Resample(points, NumResamplePoints); // rotate so that the centroid-to-1st-point is at zero degrees double radians = Utils.AngleInRadians(Utils.Centroid(points), (PointR)points[0], false); // indicative angle points = Utils.RotateByRadians(points, -radians); // undo angle // scale to a common (square) dimension points = Utils.ScaleTo(points, ResampleScale); // translate to a common origin points = Utils.TranslateCentroidTo(points, ResampleOrigin); NBestList nbest = new NBestList(); foreach (Gesture p in _gestures.Values) { double[] best = GoldenSectionSearch( points, // to rotate p.Points, // to match Utils.Deg2Rad(-45.0), // lbound Utils.Deg2Rad(+45.0), // ubound Utils.Deg2Rad(2.0)); // threshold double score = 1d - best[0] / HalfDiagonal; nbest.AddResult(p.Name, score, best[0], best[1]); // name, score, distance, angle } nbest.AddResult("Try Again", tolerance, 0.0, 0.0); nbest.SortDescending(); // sort so that nbest[0] is best result return(nbest); }
public NBestList Recognize(ArrayList points) // candidate points { // resample to a common number of points points = Utils.Resample(points, NumResamplePoints); // rotate so that the centroid-to-1st-point is at zero degrees double radians = Utils.AngleInRadians(Utils.Centroid(points), (PointR) points[0], false); // indicative angle points = Utils.RotateByRadians(points, -radians); // undo angle // scale to a common (square) dimension points = Utils.ScaleTo(points, ResampleScale); // translate to a common origin points = Utils.TranslateCentroidTo(points, ResampleOrigin); NBestList nbest = new NBestList(); foreach (Gesture p in _gestures.Values) { double[] best = GoldenSectionSearch( points, // to rotate p.Points, // to match Utils.Deg2Rad(-45.0), // lbound Utils.Deg2Rad(+45.0), // ubound Utils.Deg2Rad(2.0)); // threshold double score = 1d - best[0] / HalfDiagonal; nbest.AddResult(p.Name, score, best[0], best[1]); // name, score, distance, angle } nbest.AddResult("Try Again", tolerance, 0.0, 0.0); nbest.SortDescending(); // sort so that nbest[0] is best result return nbest; }
/// <summary> /// Tests an entire batch of files. See comments atop MainForm.TestBatch_Click(). /// </summary> /// <param name="subject">Subject number.</param> /// <param name="speed">"fast", "medium", or "slow"</param> /// <param name="categories">A list of gesture categories that each contain lists of /// prototypes (examples) within that gesture category.</param> /// <param name="dir">The directory into which to write the output files.</param> /// <returns>True if successful; false otherwise.</returns> public bool TestBatch(int subject, string speed, ArrayList categories, string dir) { bool success = true; StreamWriter mainWriter = null; StreamWriter recWriter = null; try { // // set up a main results file and detailed recognition results file // int start = Environment.TickCount; string mainFile = String.Format("{0}\\geometric_main_{1}.txt", dir, start); string recFile = String.Format("{0}\\geometric_data_{1}.txt", dir, start); mainWriter = new StreamWriter(mainFile, false, Encoding.UTF8); mainWriter.WriteLine("Subject = {0}, Recognizer = geometric, Speed = {1}, StartTime(ms) = {2}", subject, speed, start); mainWriter.WriteLine("Subject Recognizer Speed NumTraining GestureType RecognitionRate\n"); recWriter = new StreamWriter(recFile, false, Encoding.UTF8); recWriter.WriteLine("Subject = {0}, Recognizer = geometric, Speed = {1}, StartTime(ms) = {2}", subject, speed, start); recWriter.WriteLine("Correct? NumTrain Tested 1stCorrect Pts Ms Angle : (NBestNames) [NBestScores]\n"); // // determine the number of gesture categories and the number of examples in each one // int numCategories = categories.Count; int numExamples = ((Category)categories[0]).NumExamples; double totalTests = (numExamples - 1) * NumRandomTests; // // outermost loop: trains on N=1..9, tests on 10-N (for e.g., numExamples = 10) // for (int n = 1; n <= numExamples - 1; n++) { // storage for the final avg results for each category for this N double[] results = new double[numCategories]; // // run a number of tests at this particular N number of training examples // for (int r = 0; r < NumRandomTests; r++) { _gestures.Clear(); // clear any (old) loaded prototypes // load (train on) N randomly selected gestures in each category for (int i = 0; i < numCategories; i++) { Category c = (Category)categories[i]; // the category to load N examples for int[] chosen = Utils.Random(0, numExamples - 1, n); // select N unique indices for (int j = 0; j < chosen.Length; j++) { Gesture p = c[chosen[j]]; // get the prototype from this category at chosen[j] _gestures.Add(p.Name, p); // load the randomly selected test gestures into the recognizer } } // // testing loop on all unloaded gestures in each category. creates a recognition // rate (%) by averaging the binary outcomes (correct, incorrect) for each test. // for (int i = 0; i < numCategories; i++) { // pick a random unloaded gesture in this category for testing // instead of dumbly picking, first find out what indices aren't // loaded, and then randomly pick from those. Category c = (Category)categories[i]; int[] notLoaded = new int[numExamples - n]; for (int j = 0, k = 0; j < numExamples; j++) { Gesture g = c[j]; if (!_gestures.ContainsKey(g.Name)) { notLoaded[k++] = j; // jth gesture in c is not loaded } } int chosen = Utils.Random(0, notLoaded.Length - 1); // index Gesture p = c[notLoaded[chosen]]; // gesture to test Debug.Assert(!_gestures.ContainsKey(p.Name)); // do the recognition! ArrayList testPts = Utils.RotateByDegrees(p.RawPoints, Utils.Random(0, 359)); NBestList result = this.Recognize(testPts); string category = Category.ParseName(result.Name); int correct = (c.Name == category) ? 1 : 0; recWriter.WriteLine("{0} {1} {2} {3} {4} {5} {6:F1}{7} : ({8}) [{9}]", correct, // Correct? n, // NumTrain p.Name, // Tested FirstCorrect(p.Name, result.Names), // 1stCorrect p.RawPoints.Count, // Pts p.Duration, // Ms Math.Round(result.Angle, 1), (char)176, // Angle tweaking : result.NamesString, // (NBestNames) result.ScoresString); // [NBestScores] results[i] += correct; } // provide feedback as to how many tests have been performed thus far. double testsSoFar = ((n - 1) * NumRandomTests) + r; ProgressChangedEvent(this, new ProgressEventArgs(testsSoFar / totalTests)); // callback } // // now create the final results for this N and write them to a file // for (int i = 0; i < numCategories; i++) { results[i] /= (double)NumRandomTests; // normalize by the number of tests at this N Category c = (Category)categories[i]; // Subject Recognizer Speed NumTraining GestureType RecognitionRate mainWriter.WriteLine("{0} geometric {1} {2} {3} {4:F3}", subject, speed, n, c.Name, Math.Round(results[i], 3)); } } // time-stamp the end of the processing int end = Environment.TickCount; mainWriter.WriteLine("\nEndTime(ms) = {0}, Minutes = {1:F2}", end, Math.Round((end - start) / 60000.0, 2)); recWriter.WriteLine("\nEndTime(ms) = {0}, Minutes = {1:F2}", end, Math.Round((end - start) / 60000.0, 2)); } catch (Exception ex) { Console.WriteLine(ex.Message); success = false; } finally { if (mainWriter != null) { mainWriter.Close(); } if (recWriter != null) { recWriter.Close(); } } return(success); }