EmguCV:如何使用光流在运动物体上绘制轮廓?

14

我想用C#(使用EmguCV 3.0)进行运动检测,以便移除运动中的对象或前景,并绘制叠加层。

这是我使用Kinect进行的一个样本测试(因为它是深度相机) Démo with Kinect

如何开始使用EmguCV 3.0?

  • 我尝试了很多无法工作的背景去除代码
  • 看起来OpticalFlow是一个不错的开始,但在EmguCV 3.0中没有例子
  • 如果我找到最大的斑点,如何找到它的轮廓?

有人能帮助我入门吗?

编辑:17/06/2015

在EmguCV3.0.0 RC中,我没有在包和文档中看到OpticalFlow: http://www.emgu.com/wiki/files/3.0.0-rc1/document/html/b72c032d-59ae-c36f-5e00-12f8d621dfb8.htm

只有:DenseOpticalFlow、OpticalFlowDualTVL1 ???

这是一个AbsDiff代码:

var grayFrame = frame.Convert<Gray, Byte>();
var motionFrame = grayFrame.AbsDiff(backFrame)
                           .ThresholdBinary(new Gray(20), new Gray(255))
                           .Erode(2) 
                           .Dilate(2);

结果:演示差异

我不知道如何在白色中添加运动效果?

这是Blob代码:

Image<Bgr, Byte> smoothedFrame = new Image<Bgr, byte>(frame.Size);
CvInvoke.GaussianBlur(frame, smoothedFrame, new Size(3, 3), 1); //filter out noises

Mat forgroundMask = new Mat();
fgDetector.Apply(smoothedFrame, forgroundMask);

CvBlobs blobs = new CvBlobs();
blobDetector.Detect(forgroundMask.ToImage<Gray, byte>(), blobs);
blobs.FilterByArea(400, int.MaxValue);
blobTracker.Update(blobs, 1.0, 0, 1);

foreach (var pair in blobs) {
  CvBlob b = pair.Value;
  CvInvoke.Rectangle(frame, b.BoundingBox, new MCvScalar(255.0, 255.0, 255.0), 2);
}

结果: Blob Demo

为什么会有这么多假阳性?

这是一个MOG2代码:

forgroundDetector.Apply(frame, forgroundMask);
motionHistory.Update(forgroundMask);
var motionMask = GetMotionMask();
Image<Bgr, Byte> motionImage = new Image<Bgr, byte>(motionMask.Size);
CvInvoke.InsertChannel(motionMask, motionImage, 0);

Rectangle[] rects;
using (VectorOfRect boundingRect = new VectorOfRect()) {
  motionHistory.GetMotionComponents(segMask, boundingRect);
  rects = boundingRect.ToArray();
}

foreach (Rectangle comp in rects) { ...

结果: MOG2 Demo

如果我选择最大的面积,如何获取物体的轮廓?

1个回答

7

首先,我可以给您一些光流代码示例。

oldImagenewImage成为保存前一帧和当前帧的变量。在我的代码中,它是Image<Gray, Byte>类型。

// prep containers for x and y vectors
Image<Gray, float> velx = new Image<Gray, float>(newImage.Size);
Image<Gray, float> vely = new Image<Gray, float>(newImage.Size);

// use the Horn and Schunck dense optical flow algorithm.
OpticalFlow.HS(oldImage, newImage, true, velx, vely, 0.1d, new MCvTermCriteria(100));

// color each pixel
Image<Hsv, Byte> coloredMotion = new Image<Hsv, Byte>(newImage.Size);
for (int i = 0; i < coloredMotion.Width; i++)
{
    for (int j = 0; j < coloredMotion.Height; j++)
    {
        // Pull the relevant intensities from the velx and vely matrices
        double velxHere = velx[j, i].Intensity;
        double velyHere = vely[j, i].Intensity;

        // Determine the color (i.e, the angle)
        double degrees = Math.Atan(velyHere / velxHere) / Math.PI * 90 + 45;
        if (velxHere < 0)
        {
            degrees += 90;
        }
        coloredMotion.Data[j, i, 0] = (Byte) degrees;
        coloredMotion.Data[j, i, 1] = 255;

        // Determine the intensity (i.e, the distance)
        double intensity = Math.Sqrt(velxHere * velxHere + velyHere * velyHere) * 10;
        coloredMotion.Data[j, i, 2] = (intensity > 255) ? 255 : intensity;
    }
}
// coloredMotion is now an image that shows intensity of motion by lightness
// and direction by color.

关于如何去除前景的更大问题:

如果我有一种获取静态背景图像的方法,那是开始的最佳方式。然后,前景将由AbsDiff方法检测,并使用ErodeDilateGaussian平滑图像,然后使用blob检测。

对于简单的前景检测,我发现光流处理太过繁琐(最高8fps),而AbsDiff方法同样准确但不会影响帧率。
关于轮廓,如果你只是想找到大小、位置和其他时刻,那么上面AbsDiff教程中的blob检测似乎已经足够了,它使用了Image.FindContours(...)
如果不行,我建议看一下this tutorial中使用的CvBlobDetector类。它有一个内置的DrawBlob函数可能会很有用。

谢谢,看起来EmguCV 3中没有光流(OpticalFlow)?只有稠密光流(DenseOpticalFlow)?我错了吗? - Jean-Philippe Encausse
我在背景/前景上尝试了AbsDiff(似乎是最好的),但我无法得到干净的运动物体。我尝试了Blob检测器,但它完全混乱,会检测出太多东西。我还尝试了人体检测,但它不能处理部分人体。 - Jean-Philippe Encausse
还有OpticalFlow.LK(...),使用Lukas-Kanade算法,它在关键点上运行并测量光流。它比密集光流更快,但需要对象具有良好的关键点,并且您不会得到明显的区域。另外,除了AbsDiff之外,您还使用了哪些代码? - Mark Miller
我用示例代码编辑了我的文章。我还链接了3.0.0-rc的文档。我找不到OpticalFlow对象。 - Jean-Philippe Encausse

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