public decimal PredictFrame(Ball b, int frame)
        {
            Image<Bgr, byte> frameImg = video.GetFrame(Camera.StartFrame + frame);

            ErodeDilateSimplifier s = new ErodeDilateSimplifier(Camera.Iterations);
            BgrThresholdsDetector d = new BgrThresholdsDetector(Camera.MinimumThresholds, Camera.MaximumThresholds);

            Image<Bgr, byte> simplifiedFrame = s.Simplify(frameImg);
            Blob prediction = d.Detect(simplifiedFrame);

            if (prediction != null)
            {
                int apparentWidth = (prediction.Contour.BoundingRectangle.Width + prediction.Contour.BoundingRectangle.Height) / 2;
                Distances[frame] = Camera.FocalLength / apparentWidth * b.Diameter;
            }
            else
            {
                Distances[frame] = -1; // Ball could not be located in the frame
            }

            return Distances[frame];
        }
        private void DrawHelperCrossHair(int x, int y)
        {
            ErodeDilateSimplifier simplifier = new ErodeDilateSimplifier((int)configBall_iterations.Value);
            Bitmap erodedBitmap = simplifier.Simplify(video.GetFrame((int)configBall_previewFrame.Value)).ToBitmap();

            Image erodedBitmapCopy = (Image)erodedBitmap.Clone();
            
            Point intercept = new Point((int)(x / zoom - xOffset), (int)(y / zoom - yOffset));

            // Check it is within bounds
            if (intercept.X >= 0 && x < erodedBitmapCopy.Width)
            {
                if (intercept.Y >= 0 && intercept.Y < erodedBitmapCopy.Height)
                {
                    Color point = erodedBitmap.GetPixel(intercept.X, intercept.Y);

                    using (Graphics g = Graphics.FromImage(erodedBitmapCopy))
                    {
                        g.DrawLine(p, new Point(intercept.X, 0), new Point(intercept.X, erodedBitmapCopy.Height));
                        g.DrawLine(p, new Point(0, intercept.Y), new Point(erodedBitmapCopy.Width, intercept.Y));
                        g.Save();
                    }

                    configBall_blue.Text = "Blue: " + point.B;
                    configBall_green.Text = "Green: " + point.G;
                    configBall_red.Text = "Red: " + point.R;
                }
            }

            configBall_helper.Image = erodedBitmapCopy;
        }
        private void UpdatePreview(object sender = null, EventArgs e = null)
        {
            ErodeDilateSimplifier simplifier = new ErodeDilateSimplifier((int)configBall_iterations.Value);
            Image<Bgr, byte> simplifiedImage = simplifier.Simplify(video.GetFrame((int)configBall_previewFrame.Value));

            Bgr minimumThresholds = new Bgr((int)configBall_bMin.Value, (int)configBall_gMin.Value, (int)configBall_rMin.Value);
            Bgr maximumThresholds = new Bgr((int)configBall_bMax.Value, (int)configBall_gMax.Value, (int)configBall_rMax.Value);

            BgrThresholdsDetector detector = new BgrThresholdsDetector(minimumThresholds, maximumThresholds);
            Blob output = detector.Detect(simplifiedImage);

            if(output != null)
                simplifiedImage.Draw(output.Contour, new Bgr(Color.Azure), 0);

            configBall_preview.Image = simplifiedImage.ToBitmap();
        }