Exemple #1
0
        private void StartStopTaskButton_Click(object sender, EventArgs e)
        {
            taskStarted = !taskStarted;

            LockToCurrentTaskCheckbox.Checked = true;

            int prevPhase = currPhase;

            while (currPhase < 0 || !phases[currPhase].Contains("Testing"))
            {
                currPhase++;
                if (currPhase >= phases.Count)
                {
                    currPhase = prevPhase; break;
                }
            }
            SetPhase(currPhase != prevPhase);

            Logging.LogUIEvent("Task " + (taskStarted ? "started" : "stopped") + ": " + TaskChooser.Text);

            if (taskStarted)
            {
                OnTaskStarted(TaskChooser.Text);
            }

            StartStopTaskButton.Text = taskStarted ? "Stop" : "Start";

            GestureActionMap.Reset();
            GestureActionMap.CurrentTask = TaskChooser.Text;
        }
Exemple #2
0
 private void RandomizeSubmenusButton_Click(object sender, EventArgs e)
 {
     if (Properties.Settings.Default.RandomizeOrders)
     {
         GestureActionMap.RandomizeMenuItems();
     }
 }
Exemple #3
0
        private void ParticipantIDChooser_TextUpdate(object sender, EventArgs e)
        {
            Properties.Settings.Default.LastParticipant = ParticipantIDChooser.Text;
            Properties.Settings.Default.Save();

            // TODO: reset logging?
            if (Properties.Settings.Default.RandomizeOrders)
            {
                GestureActionMap.RandomizeMenuItems();
            }
            SetTasks();
            RandomizeTasks();
        }
Exemple #4
0
        private void ModeChooser_SelectedIndexChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.TestingMode = (string)ModeChooser.SelectedItem;
            if (((string)ModeChooser.SelectedItem).Contains("Testing: "))
            {
                Properties.Settings.Default.GestureMode = ((string)ModeChooser.SelectedItem).Replace("Testing: ", "");
            }
            Properties.Settings.Default.Save();

            if (((string)ModeChooser.SelectedItem).Contains("Testing: "))
            {
                if (Properties.Settings.Default.RandomizeOrders)
                {
                    GestureActionMap.RandomizeMenuItems();
                    RandomizeTasks();
                }

                TaskChooser.SelectedIndex = 0;

                if (runningParticipant)
                {
                    EnableSpeechCheckbox.Checked          = true;
                    EnableApplicationDemoCheckbox.Checked = true;
                    LockToCurrentTaskCheckbox.Checked     = false;
                }
            }
            else
            {
                if (runningParticipant)
                {
                    EnableSpeechCheckbox.Checked          = false;
                    EnableApplicationDemoCheckbox.Checked = false;
                    LockToCurrentTaskCheckbox.Checked     = false;
                }
            }
            GestureActionMap.Reset();

            Logging.LogUIEvent("Mode Set: " + ModeChooser.SelectedItem);
        }
Exemple #5
0
        public void FinishTask()
        {
            taskStarted = false;

            Invoke(new MethodInvoker(delegate
            {
                Logging.LogUIEvent("Task finished: " + TaskChooser.Text);

                if (TaskChooser.SelectedIndex + 1 < TaskChooser.Items.Count)
                {
                    TaskChooser.SelectedIndex++;
                }
                else
                {
                    currPhase++; SetPhase();
                }

                StartStopTaskButton.Text = "Start";

                GestureActionMap.Reset();

                OnTaskFinished(TaskChooser.Text);
            }));
        }
Exemple #6
0
 private void ResetMenuLocationButton_Click(object sender, EventArgs e)
 {
     GestureActionMap.Reset();
 }
Exemple #7
0
        public OnBodyInputRealtimeExperiments()
        {
            InitializeComponent();

            Location = Properties.Settings.Default.MainLocation;
            Size     = Properties.Settings.Default.MainSize;

            captureSound = new SoundPlayer("sounds\\camera_capture.wav");
            tickSound    = new SoundPlayer("sounds\\tick.wav");
            beepSound    = new SoundPlayer("sounds\\camera_beep.wav");
            phoneSound   = new SoundPlayer("sounds\\phone.wav");
            speech.Rate  = 2;

            captureSound.LoadAsync();
            tickSound.LoadAsync();
            beepSound.LoadAsync();

            timer.Elapsed         += Timer_Elapsed;
            CountdownLabel.Parent  = Display;
            numLocationPredictions = Properties.Settings.Default.PredictionSmoothing;

            Text = "Connecting to Camera and Sensors...";

            // set up the gestures and menus
            GestureActionMap.LoadMacros(File.ReadAllText("defaults/macros.txt"));
            GestureActionMap.LoadMenus(File.ReadAllText("defaults/menus.txt"));
            GestureActionMap.LoadActions(File.ReadAllText("defaults/actions.txt"));

            // needs to be initialized after the GestureActionMap
            testingForm = new TestingForm();

            testingForm.TaskStarted += (string task) =>
            {
                speech.SpeakAsyncCancelAll();
                speech.SelectVoice(TestingVoice);
                speech.SpeakAsync("Begin");
            };

            testingForm.TaskFinished += (string task) =>
            {
                speech.SpeakAsyncCancelAll();
                speech.SelectVoice(TestingVoice);
                speech.SpeakAsync("Task Completed");
            };

            //trainingForm.TrainingDataUpdated += () => { UpdateTrainingLabel(); };
            trainingForm.RecordLocation += (string coarseLocation, string fineLocation) =>
            {
                Logging.LogTrainingEvent("prepare_to_capture_location");
                coarseLocationToTrain = coarseLocation;
                fineLocationToTrain   = fineLocation;

                // change the countdown timer setting if you don't want to capture the sample immediately (useful if you're training on yourself, for example)
                countdown = Properties.Settings.Default.CountdownTimer;
                if (countdown > 0)
                {
                    tickSound.Play();
                    CountdownLabel.Text    = countdown.ToString();
                    CountdownLabel.Visible = true;
                    timer.Start();
                }
                else
                {
                    if (Properties.Settings.Default.EnableSoundEffects)
                    {
                        captureSound.Play();
                    }
                    ImageTemplate newTemplate = AddTemplate();
                    Logging.LogTrainingEvent("Added template: " + newTemplate["coarse"] + " " + newTemplate["fine"]);
                    //trainingForm.UpdateLocationList();
                }
            };
            trainingForm.RecordGesture += (string gesture) =>
            {
                Logging.LogTrainingEvent("start_recording_gesture");
                if (Properties.Settings.Default.EnableSoundEffects)
                {
                    beepSound.Play();
                }
                gestureToTrain   = gesture;
                recordingGesture = true;
            };
            trainingForm.AutoCaptureGesture += (string gesture) =>
            {
                Logging.LogTrainingEvent("start_autocapture_gesture");
                if (Properties.Settings.Default.EnableSoundEffects)
                {
                    beepSound.Play();
                }
                gestureToTrain   = gesture;
                autoTrainGesture = true;
            };
            trainingForm.StopAutoCapturingGestures += () =>
            {
                Logging.LogTrainingEvent("stop_autocapture_gesture");
                autoTrainGesture = false;
                GestureRecognition.Train();
                trainingForm.UpdateGestureList();
            };
            trainingForm.AutoCaptureLocation += (string coarseLocation, string fineLocation) =>
            {
                coarseLocationToTrain = coarseLocation;
                fineLocationToTrain   = fineLocation;

                Logging.LogTrainingEvent("start_autocapture_location");

                countdown = Properties.Settings.Default.CountdownTimer;
                if (countdown > 0)
                {
                    prepareToAutoTrainLocation = true;
                    tickSound.Play();
                    CountdownLabel.Text    = countdown.ToString();
                    CountdownLabel.Visible = true;
                    timer.Start();
                }
                else
                {
                    if (Properties.Settings.Default.EnableSoundEffects)
                    {
                        beepSound.Play();
                    }
                    autoTrainLocation = true;
                }
            };
            trainingForm.StopAutoCapturingLocation += () =>
            {
                autoTrainLocation = false;
                Logging.LogTrainingEvent("stop_autocapture_location");
            };

            TouchSegmentation.TouchDownEvent += () =>
            {
                touchDown                   = true;
                hovering                    = false;
                hoverCoarseLocation         = null;
                hoverFineLocation           = null;
                touchStart                  = DateTime.Now;
                Sensors.Instance.Brightness = ledMaxBrightness;

                Logging.LogOtherEvent("touch_down");

                // reset the location predictions
                if (!recentTouchUp)
                {
                    while (coarseLocationProbabilities.Count > 0)
                    {
                        coarseLocationProbabilities.Take();
                    }
                    while (fineLocationProbabilities.Count > 0)
                    {
                        fineLocationProbabilities.Take();
                    }
                    while (gestureCoarseLocationProbabilities.Count > 0)
                    {
                        gestureCoarseLocationProbabilities.Take();
                    }
                    while (gestureFineLocationProbabilities.Count > 0)
                    {
                        gestureFineLocationProbabilities.Take();
                    }
                    while (coarseLocationPredictions.Count > 0)
                    {
                        coarseLocationPredictions.Take();
                    }
                    while (gestureCoarseLocationPredictions.Count > 0)
                    {
                        gestureCoarseLocationPredictions.Take();
                    }
                    while (gestureFocusWeights.Count > 0)
                    {
                        gestureFocusWeights.Take();
                    }
                    while (gestureSensorReadings.Count > 0)
                    {
                        gestureSensorReadings.Take();
                    }
                    foreach (Sensors.Reading reading in sensorReadingHistory)
                    {
                        gestureSensorReadings.Add(reading);
                    }
                    Logging.LogOtherEvent("smoothing_reset");
                }

                Invoke(new MethodInvoker(delegate { TouchStatusLabel.Text = "Touch Down"; }));
            };
            TouchSegmentation.TouchUpEvent += () =>
            {
                touchDown     = false;
                recentTouchUp = true;
                Invoke(new MethodInvoker(delegate { TouchStatusLabel.Text = "Touch Up"; }));
                Logging.LogOtherEvent("touch_up");

                // trigger an event after a short delay to prevent false positives and allow for the double-tap gesture
                // it is cancelled if the user touches down again within that time
                Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(touchUpDelay);
                    recentTouchUp = false;
                    if (!touchDown)
                    {
                        Logging.LogOtherEvent("touch_up_timeout");
                        Sensors.Instance.Brightness = 0;

                        if (autoTrainLocation)
                        {
                            autoTrainLocation = false;
                            trainingForm.StopAutoCapture();
                        }

                        if ((hovering && !recordingGesture && !autoTrainGesture) || trainingForm.Training)
                        {
                            return;
                        }

                        // process the gesture

                        Gesture gesture = new Gesture(gestureSensorReadings.ToArray());
                        if (gestureSensorReadings.Count > 60)
                        {
                            GestureRecognition.PreprocessGesture(gesture);

                            if (recordingGesture || autoTrainGesture)
                            {
                                //Monitor.Enter(recognitionLock);

                                recordingGesture = false;

                                if (Properties.Settings.Default.EnableSoundEffects)
                                {
                                    captureSound.Play(); Logging.LogAudioEvent("capture", false);
                                }

                                DateTime start    = DateTime.Now;
                                gesture.ClassName = gestureToTrain;
                                GestureRecognition.AddTrainingExample(gesture, gestureToTrain);
                                Logging.LogTrainingEvent("Add gesture: " + gestureToTrain);
                                if (!autoTrainGesture)
                                {
                                    GestureRecognition.Train();
                                    Debug.WriteLine("Training: " + (DateTime.Now - start).TotalMilliseconds + " ms");
                                }

                                start = DateTime.Now;
                                if (!autoTrainGesture)
                                {
                                    //trainingForm.UpdateGestureList();
                                    trainingForm.AddGesture(gesture);
                                    Debug.WriteLine("Updating List: " + (DateTime.Now - start).TotalMilliseconds + " ms");
                                }

                                //Monitor.Exit(recognitionLock);
                            }
                            else
                            {
                                gesture.ClassName = GestureRecognition.PredictGesture(gesture);
                            }
                        }

                        Monitor.Enter(recognitionLock);

                        // predict the most likely location over the coarse of the gesture, weighted by voting and image focus
                        Dictionary <string, float>[] tempCoarseProbabilities = gestureCoarseLocationProbabilities.ToArray();
                        Dictionary <string, float>[] tempFineProbabilities   = gestureFineLocationProbabilities.ToArray();
                        string[] tempCoarsePredictions = gestureCoarseLocationPredictions.ToArray();
                        float[] tempFocusWeights       = gestureFocusWeights.ToArray();

                        // sum up the probabilities
                        Dictionary <string, float> totalProbabilities = new Dictionary <string, float>();
                        //foreach (Dictionary<string, float> probabilities in gestureCoarseLocationProbabilities)
                        for (int i = 0; i < tempCoarseProbabilities.Length; i++)
                        {
                            Dictionary <string, float> probabilities = tempCoarseProbabilities[i];
                            float weight = Math.Max(tempFocusWeights.Length > i ? tempFocusWeights[i] : 0.01f, 0.01f);
                            foreach (string key in probabilities.Keys)
                            {
                                if (!totalProbabilities.ContainsKey(key))
                                {
                                    totalProbabilities[key] = 0;
                                }
                                totalProbabilities[key] += weight * probabilities[key] / numLocationPredictions;
                            }
                        }

                        float maxProb           = 0;
                        string coarseLocation   = "";
                        float coarseProbability = 0;
                        foreach (string key in totalProbabilities.Keys)
                        {
                            if (totalProbabilities[key] > maxProb)
                            {
                                maxProb           = totalProbabilities[key];
                                coarseLocation    = key;
                                coarseProbability = maxProb;
                            }
                        }

                        // sum up the probabilities
                        totalProbabilities = new Dictionary <string, float>();
                        //foreach (Dictionary<string, float> probabilities in gestureFineLocationProbabilities)
                        for (int i = 0; i < tempFineProbabilities.Length; i++)
                        {
                            if (i < tempCoarsePredictions.Length && tempCoarsePredictions[i] == coarseLocation)
                            {
                                Dictionary <string, float> probabilities = tempFineProbabilities[i];
                                float weight = Math.Max(tempFocusWeights.Length > i ? tempFocusWeights[i] : 0.01f, 0.01f);
                                foreach (string key in probabilities.Keys)
                                {
                                    if (!totalProbabilities.ContainsKey(key))
                                    {
                                        totalProbabilities[key] = 0;
                                    }
                                    totalProbabilities[key] += weight * probabilities[key] / numLocationPredictions;
                                }
                            }
                        }

                        maxProb               = 0;
                        string fineLocation   = "";
                        float fineProbability = 0;
                        foreach (string key in totalProbabilities.Keys)
                        {
                            if (totalProbabilities[key] > maxProb)
                            {
                                maxProb         = totalProbabilities[key];
                                fineLocation    = key;
                                fineProbability = maxProb;
                            }
                        }

                        Logging.LogGestureEvent(gesture.ClassName, coarseLocation + " " + fineLocation, gesture);

                        Monitor.Exit(recognitionLock);

                        if (fineLocation == "")
                        {
                            Debug.WriteLine("Error");
                        }

                        Invoke(new MethodInvoker(delegate
                        {
                            CoarsePredictionLabel.Text  = "= " + coarseLocation;
                            CoarseProbabilityLabel.Text = " (response = " + (coarseProbability * 100).ToString("0.0") + ")";
                            FinePredictionLabel.Text    = "= " + fineLocation;
                            FineProbabilityLabel.Text   = " (response = " + (fineProbability * 100).ToString("0.0") + ")";
                            GesturePredictionLabel.Text = gesture.ClassName;
                            if (Properties.Settings.Default.EnableSpeechOutput)
                            {
                                if (Properties.Settings.Default.EnableApplicationDemos)
                                {
                                    string actionResult = GestureActionMap.PerformAction(gesture.ClassName, coarseLocation, fineLocation, Properties.Settings.Default.GestureMode, Properties.Settings.Default.FixedApplicationResponses, lockToCurrentTask: Properties.Settings.Default.LockToCurrentTask);
                                    if (actionResult != null && actionResult.Length > 0)
                                    {
                                        speech.SpeakAsyncCancelAll();
                                        speech.SelectVoice(MenuVoice);
                                        //speech.SpeakAsync(gesture.ClassName + " " + coarseLocation + " " + fineLocation);
                                        speech.SpeakAsync(actionResult);
                                        Logging.LogAudioEvent(actionResult);
                                    }
                                }
                                else
                                {
                                    speech.SpeakAsyncCancelAll();
                                    speech.SelectVoice(MenuVoice);
                                    speech.SpeakAsync(gesture.ClassName + " " + coarseLocation + " " + fineLocation);
                                    Logging.LogAudioEvent(gesture.ClassName + " " + coarseLocation + " " + fineLocation);
                                }
                            }
                        }));
                    }
                });
            };

            // Initialize the camera and other sensors in a background thread to avoid hanging the UI
            Task.Factory.StartNew(() =>
            {
                Camera.Instance.FrameAvailable += Camera_FrameAvailable;
                Camera.Instance.Error          += (string error) =>
                {
                    Debug.WriteLine(error);
                    Invoke(new MethodInvoker(delegate { Text = "Error: could not connect to camera"; }));
                };
                Camera.Instance.Brightness = Properties.Settings.Default.CameraBrightness;

                Sensors.Instance.ReadingAvailable += Sensors_ReadingAvailable;

                Camera.Instance.Connect(); Logging.LogOtherEvent("camera_connected");
                Sensors.Instance.Connect(Properties.Settings.Default.SensorPort); Logging.LogOtherEvent("sensors_connected");

                Sensors.Instance.NumSensors = Properties.Settings.Default.SingleIMU ? 1 : 2;

                Invoke(new MethodInvoker(delegate
                {
                    if (Properties.Settings.Default.TrainingVisible)
                    {
                        trainingToolStripMenuItem.PerformClick();
                    }
                    if (Properties.Settings.Default.SettingsVisible)
                    {
                        settingsToolStripMenuItem.PerformClick();
                    }
                    if (Properties.Settings.Default.TestingVisible)
                    {
                        testingToolStripMenuItem.PerformClick();
                    }
                }));
            });
        }
Exemple #8
0
        void Camera_FrameAvailable(VideoFrame frame)
        {
            if (closing)
            {
                return;
            }

            numLocationPredictions = Properties.Settings.Default.TestingMode.Contains("Training") ? 1 : Properties.Settings.Default.PredictionSmoothing;

            ImageTemplate template = new ImageTemplate(frame.Clone());

            FPS.Camera.Update();

            Task.Factory.StartNew(() =>
            {
                try
                {
                    Logging.LogVideoFrame(frame.Image.Bitmap);

                    float focus = 0;
                    //lock (processingLock)
                    if (Monitor.TryEnter(preprocessingLock))
                    {
                        ImageProcessing.ProcessTemplate(template, false);
                        focus = ImageProcessing.ImageFocus(template);
                        Logging.LogFrameProcessed();
                        currTemplate = template;
                        FPS.Instance("processing").Update();
                        Monitor.Exit(preprocessingLock);
                    }
                    else
                    {
                        return;
                    }

                    string coarseLocation          = "", fineLocation = "";
                    float coarseProbability        = 0, fineProbability = 0;
                    bool hasUpdate                 = false;
                    string predictedCoarseLocation = "", predictedFineLocation = "";
                    if (touchDown && !trainingForm.Training && Monitor.TryEnter(recognitionLock))
                    {
                        try
                        {
                            if (Localization.Instance.GetNumTrainingExamples() > 0)
                            {
                                Dictionary <string, float> coarseProbabilities = new Dictionary <string, float>();
                                predictedCoarseLocation = Localization.Instance.PredictCoarseLocation(currTemplate, out coarseProbabilities);
                                //coarseLocationPredictions.Add(predictedCoarseLocation);
                                //while (coarseLocationPredictions.Count > numLocationPredictions) coarseLocationPredictions.Take();
                                coarseLocationProbabilities.Add(coarseProbabilities);
                                gestureCoarseLocationProbabilities.Add(coarseProbabilities);
                                while (coarseLocationProbabilities.Count > numLocationPredictions)
                                {
                                    coarseLocationProbabilities.Take();
                                }

                                //// compute the mode of the array
                                //var groups = coarseLocationPredictions.GroupBy(v => v);
                                //int maxCount = groups.Max(g => g.Count());
                                //coarseLocation = groups.First(g => g.Count() == maxCount).Key;

                                // sum up the probabilities
                                Dictionary <string, float> totalProbabilities = new Dictionary <string, float>();
                                foreach (Dictionary <string, float> probabilities in coarseLocationProbabilities)
                                {
                                    foreach (string key in probabilities.Keys)
                                    {
                                        if (!totalProbabilities.ContainsKey(key))
                                        {
                                            totalProbabilities[key] = 0;
                                        }
                                        totalProbabilities[key] += probabilities[key] / numLocationPredictions;
                                    }
                                }

                                float maxProb = 0;
                                foreach (string key in totalProbabilities.Keys)
                                {
                                    if (totalProbabilities[key] > maxProb)
                                    {
                                        maxProb           = totalProbabilities[key];
                                        coarseLocation    = key;
                                        coarseProbability = maxProb;
                                    }
                                }

                                coarseLocationPredictions.Add(coarseLocation);
                                gestureCoarseLocationPredictions.Add(coarseLocation);
                                while (coarseLocationPredictions.Count > numLocationPredictions)
                                {
                                    coarseLocationPredictions.Take();
                                }

                                if (!Properties.Settings.Default.CoarseOnly)
                                {
                                    bool foundFeatureMatch = false;
                                    Dictionary <string, float> fineProbabilities = new Dictionary <string, float>();
                                    predictedFineLocation = Localization.Instance.PredictFineLocation(currTemplate, out foundFeatureMatch, out fineProbabilities, true, false, false, coarseLocation);
                                    //fineLocationPredictions.Add(predictedFineLocation);
                                    //while (fineLocationPredictions.Count > numLocationPredictions) fineLocationPredictions.Take();
                                    fineLocationProbabilities.Add(fineProbabilities);
                                    gestureFineLocationProbabilities.Add(fineProbabilities);
                                    while (fineLocationProbabilities.Count > numLocationPredictions)
                                    {
                                        fineLocationProbabilities.Take();
                                    }

                                    // compute the mode of the array
                                    //var groups = fineLocationPredictions.GroupBy(v => v);
                                    //int maxCount = groups.Max(g => g.Count());
                                    //fineLocation = groups.First(g => g.Count() == maxCount).Key;

                                    // sum up the probabilities
                                    totalProbabilities = new Dictionary <string, float>();
                                    //foreach (Dictionary<string, float> probabilities in fineLocationProbabilities)
                                    for (int fineIndex = 0; fineIndex < fineLocationProbabilities.Count; fineIndex++)
                                    {
                                        Dictionary <string, float> probabilities = fineLocationProbabilities.ToArray()[fineIndex];

                                        // make sure that the fine prediction matches the classes for the coarse prediction
                                        if (coarseLocationPredictions.ToArray()[fineIndex] == coarseLocation)
                                        {
                                            foreach (string key in probabilities.Keys)
                                            {
                                                if (!totalProbabilities.ContainsKey(key))
                                                {
                                                    totalProbabilities[key] = 0;
                                                }
                                                totalProbabilities[key] += probabilities[key] / numLocationPredictions;
                                            }
                                        }
                                    }

                                    maxProb = 0;
                                    foreach (string key in totalProbabilities.Keys)
                                    {
                                        if (totalProbabilities[key] > maxProb)
                                        {
                                            maxProb         = totalProbabilities[key];
                                            fineLocation    = key;
                                            fineProbability = maxProb;
                                        }
                                    }
                                }

                                Logging.LogLocationEvent(predictedCoarseLocation + " " + predictedFineLocation, coarseLocation + " " + fineLocation);

                                gestureFocusWeights.Add(focus);

                                FPS.Instance("matching").Update();
                                hasUpdate = true;
                            }

                            if (autoTrainLocation && (coarseLocation != coarseLocationToTrain || fineLocation != fineLocationToTrain) && Monitor.TryEnter(trainingLock))
                            {
                                trainingForm.Training     = true;
                                ImageTemplate newTemplate = CopyTemplate(currTemplate);
                                Invoke(new MethodInvoker(delegate { TrainingLabel.Visible = true; }));
                                if (Properties.Settings.Default.EnableSoundEffects)
                                {
                                    captureSound.Play(); Logging.LogAudioEvent("capture", false);
                                }
                                AddTemplate(newTemplate);
                                Logging.LogTrainingEvent("Added template: " + newTemplate["coarse"] + " " + newTemplate["fine"]);
                                Thread.Sleep(100);
                                //if (Properties.Settings.Default.EnableSoundEffects) { beepSound.Play(); Logging.LogAudioEvent("beep", false); }
                                trainingForm.Training = false;
                                Invoke(new MethodInvoker(delegate { TrainingLabel.Visible = false; }));
                                Monitor.Exit(trainingLock);
                                return;
                            }

                            if ((DateTime.Now - touchStart).TotalMilliseconds > Properties.Settings.Default.HoverTimeThreshold)
                            {
                                hovering = true;
                                //if (hoverCoarseLocation == null || coarseLocation == hoverCoarseLocation) // make sure we have the same coarse location, to help prevent jumping around
                                {
                                    hoverCoarseLocation = coarseLocation;
                                    if (hoverFineLocation == null || fineLocation != hoverFineLocation) // make sure we haven't reported the fine location already
                                    {
                                        hoverFineLocation = fineLocation;
                                        Debug.WriteLine(hoverCoarseLocation + " " + hoverFineLocation);
                                        Invoke(new MethodInvoker(delegate { GesturePredictionLabel.Text = "Hover"; }));
                                        if (Properties.Settings.Default.EnableSpeechOutput)
                                        {
                                            if (Properties.Settings.Default.EnableApplicationDemos)
                                            {
                                                string actionResult = GestureActionMap.PerformAction("Hover", coarseLocation, fineLocation, Properties.Settings.Default.GestureMode, Properties.Settings.Default.FixedApplicationResponses);
                                                if (actionResult != null && actionResult.Length > 0)
                                                {
                                                    speech.SpeakAsyncCancelAll();
                                                    speech.SelectVoice(MenuVoice);
                                                    speech.SpeakAsync(actionResult);
                                                    Logging.LogAudioEvent(actionResult);
                                                }
                                            }
                                            else
                                            {
                                                speech.SpeakAsyncCancelAll();
                                                speech.SelectVoice(MenuVoice);
                                                speech.SpeakAsync("Hover " + coarseLocation + " " + fineLocation);
                                                Logging.LogAudioEvent("Hover " + coarseLocation + " " + fineLocation);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        finally
                        {
                            Monitor.Exit(recognitionLock);
                        }
                    }

                    //LBP.GetInstance(frame.Image.Size).GetHistogram(frame);
                    Invoke(new MethodInvoker(delegate
                    {
                        Display.Image = frame.Image.Bitmap;
                        if (hasUpdate)
                        {
                            CoarsePredictionLabel.Text  = coarseLocation;
                            CoarseProbabilityLabel.Text = " (response = " + (coarseProbability * 100).ToString("0.0") + ")";
                            //Debug.WriteLine(coarseLocation);
                            FinePredictionLabel.Text  = fineLocation;
                            FineProbabilityLabel.Text = " (response = " + (fineProbability * 100).ToString("0.0") + ")";
                            //Debug.WriteLine(fineLocation);
                        }
                        //else if(!touchDown)
                        //{
                        //    CoarsePredictionLabel.Text = "";
                        //    CoarseProbabilityLabel.Text = "";
                        //    FinePredictionLabel.Text = "";
                        //    FineProbabilityLabel.Text = "";
                        //}
                        //focus = (int)(focus / 100) * 100;
                        Text = FPS.Camera.Average.ToString("0") + " fps camera / " + (Sensors.Instance.IsConnected ? FPS.Sensors.Average.ToString("0") + " fps sensors / " + FPS.Instance("processing").Average.ToString("0") + " fps processing / " + FPS.Instance("matching").Average.ToString("0") + " fps matching" : "Waiting for Sensors") /*+ " / focus = " + focus.ToString("0")*/;
                    }));
                }
                catch { }
            });
        }