Emgucv_Motion_Detection_MotionHistory_Human_Activity_in_video
This topic introduces you to the function MotionHistory of emgucv .
The motion history image (MHI) is a static image template helps in understanding the motion location and path as it progresses.
In MHI, the temporal motion information is collapsed into a single image template where intensity is a function of recency of motion.
The MHI pixel intensity is a function of the motion history at that location, where brighter values correspond to a more recent motion.
Using MHI, moving parts of a video sequence can be engraved with a single image, from where one can predict the motion flow as well as the moving parts of the video action.
Video Effect
Algorithm1
=========================================================
for each time t
Bt := absolute_difference(It, It-1) > threshold
end for
=========================================================
Algorithm2
=========================================================
for each time t
for each pixel (x,y)
if Bt(x,y) = 1
MHIt(x,y) := τ
else if MHIt-1 ≠ 0
MHIt(x,y) := MHIt-1(x,y) - 1
else
MHIt(x,y) := 0
end if
end for
=========================================================
If you want to know more information about
motion history
you can see this video
Video1
Video2_Image Moments
Video3_MHI
Code
/*
* Copyright (c) 2016 Samuel <dryjoker007@gmail.com>
*
* BSD Simplified License.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
*
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Util;
using Emgu.CV.Structure;
using Emgu.CV.VideoSurveillance;
using Emgu.CV.CvEnum;
namespace emgucv2._4._2_ex
{
public partial class Form1 : Form
{
private Capture _capture = new Capture();
private MotionHistory _motionHistory;
private IBGFGDetector<Bgr> _forgroundDetector;
public Form1()
{
InitializeComponent();
//try to create the capture
if (_capture == null)
{
try
{
_capture = new Capture();
}
catch (NullReferenceException excpt)
{ //show errors if there is any
MessageBox.Show(excpt.Message);
}
}
if (_capture != null) //if camera capture has been successfully created
{
_motionHistory = new MotionHistory(
1.0, //in second, the duration of motion history you wants to keep
0.05, //in second, maxDelta for cvCalcMotionGradient
0.5); //in second, minDelta for cvCalcMotionGradient
_capture.ImageGrabbed += ProcessFrame;
_capture.Start();
}
}
private void ProcessFrame(object sender, EventArgs e)
{
using (Image<Bgr, Byte> image = _capture.RetrieveBgrFrame())
using (MemStorage storage = new MemStorage()) //create storage for motion components
{
if (_forgroundDetector == null)
{
//_forgroundDetector = new BGCodeBookModel<Bgr>();
//_forgroundDetector = new FGDetector<Bgr>(Emgu.CV.CvEnum.FORGROUND_DETECTOR_TYPE.MOG);
_forgroundDetector = new BGStatModel<Bgr>(image, Emgu.CV.CvEnum.BG_STAT_TYPE.FGD_STAT_MODEL);
}
_forgroundDetector.Update(image);
capturedImageBox.Image = image.Bitmap;
//update the motion history
_motionHistory.Update(_forgroundDetector.ForgroundMask);
//forgroundImageBox.Image = _forgroundDetector.ForgroundMask.Bitmap;
#region get a copy of the motion mask and enhance its color
double[] minValues, maxValues;
Point[] minLoc, maxLoc;
_motionHistory.Mask.MinMax(out minValues, out maxValues, out minLoc, out maxLoc);
Image<Gray, Byte> motionMask = _motionHistory.Mask.Mul(255.0 / maxValues[0]);
#endregion
//create the motion image
Image<Bgr, Byte> motionImage = new Image<Bgr, byte>(motionMask.Size);
//display the motion pixels in blue (first channel)
motionImage[2] = motionMask;
//Threshold to define a motion area, reduce the value to detect smaller motion
double minArea = 150;
storage.Clear(); //clear the storage
Seq<MCvConnectedComp> motionComponents = _motionHistory.GetMotionComponents(storage);
//iterate through each of the motion component
foreach (MCvConnectedComp comp in motionComponents)
{
//reject the components that have small area;
if (comp.area < minArea) continue;
// find the angle and motion pixel count of the specific area
double angle, motionPixelCount;
_motionHistory.MotionInfo(comp.rect, out angle, out motionPixelCount);
//reject the area that contains too few motion
if (motionPixelCount < comp.area * 0.05) continue;
//Draw each individual motion in red
//DrawMotion(motionImage, comp.rect, angle, new Bgr(Color.Red));
}
// find and draw the overall motion angle
double overallAngle, overallMotionPixelCount;
_motionHistory.MotionInfo(motionMask.ROI, out overallAngle, out overallMotionPixelCount);
//DrawMotion(motionImage, motionMask.ROI, overallAngle, new Bgr(Color.Tomato));
//Display the amount of motions found on the current image
UpdateText(String.Format("Total Motions found: {0}; Motion Pixel count: {1}", motionComponents.Total, overallMotionPixelCount));
//Display the image of the motion
motionImageBox.Image = motionImage.Bitmap;
}
}
private void UpdateText(String text)
{
if (InvokeRequired && !IsDisposed)
{
Invoke((Action<String>)UpdateText, text);
}
else
{
label1.Text = text;
}
}
private static void DrawMotion(Image<Bgr, Byte> image, Rectangle motionRegion, double angle, Bgr color)
{
float circleRadius = (motionRegion.Width + motionRegion.Height) >> 2;
Point center = new Point(motionRegion.X + motionRegion.Width >> 1, motionRegion.Y + motionRegion.Height >> 1);
CircleF circle = new CircleF(
center,
circleRadius);
int xDirection = (int)(Math.Cos(angle * (Math.PI / 180.0)) * circleRadius);
int yDirection = (int)(Math.Sin(angle * (Math.PI / 180.0)) * circleRadius);
Point pointOnCircle = new Point(
center.X + xDirection,
center.Y - yDirection);
LineSegment2D line = new LineSegment2D(center, pointOnCircle);
image.Draw(circle, color, 1);
image.Draw(line, color, 2);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
_capture.Stop();
}
}
}
留言
張貼留言