3
$\begingroup$

I am having a VERY hard time capturing when the ball comes into frame in this video

http://www.youtube.com/watch?v=x1V6_OHrXIo

I have no idea what to set the parameters too, and trying random values doesn't seem to help at all, I can't see the pattern to know what effect the numbers are having. This is what I'm attempting.

Background subtraction, or color detection won't work, as they could easily change. I need a more generalized solution.

var laneSixBedRect = new Rectangle(new Point(240, 185), new Size(240, 150));
var laneSixBed = imgSource.GetSubRect(laneSixBedRect);

TrackShot(laneSixBed);

private static void TrackShot(Image<Bgr, byte> laneBed)
{
    var laneBedGray = laneBed.Convert<Gray, byte>();

    var circles = laneBedGray.HoughCircles(
        new Gray(150),  //cannyThreshold
        new Gray(75),   //circleAccumulatorThreshold
        2.0,            //Resolution of the accumulator used to detect centers of the circles
        20.0,           //min distance 
        5,              //min radius
        50              //max radius
        )[0];           //Get the circles from the first channel

    foreach (CircleF circle in circles)
        laneBed.Draw(circle, new Bgr(Color.Brown), 2);
}

Edit: This is my currentTrackShot method, it's running about 70% as far as accuracy, still some false positives, and some missed positives.

    private static void TrackShot(Rectangle laneRect, Image<Bgr, byte> prevImage, Image<Bgr, byte> currImage, Image<Bgr, byte> background)
    {
        var laneBedBack = background.GetSubRect(laneRect);
        var laneBedPrev = prevImage.GetSubRect(laneRect);
        var laneBedCurr = currImage.GetSubRect(laneRect);

        var laneBedBackGray = laneBedBack.Convert<Gray, byte>();
        //TODO: Should these be Smoothed?
        var laneBedPrevGray = laneBedPrev.Convert<Gray, byte>().SmoothGaussian(5);
        var laneBedCurrGray = laneBedCurr.Convert<Gray, byte>().SmoothGaussian(5);

        //TODO: Uncomment to see difference between frames, nearly black when no motion
        //var diff = laneBedPrevGray.AbsDiff(laneBedCurrGray);
        //diff.Convert<Bgr, byte>().CopyTo(laneBedCurr);

        //TODO: Improve these values
        var prevFeatures = laneBedPrevGray.GoodFeaturesToTrack(100, .01, .1, 3)[0];

        var returnFeatures = new PointF[1];
        byte[] status;
        float[] trackError;
        OpticalFlow.PyrLK(laneBedPrevGray, laneBedCurrGray, prevFeatures, new Size(15, 15), 5, new MCvTermCriteria(5), out returnFeatures, out status, out trackError);

        //TODO: Now how do I refine this???
        for (var i = 0; i < returnFeatures.Length; i++)
        {
            var prevPoint = prevFeatures[i];
            var currPoint = returnFeatures[i];
            var state = status[i];
            var error = trackError[i];

            var line = new LineSegment2D(new Point((int)prevPoint.X, (int)prevPoint.Y), new Point((int)currPoint.X, (int)currPoint.Y));
            if (state == 1 && line.Length > 15 && error < 10)
            {
                laneBedCurr.Draw(line, new Bgr(Color.Green), 3);
                Console.WriteLine("E: {0}", error);
                Console.WriteLine("L: {0}", line.Length);
            }
        }

        viewerModified.Image = currImage;
    }

EDIT2: My ulimate goal is to be able to draw a line along the trajectory the ball took and store that trajectory in some fashion that can be compared to others.

$\endgroup$
4
$\begingroup$

Remove things you don't want

Since the camera is static, you might want to use a background remover first. I found that the standard one provided with OpenCV works pretty well. I create it like this in the Android OpenCV SDK (you can play with the parameters) :

backgroundSubtractor = new BackgroundSubtractorMOG(3, 4, 0.8);

Then, apply it to each image in your video (no need to re-instantiate it unless you move the camera, it will learn from the sequence of images).

Computing the motion

First, using the Hough Transform for fast-moving shapes isn't very useful. The Hough transform requires you to be able to detect the shape's boundary with some accuracy, which obviously you can't, thanks to the motion blur.

I would suggest looking into algorithms for computing the optical flow. I don't know how close EmguCV is to the original OpenCV, but you could try calcOpticalFlowPyrLK (computes the flow for a set of points in the image, usually obtained using the goodFeaturesToTrack method) or calcOpticalFlowFarneback (computes a dense flow for the whole image, but more CPU-hungry).

Additionally, there have been some people working on CUDA/GLSL versions of Lucas-Kanade (the first one) if you really want to have a fast, dense flow algorithm, but I haven't seen a lot of useful implementations.

See the OpenCV documentation here : http://opencv.willowgarage.com/documentation/cpp/motion_analysis_and_object_tracking.html#calcOpticalFlowPyrLK

$\endgroup$
  • $\begingroup$ EmguCV is just a C# wrapper for OpenCV, it seems to have most everything covered. $\endgroup$ – CaffGeek Sep 11 '12 at 19:02
  • $\begingroup$ Then you're probably okay with that! Does your camera move, or is it static? It's much, much easier for the latter! $\endgroup$ – F.X. Sep 11 '12 at 19:04
  • $\begingroup$ It will be static. However, there could be other things moving in the image. But that's a problem for later. Right now I just want to detect the motion of a ball moving in the frame. $\endgroup$ – CaffGeek Sep 11 '12 at 19:08
  • $\begingroup$ See updated answer then, you might want to use the background removed included in OpenCV before doing any work! $\endgroup$ – F.X. Sep 11 '12 at 19:17
  • 2
    $\begingroup$ Since the camera is static, you should be able to leverage prior knowledge, such as the fact that the balls only move through fixed planes, namely the alley. $\endgroup$ – Maurits Sep 11 '12 at 19:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.