1 #include "opencv2/video/tracking.hpp"
2 #include "opencv2/imgproc/imgproc.hpp"
3 #include "opencv2/highgui/highgui.hpp"
11 "\nThis program demonstrated the use of motion templates -- basically using the gradients\n"
12 "of thresholded layers of decaying frame differencing. New movements are stamped on top with floating system\n"
13 "time code and motions too old are thresholded away. This is the 'motion history file'. The program reads from the camera of your choice or from\n"
14 "a file. Gradients of motion history are used to detect direction of motoin etc\n"
16 "./motempl [camera number 0-n or file name, default is camera 0]\n"
19 // various tracking parameters (in seconds)
20 const double MHI_DURATION = 1;
21 const double MAX_TIME_DELTA = 0.5;
22 const double MIN_TIME_DELTA = 0.05;
23 // number of cyclic frame buffer used for motion detection
24 // (should, probably, depend on FPS)
32 IplImage *mhi = 0; // MHI
33 IplImage *orient = 0; // orientation
34 IplImage *mask = 0; // valid orientation mask
35 IplImage *segmask = 0; // motion segmentation map
36 CvMemStorage* storage = 0; // temporary storage
39 // img - input video frame
40 // dst - resultant motion picture
41 // args - optional parameters
42 void update_mhi( IplImage* img, IplImage* dst, int diff_threshold )
44 double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds
45 CvSize size = cvSize(img->width,img->height); // get current frame size
46 int i, idx1 = last, idx2;
56 // allocate images at the beginning or
57 // reallocate them if the frame size is changed
58 if( !mhi || mhi->width != size.width || mhi->height != size.height ) {
60 buf = (IplImage**)malloc(N*sizeof(buf[0]));
61 memset( buf, 0, N*sizeof(buf[0]));
64 for( i = 0; i < N; i++ ) {
65 cvReleaseImage( &buf[i] );
66 buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
69 cvReleaseImage( &mhi );
70 cvReleaseImage( &orient );
71 cvReleaseImage( &segmask );
72 cvReleaseImage( &mask );
74 mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
75 cvZero( mhi ); // clear MHI at the beginning
76 orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );
77 segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );
78 mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
81 cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
83 idx2 = (last + 1) % N; // index of (last - (N-1))th frame
87 cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
89 cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it
90 cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
92 // convert MHI to blue 8u image
93 cvCvtScale( mhi, mask, 255./MHI_DURATION,
94 (MHI_DURATION - timestamp)*255./MHI_DURATION );
96 cvMerge( mask, 0, 0, 0, dst );
98 // calculate motion gradient orientation and valid orientation mask
99 cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
102 storage = cvCreateMemStorage(0);
104 cvClearMemStorage(storage);
106 // segment motion: get sequence of motion components
107 // segmask is marked motion components map. It is not used further
108 seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA );
110 // iterate through the motion components,
111 // One more iteration (i == -1) corresponds to the whole image (global motion)
112 for( i = -1; i < seq->total; i++ ) {
114 if( i < 0 ) { // case of the whole image
115 comp_rect = cvRect( 0, 0, size.width, size.height );
116 color = CV_RGB(255,255,255);
119 else { // i-th motion component
120 comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
121 if( comp_rect.width + comp_rect.height < 100 ) // reject very small components
123 color = CV_RGB(255,0,0);
127 // select component ROI
128 cvSetImageROI( silh, comp_rect );
129 cvSetImageROI( mhi, comp_rect );
130 cvSetImageROI( orient, comp_rect );
131 cvSetImageROI( mask, comp_rect );
133 // calculate orientation
134 angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);
135 angle = 360.0 - angle; // adjust for images with top-left origin
137 count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI
139 cvResetImageROI( mhi );
140 cvResetImageROI( orient );
141 cvResetImageROI( mask );
142 cvResetImageROI( silh );
144 // check for the case of little motion
145 if( count < comp_rect.width*comp_rect.height * 0.05 )
148 // draw a clock with arrow indicating the direction
149 center = cvPoint( (comp_rect.x + comp_rect.width/2),
150 (comp_rect.y + comp_rect.height/2) );
152 cvCircle( dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0 );
153 cvLine( dst, center, cvPoint( cvRound( center.x + magnitude*cos(angle*CV_PI/180)),
154 cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, CV_AA, 0 );
159 int main(int argc, char** argv)
161 IplImage* motion = 0;
162 CvCapture* capture = 0;
166 if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
167 capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
169 capture = cvCaptureFromFile( argv[1] );
173 cvNamedWindow( "Motion", 1 );
177 IplImage* image = cvQueryFrame( capture );
183 motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 );
185 motion->origin = image->origin;
188 update_mhi( image, motion, 30 );
189 cvShowImage( "Motion", motion );
191 if( cvWaitKey(10) >= 0 )
194 cvReleaseCapture( &capture );
195 cvDestroyWindow( "Motion" );