Подтвердить что ты не робот

EmguCV: рисовать контур объекта в движении с помощью оптического потока?

Я хотел бы сделать обнаружение движения в С# (используя EmguCV 3.0), чтобы удалить объект в движении или на переднем плане, чтобы нарисовать оверлей.

Вот пример теста, который я сделал с Kinect (потому что это камера глубины) Démo with Kinect

Как я могу начать работу с EmguCV 3.0?

  • Я пробовал много кода удаления фона, которые не работают.
  • Кажется, OpticalFlow - хорошее начало, но нет примера в EmguCV 3.0
  • Если я нахожу самый большой blob, как я могу найти его контуры?

Может кто-нибудь помочь мне начать?

РЕДАКТИРОВАТЬ: 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);

Результат: Demo Diff

Я не знаю, как получить движение в белом?

Это код 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

Если я выбираю самую большую область, как я могу получить контур объекта?

4b9b3361

Ответ 1

Во-первых, я могу привести вам пример кода оптического потока.

Пусть oldImage и newImage - переменные, которые содержат предыдущий и текущий кадры. В моем коде это тип 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 и с помощью Erode и Dilate или Gaussian, чтобы сгладить изображение, затем используйте обнаружение blob.

Для простого обнаружения переднего плана я обнаружил, что Optical Flow слишком много обрабатывает (максимум 8 кадров в секунду), тогда как метод AbsDiff был столь же точным, но не влиял на частоту кадров.

Что касается контуров, если вы просто хотите найти размер, положение и другие моменты, то обнаружение blob в учебнике AbsDiff, как представляется, достаточно, в котором используется Image.FindContours(...).

Если нет, я бы начал рассматривать класс CvBlobDetector, используемый в этот учебник. Там есть встроенная функция DrawBlob, которая может пригодиться.