Click here to Skip to main content
Email Password   helpLost your password?

Motion Detector

Introduction

There are many approaches for motion detection in a continuous video stream. All of them are based on comparing of the current video frame with one from the previous frames or with something that we'll call background. In this article, I'll try to describe some of the most common approaches.

In description of these algorithms I'll use the AForge.NET framework, which is described in some other articles on Code Project: [1], [2]. So, if you are common with it, it will only help.

The demo application supports the following types of video sources:

Algorithms

One of the most common approaches is to compare the current frame with the previous one. It's useful in video compression when you need to estimate changes and to write only the changes, not the whole frame. But it is not the best one for motion detection applications. So, let me describe the idea more closely.

Assume that we have an original 24 bpp RGB image called current frame (image), a grayscale copy of it (currentFrame) and previous video frame also gray scaled (backgroundFrame). First of all, let's find the regions where these two frames are differing a bit. For the purpose we can use Difference and Threshold filters.

// create filters

Difference differenceFilter = new Difference( );
IFilter thresholdFilter = new Threshold( 15 );
// set backgroud frame as an overlay for difference filter

differenceFilter.OverlayImage = backgroundFrame;
// apply the filters

Bitmap tmp1 = differenceFilter.Apply( currentFrame );
Bitmap tmp2 = thresholdFilter.Apply( tmp1 );

On this step we'll get an image with white pixels on the place where the current frame is different from the previous frame on the specified threshold value. It's already possible to count the pixels, and if the amount of it will be greater than a predefined alarm level we can signal about a motion event.

But most cameras produce a noisy image, so we'll get motion in such places, where there is no motion at all. To remove random noisy pixels, we can use an Erosion filter, for example. So, we'll get now mostly only the regions where the actual motion was.

// create filter

IFilter erosionFilter = new Erosion( );
// apply the filter 

Bitmap tmp3 = erosionFilter.Apply( tmp2 );

The simplest motion detector is ready! We can highlight the motion regions if needed.

// extract red channel from the original image

IFilter extrachChannel = new ExtractChannel( RGB.R );
Bitmap redChannel = extrachChannel.Apply( image );
//  merge red channel with motion regions

Merge mergeFilter = new Merge( );
mergeFilter.OverlayImage = tmp3;
Bitmap tmp4 = mergeFilter.Apply( redChannel );
// replace red channel in the original image

ReplaceChannel replaceChannel = new ReplaceChannel( RGB.R );
replaceChannel.ChannelImage = tmp4;
Bitmap tmp5 = replaceChannel.Apply( image );

Here is the result of it:

Simplest motion detector

From the above picture we can see the disadvantages of the approach. If the object is moving smoothly we'll receive small changes from frame to frame. So, it's impossible to get the whole moving object. Things become worse, when the object is moving so slowly, when the algorithms will not give any result at all.

There is another approach. It's possible to compare the current frame not with the previous one but with the first frame in the video sequence. So, if there were no objects in the initial frame, comparison of the current frame with the first one will give us the whole moving object independently of its motion speed. But, the approach has a big disadvantage - what will happen, if there was, for example, a car on the first frame, but then it is gone? Yes, we'll always have motion detected on the place, where the car was. Of course, we can renew the initial frame sometimes, but still it will not give us good results in the cases where we can not guarantee that the first frame will contain only static background. But, there can be an inverse situation. If I'll put a picture on the wall in the room? I'll get motion detected until the initial frame will be renewed.

The most efficient algorithms are based on building the so called background of the scene and comparing each current frame with the background. There are many approaches to build the scene, but most of them are too complex. I'll describe here my approach for building the background. It's rather simple and can be realized very quickly.

As in the previous case, let's assume that we have an original 24 bpp RGB image called current frame (image), a grayscale copy of it (currentFrame) and a background frame also gray scaled (backgroundFrame). At the beginning, we get the first frame of the video sequence as the background frame. And then we'll always compare the current frame with the background one. But it will give us the result I've described above, which we obviously don't want very much. Our approach is to "move" the background frame to the current frame on the specified amount (I've used 1 level per frame). We move the background frame slightly in the direction of the current frame - we are changing colors of pixels in the background frame by one level per frame.

// create filter

MoveTowards moveTowardsFilter = new MoveTowards( );
// move background towards current frame

moveTowardsFilter.OverlayImage = currentFrame;
Bitmap tmp = moveTowardsFilter.Apply( backgroundFrame );
// dispose old background

backgroundFrame.Dispose( );
backgroundFrame = tmp;

And now, we can use the same approach we've used above. But, let me extend it slightly to get a more interesting result.

// create processing filters sequence

FiltersSequence processingFilter = new FiltersSequence( );
processingFilter.Add( new Difference( backgroundFrame ) );
processingFilter.Add( new Threshold( 15 ) );
processingFilter.Add( new Opening( ) );
processingFilter.Add( new Edges( ) );
// apply the filter

Bitmap tmp1 = processingFilter.Apply( currentFrame );

// extract red channel from the original image

IFilter extrachChannel = new ExtractChannel( RGB.R );
Bitmap redChannel = extrachChannel.Apply( image );
//  merge red channel with moving object borders

Merge mergeFilter = new Merge( );
mergeFilter.OverlayImage = tmp1;
Bitmap tmp2 = mergeFilter.Apply( redChannel );
// replace red channel in the original image

ReplaceChannel replaceChannel = new ReplaceChannel( RGB.R );
replaceChannel.ChannelImage = tmp2;
Bitmap tmp3 = replaceChannel.Apply( image );
Motion detector - 2nd approach

Now it looks much better!

There is another approach based on the idea. As in the previous cases, we have an original frame and a gray scaled version of it and of the background frame. But let's apply Pixellate filter to the current frame and to the background before further processing.

// create filter

IFilter pixellateFilter = new Pixellate( );
// apply the filter

Bitmap newImage = pixellateFilter( image );

So, we have pixellated versions of the current and background frames. Now, we need to move the background frame towards the current frame as we were doing before. The next change is only the main processing step:

// create processing filters sequence

FiltersSequence processingFilter = new FiltersSequence( );
processingFilter.Add( new Difference( backgroundFrame ) );
processingFilter.Add( new Threshold( 15 ) );
processingFilter.Add( new Dilatation( ) );
processingFilter.Add( new Edges( ) );
// apply the filter

Bitmap tmp1 = processingFilter.Apply( currentFrame );

After merging tmp1 image with the red channel of the original image, we'll get the following image:

Motion detector - 3rd approach

May be it looks not so perfect as the previous one, but the approach has a great possibility for performance optimization.

Looking at the previous picture, we can see, that objects are highlighted with a curve, which represents the moving object's boundary. But sometimes it's more likely to get a rectangle of the object. Not only this, what to do if we want not just highlight the objects, but get their count, position, width and height? Recently I was thinking: "Hmmm, it's possible, but not so trivial". Don't be afraid, it's easy. It can be done using the BlobCounter class from my imaging library, which was developed recently. Using BlobCounter we can get the number of objects, their position and the dimension on a binary image. So, let's try to apply it. We'll apply it to the binary image containing moving objects, the result of Threshold filter.

BlobCounter blobCounter = new BlobCounter( );
...
// get object rectangles

blobCounter.ProcessImage( thresholdedImage );
Rectangle[] rects = BlobCounter.GetObjectRectangles( );
// create graphics object from initial image

Graphics g = Graphics.FromImage( image );
// draw each rectangle

using ( Pen pen = new Pen( Color.Red, 1 ) )
{
    foreach ( Rectangle rc in rects )
    {
        g.DrawRectangle( pen, rc );

        if ( ( rc.Width > 15 ) && ( rc.Height > 15 ) )
        {
            // here we can higligh large objects with something else

        }
    }
}
g.Dispose( );

Here is the result of this small piece of code. Looks pretty. Oh, I forgot. In my original implementation, there is some code instead of that comment for processing large objects. So, we can see a small numbers on the objects.

Motion detector - 4th approach

[14.06.2006] There was a lot of complains that the idea of MoveTowards filter, which is used for updating background image, is hard to understand. So, I was thinking a little bit about changing this filter to something else, which is clearer to understand. And the solution is to use Morph filer, which became available in 2.4 version of AForge.Imaging library. The new filter has two benefits:

The idea of the filter is to preserve specified percentage of the source filter and to add missing percentage from overlay image. So, if the filter was applied to source image with percent value equal to 60%, then the result image will contain 60% of source image and 40% of overlay image. Applying the filter with percent values around 90% makes background image changing continuously to current frame.

Motion Alarm

It is pretty easy to add motion alarm feature to all these motion detection algorithms. Each algorithm calculates a binary image containing difference between current frame and the background one. So, the only we need is to just calculate the amount of white pixels on this difference image.

// Calculate white pixels

private int CalculateWhitePixels( Bitmap image )
{
    int count = 0;
    // lock difference image

    BitmapData data = image.LockBits( new Rectangle( 0, 0, width, height ),
        ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed );
    int offset = data.Stride - width;
    unsafe
    {
        byte * ptr = (byte *) data.Scan0.ToPointer( );
        for ( int y = 0; y < height; y++ )
        {
            for ( int x = 0; x < width; x++, ptr++ )
            {
                count += ( (*ptr) >> 7 );
            }
            ptr += offset;
        }
    }
    // unlock image

    image.UnlockBits( data );
    return count;
}

For some algorithms it could be done even simpler. For example, in blob counting approach we can accumulate not the white pixels count, but the area of each detected object. Then, if the computed amount of changes is greater than a predefined value, we can fire an alarm event.

Video Saving

There are many different ways to process motion alarm event: just draw a blinking rectangle around the video, or play sound to attract attention. But, of course, the most useful one is video saving on motion detection. In the demo application I was using the AVIWriter class, which uses Video for Windows interop to provide AVI files saving capabilities. Here is the small sample of using the class to write small AVI file, which draw diagonal line:

SaveFileDialog sfd = new SaveFileDialog( );
if ( sfd.ShowDialog( ) == DialogResult.OK )
{
    AVIWriter writer = new AVIWriter( "wmv3" );
    try
    {
        writer.Open( sfd.FileName, 320, 240 );
        Bitmap bmp = new Bitmap( 320, 240, PixelFormat.Format24bppRgb );
        for ( int i = 0; i < 100; i++ )
        {
            bmp.SetPixel( i, i, Color.FromArgb( i, 0, 255 - i ) );
            writer.AddFrame( bmp );
        }
        bmp.Dispose( );
    }
    catch ( ApplicationException ex )
    {
    }
    writer.Dispose( );
}

Note: In this small sample and in the demo application I was using Windows Media Video 9 VCM codec.

AForge.NET framework

The Motion Detection application is based on the AForge.NET framework, which provides all the filters and image processing routines used in this application. To get more information about the framework, you may read dedicated article on Code Project or visit project's home page, where you can get all the latest information about it, participate in a discussion group or submit issues or requests for enhancements.

Applications for motion detection

Some people ask me one question from time to time, which is a little bit strange to me. The question is "What is the application for motion detectors". There is a lot to do with them and it depends on the imagination. One of the most straight forward applications is video surveillance, but it is not the only one. Since the first release of this application, I've received many e-mails from different people, who applied this application to incredible things. Some of them have their own articles, so you can take a look:

Conclusion

I've described only ideas here. To use these ideas in real applications, you need to optimize its realization. I've used an image processing library for simplicity, it's not a video processing library. Besides, the library allows me to research different areas more quickly, than to write optimized solutions from the beginning. A small sample of optimization can be found in the sources.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralOutput text file of detections
davegaga
14:26 22 Jan '10  
Hi,

I wanted to incorporate this into my project but with a modification. I would like to somehow create a text file detailing any motions detected above a certain duration (say at least 5seconds) with a time stamp for each entry. Would this be possible?

Cheers
GeneralRe: Output text file of detections
Andrew Kirillov
6:03 23 Jan '10  
Hello,

Yes it is possible. The application already shows blinking red rectangle when motion is detected. You may do similar - save time when motion is detected and then save duration (similar to duration of red rectangle blinking).

With best regards,
Andrew Kirillov
AForge.NET

Generalcan I use surveillance cameras...?
Asanka28864
5:21 18 Jan '10  
Can I use IP Cameras(surveillance cameras) for this,without using web cams....?
GeneralRe: can I use surveillance cameras...?
Andrew Kirillov
7:40 18 Jan '10  
Hello,

Yes, this application can work with IP cameras if they support JPEG or MJPEG stream. Motion detection algorithms don't depend on any particular camera at all.

With best regards,
Andrew Kirillov
AForge.NET

QuestionExhaustive Block Matching sort
ivan_nn2
6:26 8 Jan '10  
Hullo:

I am experiencing a problem with the Exhaustive Block Matching method process image: Is there any way to skip the sorting (by similarity), which is included in this method?
Having a list of multiple points to track, it looks like they are "shuffled", i.e. the i-th tracked point in the Output List<BlockMatch> does not correspond to its relative i-th of the Input List<intPoints>.

Thanks for this!
Ivan
AnswerRe: Exhaustive Block Matching sort
Andrew Kirillov
10:45 8 Jan '10  
Hello,

Not really sure what are you talking about. The methods described in the article don't use any Echaustive Block Matching.

With best regards,
Andrew Kirillov
AForge.NET

GeneralRe: Exhaustive Block Matching sort
ivan_nn2
22:24 10 Jan '10  
I'm sorry, maybe i post in the wrong place....

can i have a link where you talk about Exhaustive block matching?...

thanks....
GeneralFeatures [modified]
JonFrost
20:27 4 Jan '10  
Tuner integration a must, for selective input from tv card or other multi-input device. Still a good sample. WD!!
Generalavi with 2 webcams
ivan_nn2
22:41 29 Dec '09  
Hello...

it's 2 months that i'm trying to use your code for a project..it's very useful...
now i can manage webcams and lan cams. thanks..

I have a question.
I connected 2 logitech webcams (640x480)..

and i would like to save two avi while watching the video.
My first try was to enque the bitmap during the onNewFrame event of the VideoSourcePlayer..
but after a while the memory is full so i had to give up...
I was rying also to save the bitmap while arriving like this

private void onNewFrame_cam2(object sender, ref Bitmap image)
{
if (RecordEnable == true)
{
if (videoSourcePlayer2.VideoSource != null)
{
aviFile2.AddFrame((Bitmap)image.Clone());
}
}
(and another one for the other camera)..

but after a while the cameras start skipping frame and desync each other...

Do i miss something?...

thanks again
GeneralRe: avi with 2 webcams
Andrew Kirillov
5:12 30 Dec '09  
Hello,

I think you create too much garbage, so it takes some time for GC to collect it. Why do you clone image? Don't need doing it in your case. Even if you do so, then you need to dispose the clone.

With best regards,
Andrew Kirillov
AForge.NET

GeneralRe: avi with 2 webcams
ivan_nn2
0:58 31 Dec '09  
...hello... thanks for the answer...

You are right. If i don't make the Clone and i do avi1.Addframe(image)... it's much faster...
But anyhow still skips 2 or 3 frame (and the bigger the avi becomes the greater the number of frames skips...)..
have you got any clue about it?.. or you think it's just too much bytes to write on disk (i have a sata2 anyway)?...
thanks again
GeneralDetect movement from left or from right
ALEXNG88
3:28 28 Dec '09  
I would like to do a simple motion detection that can detect a car from my web cam in which my program can tell you the car is from left to right or from right to left.

So I tried to add something here: My idea is whenever the R,G or B changes, I get the coordinate and decide the direction. However, it will stop capturing the video too

....
thresholdFilter.ApplyInPlace( bitmapData );
// erosion filter
Bitmap tmpImage3 = erosionFilter.Apply( bitmapData );

// unlock temporary image
tmpImage2.UnlockBits( bitmapData );
tmpImage2.Dispose( );

////////////////////////I added here in order to check the pixel changes and get the x , y coordinates/////

for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
//tmpImage3.GetPixel(x, y).ToString();
if ((tmpImage3.GetPixel(x, y).R > 0) || (tmpImage3.GetPixel(x, y).G > 0) || (tmpImage3.GetPixel(x, y).B > 0))
{
Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));
Debug.WriteLine(x.ToString());
Debug.WriteLine(y.ToString());
}
else
{

}

}
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// calculate amount of changed pixels
pixelsChanged = ( calculateMotionLevel ) ?
CalculateWhitePixels( tmpImage3 ) : 0;

// dispose old background
backgroundFrame.Dispose( );
// set backgound to current
backgroundFrame = tmpImage;

.........

Does it achieve my purpose?

Please advise.
GeneralAudio stream
lardpvo
8:13 10 Dec '09  
Hi, congrats on the great work. I have just processed one of my avi files,
and while motion filter gets applied correctly I loose all the audio on the output file.
Is there a way to keep the audio stream ?

Thanks

21212

Questionneed information
mohammad azharruddin
23:31 7 Dec '09  
Hey
I went through the motion algorithm, and i am need of a C code for the removal of shadow from the video frames,
kindly mail me the details and your reply to my question.
my id is moonstruckazhar28@gmail.com

hope to hear soon
GeneralConvert code in vb.net
ste1990
1:06 3 Dec '09  
Hi, i'm going to convert the code in vb.net but i have problem with events
for exampe in camera windows there are this code
camera.NewFrame += new EventHandler( camera_NewFrame );
i've translate it in vb.net addhandler camera.newframe,camera_newframe

but visual studio say me there are a problem..
can we help me?
GeneralConvert code in vb.net
ste1990
22:34 1 Dec '09  
hi, it is possible to have the code converted in vb.net ?
thanks
GeneralRe: Convert code in vb.net
Andrew Kirillov
23:30 1 Dec '09  
Hello,

Yes, it is possible. But, if you need it, then you need to do this on your own.

It is not the first time when I receive such type of requests. Some people want C++, but most people want VB.NET. It is simply amazing that people think that somebody will do their work.

With best regards,
Andrew Kirillov
AForge.NET

GeneralRe: Convert code in vb.net
ste1990
0:31 2 Dec '09  
i don't want you convert the code.
i would say if i convert the code in vb.net it will work
GeneralHow to display video on form load
Member 4700984
21:15 5 Nov '09  
Regarding video

Currently if i click the menu then only the video starting.

But what i want is to load the the video while the form load.

I tried the click "video menu" code on the form onload. But no luck.

Please guide me to fix this problem
Generalvideo streaming using jpg file from local directory
Siddiq Ansari
6:26 1 Nov '09  
It is a great work by you.
I am a college student and also new to c#. How can I perform video streaming using jpg file from local directory (I want help in writing code for this).Hope you will help me without any hesitation.
GeneralRe: video streaming using jpg file from local directory
Andrew Kirillov
0:21 2 Nov '09  
Hello,

What is the aim of streaming single JPG file? Do you want to get video which always shows the same?

When you say 'streaming', what do actually mean? Do you want to send your video over network?

With best regards,
Andrew Kirillov
AForge.NET

GeneralRe: video streaming using jpg file from local directory
Siddiq Ansari
21:19 2 Nov '09  
Thanks for comment.
No, its not streaming a single jpg file, rather if the jpg file is changed continuously with the same filename and we want to display them continuously over camera window then what should be done to do that.
Also, I want to send the video which is being displayed over camera window, then what should be done to send over network?
Thank you...
GeneralRe: video streaming using jpg file from local directory
Andrew Kirillov
23:15 2 Nov '09  
Hello,

If you have directory of JPEG files, then it is quite simple. One of the AForge.NET framework's users did. Here it is[^]. Need to note that this is quick and dirty adaptation of one of the AForge.NET framework's classes. So I would recoment taking idea there only.

With best regards,
Andrew Kirillov
AForge.NET

GeneralRe: video streaming using jpg file from local directory
Siddiq Ansari
8:06 4 Nov '09  
hello, Thank you for this great help...
GeneralYUV Format
Member 2550168
6:18 16 Oct '09  
Hi

I've images in yuv 422 format (fourcc YV16) decoded from an mjpeg ip camera stream, I could also have rgb format, but for performance reasons during h264 post encoding, yuv is better.
Is it possible to apply your fourth algorithm with yuv format or should I convert the images to an rgb format?

Thanks

Marco


Last Updated 27 Mar 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010