3

我正在构建一个应该跟踪未知对象的对象跟踪程序。用户必须在实时视频流中选择一个应该被跟踪的区域。我的项目类似于这个视频。

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

我尝试了一种方法,但它不够健壮,并且跟踪器移动很多。所以我又从头开始了。

任何人都知道如何在视频中提出一种方法?我是 emgucv 的新手,到目前为止我真的不知道从哪里开始。

4

2 回答 2

8

该视频建议模板匹配,由于速度的原因,我认为它更有可能是 FFT(快速傅立叶变换)方法,这在 EMGU 中相当容易实现,但很难做到完美。


模板匹配

首先,模板匹配方法我已经创建了一个方法,它将匹配您输入其中的图像中的对象 FFT 仅适用于单光谱图像的颜色,您必须拆分光谱并将结果矩阵添加在一起:

Point Location;

private bool Detect_object(Image<Gray, Byte> Area_Image, Image<Gray, Byte> image_object)
{
    bool success = false;

    //Work out padding array size
    Point dftSize = new Point(Area_Image.Width + (image_object.Width * 2), Area_Image.Height + (image_object.Height * 2));
    //Pad the Array with zeros
    using (Image<Gray, Byte> pad_array = new Image<Gray, Byte>(dftSize.X, dftSize.Y))
    {
        //copy centre
        pad_array.ROI = new Rectangle(image_object.Width, image_object.Height, Area_Image.Width, Area_Image.Height);
        CvInvoke.cvCopy(Area_Image, pad_array, IntPtr.Zero);

        pad_array.ROI = (new Rectangle(0, 0, dftSize.X, dftSize.Y));

        //Match Template
        using (Image<Gray, float> result_Matrix = pad_array.MatchTemplate(image_object, TM_TYPE.CV_TM_CCOEFF_NORMED))
        {
            Point[] MAX_Loc, Min_Loc;
            double[] min, max;
            //Limit ROI to look for Match

            result_Matrix.ROI = new Rectangle(image_object.Width, image_object.Height, Area_Image.Width - image_object.Width, Area_Image.Height - image_object.Height);

            result_Matrix.MinMax(out min, out max, out Min_Loc, out MAX_Loc);

            Location = new Point((MAX_Loc[0].X), (MAX_Loc[0].Y));
            success = true;
            Results =result_Matrix.Convert<Gray,Double>();

        }
    }
    return success;
}

大多数人忘记的是用零填充数组,类似于我们使用零的模板的大小,因为这对 fft 方法没有影响。我们填充矩阵,否则我们不能正确处理边缘周围的数据,我们可能会错过匹配的项目。

第二点,我不能强调这是多么重要,即 FFT 方法将在此刻返回一个匹配对象的左上角。result_Matrix.MinMax 查找对象最有可能匹配的位置。您需要尝试很多东西,所以如果有更多问题可以在这里或 EMGU 提问,我会尽可能提供帮助。我也会复制并粘贴此解决方案。


视频中的方法

好吧,我将让您编写其中的大部分代码,因为我被卡住了时间,但实际上用户使用油漆盒的单击事件来查找图像中对象的设置 eX 和 eY 位置。模板是固定大小的,所以 100x100

Image<Gray, Byte> template_img = Main_Image.Copy(new Rectangle(x, y, 100, 100);

然后,他在对象周围的原始图像上设置一个 ROI,这说明了运动。在我们的例子中,我们想要一个围绕 50 像素的模板的缓冲区 (ROI)。这相当于初始投资回报率:

Main_Image.ROI = new Rectangle(x - 50, y - 50, 200, 200);

现在,由于使用图像的 ROI,我们可以减慢处理速度,并再次弄乱原始图像的显示,因此最好执行以下操作:

using( Image<Gray, Byte> img_ROI = Main_Image.Copy(new Rectangle(x - 50, y - 50, 200, 200))
{
    Detect_object(img_ROI, template_img)
}

我们使用 using 语句,因为这会在我们完成并释放资源时处理额外的图像数据。

现在,对于技巧,ROI 实际上由 Detect_object 的结果控制,这就是我们将 Location 保留为全局变量的原因。一旦 Location 我们成功匹配了模板,我们的 using 语句将看起来更像:

using( Image<Gray, Byte> img_ROI = Main_Image.Copy(new Rectangle(Location.X - 50, Location.Y - 50, 200, 200)) 
{
    ...
}

除了 ROI 和模板的矩形之外,几乎就是这样,如果您有问题,请在图像上绘制大小和位置,让我知道,但代码应该很容易出现

干杯,

克里斯

于 2012-01-06T10:40:36.537 回答
0

该视频似乎使用了类似于Gary Bradski 描述的CAMSHIFT 方法。是 camshift 演示应用程序的 C++ 代码,我知道它不是 C#,但希望它可以轻松移植到 EmguCV。是 camshift 算法核心的文档。

希望有帮助!

于 2012-01-05T14:46:08.237 回答