Me gustaría hacer detección de movimiento en C# (usando EmguCV 3.0) para eliminar objetos en movimiento o en primer plano para dibujar una superposición.
Aquí hay una prueba de muestra que hice con un Kinect (porque es una cámara de profundidad)
¿Cómo puedo comenzar con EmguCV 3.0?
¿Puede alguien ayudarme a empezar?
EDITADO: 17/06/2015
En EmguCV3.0.0 RC no veo OpticalFlow en el paquete y la documentación: http://www.emgu.com/wiki/files/3.0.0-rc1/document/html/b72c032d-59ae-c36f-5e00-12f8d621dfb8 .htm
Solo hay: DenseOpticalFlow, OpticalFlowDualTVL1 ???
Este es un código AbsDiff:
var grayFrame = frame.Convert<Gray, Byte>(); var motionFrame = grayFrame.AbsDiff(backFrame) .ThresholdBinary(new Gray(20), new Gray(255)) .Erode(2) .Dilate(2); Resultado:
No sé cómo obtener el movimiento en blanco?
Este es el código del 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); } Resultado:
¿Por qué tanto falso positivo?
Este es un código 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) { ... Resultado:
Si selecciono el Área más grande, ¿cómo puedo obtener el contorno del objeto?
Primero, puedo darle un ejemplo de código de flujo óptico.
Deje que oldImage y newImage sean variables que contienen el marco anterior y actual. En mi código, es de tipo 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 (ie, 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 (ie, 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.Con respecto a la cuestión más amplia de cómo eliminar el primer plano:
Si tuviera una forma de obtener una imagen de fondo estática, esa es la mejor manera de comenzar. Luego, el primer plano sería detectado por el método AbsDiff y usando Erode and Dilate o Gaussian para suavizar la imagen, luego usaría la detección de manchas.
Para la detección simple de primer plano, encontré que el flujo óptico era demasiado procesado (8 fps máx.), mientras que el método AbsDiff era igual de preciso pero no tenía efecto en la velocidad de fotogramas.
Con respecto a los contornos, si solo busca encontrar el tamaño, la posición y otros momentos, entonces la detección de manchas en el tutorial de AbsDiff anterior parece ser suficiente, que usa Image.FindContours(...) .
Si no, comenzaría a buscar en la clase CvBlobDetector como se usa en este tutorial . Hay una función DrawBlob incorporada que puede ser útil.