Пример #1
0
        /// <summary>
        /// Tests an entire batch of files. See comments atop MainForm.TestBatch_Click().
        /// </summary>
        /// <param name="subject">Subject identification.</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>
        /// <param name="protractor">If true, uses Protractor instead of Golden Section Search.</param>
        /// <returns>The two filenames of the output file if successful; null otherwise. The main results are in string[0],
        /// while the detailed recognition results are in string[1].</returns>
        public string[] TestBatch(string subject, string speed, List <Category> categories, string dir, bool protractor)
        {
            StreamWriter mw = null; // main results writer
            StreamWriter dw = null; // detailed results writer

            string[] filenames = new string[2];
            try
            {
                // set up a main results file and detailed results file
                int start = Environment.TickCount;
                filenames[0] = String.Format("{0}\\$1({1})_main_{2}.txt", dir, protractor ? "protractor" : "gss", start);  // main results (small file)
                filenames[1] = String.Format("{0}\\$1({1})_nbest_{2}.txt", dir, protractor ? "protractor" : "gss", start); // recognition details (large file)

                mw = new StreamWriter(filenames[0], false, Encoding.UTF8);
                mw.WriteLine("Subject = {0}, Recognizer = $1, Search = {1}, Speed = {2}, StartTime(ms) = {3}", subject, protractor ? "protractor" : "gss", speed, start);
                mw.WriteLine("Subject Recognizer Search Speed NumTraining GestureType RecognitionRate\n");

                dw = new StreamWriter(filenames[1], false, Encoding.UTF8);
                dw.WriteLine("Subject = {0}, Recognizer = $1, Search = {1}, Speed = {2}, StartTime(ms) = {3}", subject, protractor ? "protractor" : "gss", speed, start);
                dw.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   = 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++)
                        {
                            int[] chosen = RandomEx.Array(0, numExamples - 1, n, true); // select N unique indices
                            for (int j = 0; j < chosen.Length; j++)
                            {
                                Unistroke p = categories[i][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.
                            int[] notLoaded = new int[numExamples - n];
                            for (int j = 0, k = 0; j < numExamples; j++)
                            {
                                Unistroke g = categories[i][j];
                                if (!_gestures.ContainsKey(g.Name))
                                {
                                    notLoaded[k++] = j; // jth gesture in categories[i] is not loaded
                                }
                            }
                            int       chosen = RandomEx.Integer(0, notLoaded.Length - 1); // index
                            Unistroke p      = categories[i][notLoaded[chosen]];          // gesture to test
                            Debug.Assert(!_gestures.ContainsKey(p.Name));

                            // do the recognition!
                            List <PointF> testPts = GeotrigEx.RotatePoints( // spin gesture randomly
                                TimePointF.ConvertList(p.RawPoints),
                                GeotrigEx.Degrees2Radians(RandomEx.Integer(0, 359))
                                );
                            NBestList result   = this.Recognize(TimePointF.ConvertList(testPts), protractor);
                            string    category = Category.ParseName(result.Name);
                            int       correct  = (category == categories[i].Name) ? 1 : 0;

                            dw.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;
                        //TODO
                        //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 Search Speed NumTraining GestureType RecognitionRate
                        mw.WriteLine("{0} $1 {1} {2} {3} {4} {5:F3}",
                                     subject,
                                     protractor ? "protractor" : "gss",
                                     speed,
                                     n,
                                     c.Name,
                                     Math.Round(results[i], 3)
                                     );
                    }
                }

                // time-stamp the end of the processing
                int end = Environment.TickCount;
                mw.WriteLine("\nEndTime(ms) = {0}, Minutes = {1:F2}", end, Math.Round((end - start) / 60000.0, 2));
                dw.WriteLine("\nEndTime(ms) = {0}, Minutes = {1:F2}", end, Math.Round((end - start) / 60000.0, 2));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                filenames = null;
            }
            finally
            {
                if (mw != null)
                {
                    mw.Close();
                }
                if (dw != null)
                {
                    dw.Close();
                }
            }
            return(filenames);
        }
Пример #2
0
        /// <summary>
        /// Constructs a FittsSession instance. A FittsSession contains conditions for a Fitts' law study,
        /// which, in turn, contain a set of trials. A constructed instance contains a list of conditions
        /// in sequence, which themselves contain a list of trials.
        /// </summary>
        /// <param name="o">The options that configure this session obtained from the OptionsForm dialog.</param>
        public SessionData(OptionsForm.Options o)
        {
            //
            // Set the condition variables that define this test.
            //
            _subject    = o.Subject;
            _circular   = o.Is2D;
            _a          = o.A;
            _w          = o.W;
            _mtpct      = o.MTPct;
            _intercept  = o.Intercept;
            _slope      = o.Slope;
            _screen     = Screen.PrimaryScreen.Bounds;
            _conditions = new List <ConditionData>();

            //
            // Create the order of conditions. Nesting is mt%[a[w]]].
            //
            int[] a_order, w_order, mt_order;
            if (o.Randomize) // randomize the order of conditions
            {
                a_order = RandomEx.Array(0, o.A.Length - 1, o.A.Length, true);
                w_order = RandomEx.Array(0, o.W.Length - 1, o.W.Length, true);
                if (o.MTPct != null)
                {
                    mt_order = RandomEx.Array(0, o.MTPct.Length - 1, o.MTPct.Length, true);
                    while (o.MTPct[mt_order[0]] < StatsEx.Mean(o.MTPct)) // enforce that the first MT% condition is >avg(MT%)
                    {
                        mt_order = RandomEx.Array(0, o.MTPct.Length - 1, o.MTPct.Length, true);
                    }
                }
                else
                {
                    mt_order = null;
                }
            }
            else // in-order arrays
            {
                a_order = new int[o.A.Length];
                for (int i = 0; i < o.A.Length; i++)
                {
                    a_order[i] = i;
                }
                w_order = new int[o.W.Length];
                for (int i = 0; i < o.W.Length; i++)
                {
                    w_order[i] = i;
                }
                mt_order = (o.MTPct != null) ? new int[o.MTPct.Length] : null;
                for (int i = 0; o.MTPct != null && i < o.MTPct.Length; i++)
                {
                    mt_order[i] = i;
                }
            }

            //
            // Create the ordered condition list for the first block of all conditions (i.e., one time through).
            //
            int n = 0;

            for (int i = 0; o.MTPct == null || i < o.MTPct.Length; i++)
            {
                for (int j = 0; j < o.A.Length; j++)
                {
                    for (int k = 0; k < o.W.Length; k++)
                    {
                        double        pct   = (o.MTPct != null) ? o.MTPct[mt_order[i]] : -1.0; // MT%
                        double        fitts = o.Intercept + o.Slope * Math.Log((double)o.A[a_order[j]] / o.W[w_order[k]] + 1.0, 2.0);
                        long          mt    = (o.MTPct != null) ? (long)fitts : -1L;           // Fitts' law predicted movement time
                        ConditionData cd    = new ConditionData(0, n++, o.A[a_order[j]], o.W[w_order[k]], pct, mt, o.Trials, o.Practice, o.Is2D);
                        _conditions.Add(cd);
                    }
                }
                if (o.MTPct == null)
                {
                    break;
                }
            }

            //
            // Now possibly replicate the created order multiple times.
            //
            int nConditions = _conditions.Count; // number of conditions in one block

            for (int b = 1; b < o.Blocks; b++)
            {
                for (int c = 0; c < nConditions; c++)
                {
                    ConditionData fx = _conditions[c];
                    ConditionData fc = new ConditionData(b, c, fx.A, fx.W, fx.MTPct, fx.MTPred, o.Trials, o.Practice, o.Is2D);
                    _conditions.Add(fc);
                }
            }
        }