EmguCV:检测框架中的球

信息处理 计算机视觉 opencv 边缘检测
2022-01-31 07:27:19

在这段视频中,当球进入画面时,我很难捕捉到

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

我也不知道要设置什么参数,而且尝试随机值似乎根本没有帮助,我看不到模式来知道数字有什么影响。这就是我正在尝试的。

背景减法或颜色检测不起作用,因为它们很容易改变。我需要一个更通用的解决方案。

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);
}

编辑:这是我的 currentTrackShot 方法,它的准确率大约为 70%,仍然有一些误报,还有一些漏报。

    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:我的终极目标是能够沿着球的轨迹画一条线,并以某种可以与其他方式进行比较的方式存储该轨迹。

1个回答

删除你不想要的东西

由于相机是静态的,您可能需要先使用背景去除剂。我发现 OpenCV 提供的标准版本运行良好。我在 Android OpenCV SDK 中这样创建它(你可以使用参数):

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

然后,将其应用于视频中的每个图像(除非您移动相机,否则无需重新实例化它,它将从图像序列中学习)。

计算运动

首先,对快速移动的形状使用霍夫变换并不是很有用。霍夫变换要求您能够以一定的精度检测形状的边界,这显然是由于运动模糊而无法做到的。

我建议研究计算光流的算法。我不知道 EmguCV 与原始 OpenCV 有多接近,但您可以尝试calcOpticalFlowPyrLK(计算图像中一组点的流,通常使用该goodFeaturesToTrack方法获得)或calcOpticalFlowFarneback(计算整个图像的密集流,但更多CPU 饥渴)。

此外,如果你真的想要一个快速、密集的流算法,有一些人正在研究 Lucas-Kanade 的 CUDA/GLSL 版本(第一个),但我还没有看到很多有用的实现。

请参阅此处的 OpenCV 文档:http: //opencv.willowgarage.com/documentation/cpp/motion_analysis_and_object_tracking.html#calcOpticalFlowPyrLK