EmguCV中的物体跟踪

3
我正在开发一个目标追踪程序,用于追踪未知物体。用户必须在实时视频流中选择要追踪的区域。我的项目与这个视频类似。

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

我已尝试一种方法,但它不够稳健,跟踪器移动很多。所以我要重新开始。请问有人知道如何实现视频中的方法吗?我是emgucv的新手,目前真的不知道从哪里重新开始。
2个回答

9
视频中建议使用模板匹配,由于速度上我认为更可能是使用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中提出,我会尽力帮助。我也会复制并粘贴这个解决方案。
视频中的方法
好吧,我会让你编写大部分代码,因为我时间不够,但实际上用户使用paintbox的点击事件来查找图像中对象的e.X和e.Y位置。模板具有固定的大小,因此为100x100。
Image<Gray, Byte> template_img = Main_Image.Copy(new Rectangle(x, y, 100, 100);

然后,他在原始图像周围设置ROI,以考虑运动。在我们的情况下,假设我们想要一个50像素的模板缓冲区(ROI)。这将等同于初始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 作为全局变量保存的原因。一旦成功匹配模板,我们的 using 语句看起来会更像:

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

除了ROI和模板的矩形大小和位置之外,这基本就是全部内容了。如果你对此有困难,请告诉我,但是代码应该已经准备就绪了。

谢谢,

Chris


我尝试追踪代码,但对于detect object中的大多数方法以及bool success的工作原理感到有些困惑... - e_phi

0
视频似乎使用了类似于Gary Bradski所描述的CAMSHIFT方法。这里是camshift演示应用程序的C++代码(此处链接),我知道它不是C#,但希望可以轻松移植到EmguCV。这里是camshift算法核心的文档。
希望能帮到你!

看看Trashlock视频的顶部评论:“@Computer22Nerd,这主要是模板匹配。但它只绑定在一个小区域内,而不是整个图像上进行匹配。基本上,绿色框是被跟踪的对象,红色框是跟踪区域(将用于测试模板的区域)。当我用鼠标单击时,会定义一个40x40的区域作为模板。一个80x80的区域被定义为搜索区域。这个系统的关键是每帧更新模板,使得跟踪不断变化的对象成为可能。” - Chris
@Chris 很好知道。肯定有比每帧直接暴力创建模板更好的方法。演示的方法也容易出现漂移,这在视频中经常发生。我会看看能否找到我用于此类事情的论文,并发布它。另外,希望你不认为我给你投了反对票,因为你的回答很好。 :) - mevatron
嘿,如果你这样做了那很好,但是方法和它们的能力之间经常存在混淆。我同意,确实有更好的方法,但是仅使用camshift是不合适的(尽管ROI被最小化),因为整个手在移动,即有很多噪音。您需要包括适当的轮廓分析来找到每个帧中手指尖的更可靠参考点。对于EMGU/opencv中的其他人,这将在背景减法/投影方法和“结构分析和形状描述符”下进行。干杯 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接