Tuesday, May 22, 2007

Motion Detection using OpenCV

// MotionDetection.cpp : Defines the entry point for the console application.
//


// Contourold.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"

#include "iostream"
#include "stdlib.h"

// OpenCV includes.
#include "cv.h"
#include "highgui.h"
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cxcore.lib")
#pragma comment(lib,"highgui.lib")

using namespace std;

int main(int argc, char* argv[])
{

//Create a new window.
cvNamedWindow("My Window", CV_WINDOW_AUTOSIZE);

//Create a new movie capture object.
CvCapture *input;

//Assign the movie to capture.
//inputMovie = cvCaptureFromAVI("vinoth.avi");

char *fileName = "D:\\highway.avi";
//char *fileName = "D:\\Profile\\AVI\\cardriving.wmv";
input = cvCaptureFromFile(fileName);
if (!input)
{
cout << "Can't open file" << fileName < }


//Size of the image.
CvSize imgSize;
imgSize.width = 352;
imgSize.height = 240;

//Images to use in the program.
IplImage* greyImage = cvCreateImage( imgSize, IPL_DEPTH_8U, 1);
IplImage* colourImage;
IplImage* movingAverage = cvCreateImage( imgSize, IPL_DEPTH_32F, 3);
IplImage* difference;
IplImage* temp;
IplImage* motionHistory = cvCreateImage( imgSize, IPL_DEPTH_8U, 3);

//Rectangle to use to put around the people.
CvRect bndRect = cvRect(0,0,0,0);

//Points for the edges of the rectangle.
CvPoint pt1, pt2;

//Create a font object.
CvFont font;


//Create video to output to.
char* outFilename = argc==2 ? argv[1] : "D:\\outputMovie.avi";
CvVideoWriter* outputMovie = cvCreateVideoWriter(outFilename,
CV_FOURCC('F', 'L', 'V', 'I'), 29.97, cvSize(720, 576));

//Capture the movie frame by frame.
int prevX = 0;
int numPeople = 0;

//Buffer to save the number of people when converting the integer
//to a string.
char wow[65];

//The midpoint X position of the rectangle surrounding the moving objects.
int avgX = 0;

//Indicates whether this is the first time in the loop of frames.
bool first = true;

//Indicates the contour which was closest to the left boundary before the object
//entered the region between the buildings.
int closestToLeft = 0;
//Same as above, but for the right.
int closestToRight = 320;

//Keep processing frames...
for(;;)
{
//Get a frame from the input video.
colourImage = cvQueryFrame(input);

//If there are no more frames, jump out of the for.
if( !colourImage )
{
break;
}

//If this is the first time, initialize the images.
if(first)
{
difference = cvCloneImage(colourImage);
temp = cvCloneImage(colourImage);
cvConvertScale(colourImage, movingAverage, 1.0, 0.0);
first = false;
}
//else, make a running average of the motion.
else
{
cvRunningAvg(colourImage, movingAverage, 0.020, NULL);
}

//Convert the scale of the moving average.
cvConvertScale(movingAverage,temp, 1.0, 0.0);

//Minus the current frame from the moving average.
cvAbsDiff(colourImage,temp,difference);

//Convert the image to grayscale.
cvCvtColor(difference,greyImage,CV_RGB2GRAY);

//Convert the image to black and white.
cvThreshold(greyImage, greyImage, 70, 255, CV_THRESH_BINARY);

//Dilate and erode to get people blobs
cvDilate(greyImage, greyImage, 0, 18);
cvErode(greyImage, greyImage, 0, 10);

//Find the contours of the moving images in the frame.
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contour = 0;
cvFindContours( greyImage, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

//Process each moving contour in the current frame...
for( ; contour != 0; contour = contour->h_next )
{
//Get a bounding rectangle around the moving object.
bndRect = cvBoundingRect(contour, 0);

pt1.x = bndRect.x;
pt1.y = bndRect.y;
pt2.x = bndRect.x + bndRect.width;
pt2.y = bndRect.y + bndRect.height;

//Get an average X position of the moving contour.
avgX = (pt1.x + pt2.x) / 2;

//If the contour is within the edges of the building...
if(avgX > 90 && avgX < 250)
{
//If the the previous contour was within 2 of the left boundary...
if(closestToLeft >= 88 && closestToLeft <= 90)
{
//If the current X position is greater than the previous...
if(avgX > prevX)
{
//Increase the number of people.
numPeople++;

//Reset the closest object to the left indicator.
closestToLeft = 0;
}
}
//else if the previous contour was within 2 of the right boundary...
else if(closestToRight >= 250 && closestToRight <= 252)
{
//If the current X position is less than the previous...
if(avgX < prevX)
{
//Increase the number of people.
numPeople++;

//Reset the closest object to the right counter.
closestToRight = 320;
}
}

//Draw the bounding rectangle around the moving object.
cvRectangle(colourImage, pt1, pt2, CV_RGB(255,0,0), 1);
}

//If the current object is closer to the left boundary but still not across
//it, then change the closest to the left counter to this value.
if(avgX > closestToLeft && avgX <= 90)
{
closestToLeft = avgX;
}

//If the current object is closer to the right boundary but still not across
//it, then change the closest to the right counter to this value.
if(avgX < closestToRight && avgX >= 250)
{
closestToRight = avgX;
}

//Save the current X value to use as the previous in the next iteration.
prevX = avgX;
}


//Write the number of people counted at the top of the output frame.
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.8, 0.8, 0, 2);
cvPutText(colourImage, _itoa(numPeople, wow, 10), cvPoint(60, 200), &font, cvScalar(0, 0, 300));

//Show the frame.
cvShowImage("My Window", colourImage);

//Wait for the user to see it.
cvWaitKey(10);

//Write the frame to the output movie.
cvWriteFrame(outputMovie, colourImage);
}

// Destroy the image, movies, and window.
cvReleaseImage(&temp);
cvReleaseImage(&difference);
cvReleaseImage(&greyImage);
cvReleaseImage(&movingAverage);
cvDestroyWindow("My Window");

cvReleaseCapture(&input);
cvReleaseVideoWriter(&outputMovie);


return 0;

}

Motion detection can be done through this program. this code contains the code for writing the motion detected video to the output file.

Here they hardcoded the values for detecting the people in the video.

we need to remove the code like AvgX,closestToLeft and closestToRight like these ...

it is an enough thing to use the draw the rectangle on all the moving objects.

Labels:

18 Comments:

Anonymous Shervin Emami said...

Hi Sundar,
I wrote some tutorials and free source-code for using OpenCV, such as Face Recognition, Shirt Color Detection, HSV Conversion, etc:

http://www.shervinemami.co.cc/openCV.html

Cheers,
Shervin Emami.

11:31 AM  
Anonymous Matt Williamson said...

Thanks for the sample. I adapted it into Python to suite my needs. More info here: http://appdelegateinc.com/blog/2010/08/02/motion-tracking-with-a-webcam/

10:37 PM  
Anonymous Evil85 said...

I use this linked options:

g++ -L/usr/lib -lcxcore -lcv -lhighgui -lcvaux -lml -o"OpenCVEclipse" ./MyTest.o

but I gave this error:


/home/rjobbagy/workspace/OpenCVEclipse/Debug/../MyTest.cpp:62: undefined reference to `cvCaptureFromFile'

what's wrong?

Thanks your help

12:31 AM  
Anonymous John said...

Hi, I compiled the code successfully but while running it I got an error mssg like:
OpenCV Error: Assertion failed (src.size() == dst.size() && src.channels() == ds
t.channels()) in unknown function, file ..\..\..\src\cxcore\cxconvert.cpp, line
953. what's it??

12:49 AM  
Anonymous Sraddha said...

OpenCV Error: Assertion failed (src.size == dst.size && src.channels() == dst.channels()) in cvConvertScale, file /home/sukrut/OpenCV-2.2.0/modules/core/src/convert.cpp, line 1038

Trying to fix this error , Any help is appreciated.
thanks !

7:05 AM  
Anonymous Sraddha said...

OpenCV Error: Assertion failed (src.size == dst.size && src.channels() == dst.channels()) in cvConvertScale, file /home/sukrut/OpenCV-2.2.0/modules/core/src/convert.cpp, line 1038

Trying to fix this error , Any help is appreciated.
thanks !

7:05 AM  
Anonymous Arash Shafiei said...

The problem is here:

//Size of the image.
CvSize imgSize;
imgSize.width = 352;
imgSize.height = 240;

replace this part with:

//Size of the image.
IplImage* frame = cvQueryFrame(input);
CvSize imgSize = cvGetSize(frame);

2:56 PM  
Anonymous hritikesh said...

Hi,
This is kanitkar .I am looking for the algorithm which can give displacement of the object in terms of pixels and angle from avideo when any vehicle or person comes into picture (assuming camera is stationary).
I am working on thermal images which have low spatial resolution.

12:01 AM  
Anonymous Muhammad Usman Maqbool said...

hi, can you tell me how I use this for video?
and information about visual studio settings plus OpenCv version.

5:41 AM  
Anonymous A said...

I have the sample compile and link fine, but for some reason it crashes at cvAbsDiff(colourImage,temp,difference);

I've made sure arguments are the same size and so on. Any idea what gives?

4:36 AM  
Anonymous kim sen said...

hi!
i debug, opencv error C2275: 'CvSize', error C2065: 'imgSize'...
Trying to fix this error , Any help is appreciated.
thanks !
mail kimsen87dn2006@yahoo.com

10:18 AM  
Anonymous Arash Shafiei said...

Hi Kim,

Did you notice to my last comment?

The image size has been defined statically, so you should get it dynamically:

IplImage* frame = cvQueryFrame(input);
CvSize imgSize = cvGetSize(frame);

10:24 AM  
Anonymous kim sen said...

hi!
when i run the above code, error C2065: 'colourImage': undeclared identifier
so could u please help me out
thanks

7:01 AM  
Anonymous rabia said...

Hi ,

I run your code from start to until dilate and erode morphological operations. and just showed gray scale image . but it show me too much moving white blockies .

Thats not showing moving hand or object. . its just moving white blockies .

I have implemented like that before but i am not satisfied with this cvRunningAverage.

Sorry .Please show your result or output of your code too .

Thanks

4:47 PM  
Anonymous rabia said...

Hi ,

I run your code from start to until dilate and erode morphological operations. and just showed gray scale image . but it show me too much moving white blockies .

Thats not showing moving hand or object. . its just moving white blockies .

I have implemented like that before but i am not satisfied with this cvRunningAverage.

Sorry .Please show your result or output of your code too .

Thanks

4:47 PM  
Anonymous ben silver said...

Hello, I'm having a little trouble...it shows the error C2446 at the

char* outFilename = argc==2 ? argv[1] : "D:\\outputMovie.avi";

what could it be?

5:30 PM  
Anonymous Arash Shafiei said...

This comment has been removed by the author.

6:05 PM  
Anonymous Arash Shafiei said...

try

char default_file[50] = "D:\\outputMovie.avi";
char* outFilename = argc==2 ? argv[1] : default_file;

6:09 PM  

Post a Comment

<< Home