1 #include "opencv2/video/tracking_c.h"
2 #include "opencv2/imgproc/imgproc_c.h"
3 #include "opencv2/videoio/videoio_c.h"
4 #include "opencv2/highgui/highgui_c.h"
12 "\nThis program demonstrated the use of motion templates -- basically using the gradients\n"
13 "of thresholded layers of decaying frame differencing. New movements are stamped on top with floating system\n"
14 "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"
15 "a file. Gradients of motion history are used to detect direction of motoin etc\n"
17 "./motempl [camera number 0-n or file name, default is camera 0]\n"
20 // various tracking parameters (in seconds)
21 const double MHI_DURATION = 1;
22 const double MAX_TIME_DELTA = 0.5;
23 const double MIN_TIME_DELTA = 0.05;
24 // number of cyclic frame buffer used for motion detection
25 // (should, probably, depend on FPS)
33 IplImage *mhi = 0; // MHI
34 IplImage *orient = 0; // orientation
35 IplImage *mask = 0; // valid orientation mask
36 IplImage *segmask = 0; // motion segmentation map
37 CvMemStorage* storage = 0; // temporary storage
40 // img - input video frame
41 // dst - resultant motion picture
42 // args - optional parameters
43 static void update_mhi( IplImage* img, IplImage* dst, int diff_threshold )
45 double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds
46 CvSize size = cvSize(img->width,img->height); // get current frame size
47 int i, idx1 = last, idx2;
57 // allocate images at the beginning or
58 // reallocate them if the frame size is changed
59 if( !mhi || mhi->width != size.width || mhi->height != size.height ) {
61 buf = (IplImage**)malloc(N*sizeof(buf[0]));
62 memset( buf, 0, N*sizeof(buf[0]));
65 for( i = 0; i < N; i++ ) {
66 cvReleaseImage( &buf[i] );
67 buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
70 cvReleaseImage( &mhi );
71 cvReleaseImage( &orient );
72 cvReleaseImage( &segmask );
73 cvReleaseImage( &mask );
75 mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
76 cvZero( mhi ); // clear MHI at the beginning
77 orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );
78 segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );
79 mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
82 cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
84 idx2 = (last + 1) % N; // index of (last - (N-1))th frame
88 cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
90 cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it
91 cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
93 // convert MHI to blue 8u image
94 cvCvtScale( mhi, mask, 255./MHI_DURATION,
95 (MHI_DURATION - timestamp)*255./MHI_DURATION );
97 cvMerge( mask, 0, 0, 0, dst );
99 // calculate motion gradient orientation and valid orientation mask
100 cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
103 storage = cvCreateMemStorage(0);
105 cvClearMemStorage(storage);
107 // segment motion: get sequence of motion components
108 // segmask is marked motion components map. It is not used further
109 seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA );
111 // iterate through the motion components,
112 // One more iteration (i == -1) corresponds to the whole image (global motion)
113 for( i = -1; i < seq->total; i++ ) {
115 if( i < 0 ) { // case of the whole image
116 comp_rect = cvRect( 0, 0, size.width, size.height );
117 color = CV_RGB(255,255,255);
120 else { // i-th motion component
121 comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
122 if( comp_rect.width + comp_rect.height < 100 ) // reject very small components
124 color = CV_RGB(255,0,0);
128 // select component ROI
129 cvSetImageROI( silh, comp_rect );
130 cvSetImageROI( mhi, comp_rect );
131 cvSetImageROI( orient, comp_rect );
132 cvSetImageROI( mask, comp_rect );
134 // calculate orientation
135 angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);
136 angle = 360.0 - angle; // adjust for images with top-left origin
138 count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI
140 cvResetImageROI( mhi );
141 cvResetImageROI( orient );
142 cvResetImageROI( mask );
143 cvResetImageROI( silh );
145 // check for the case of little motion
146 if( count < comp_rect.width*comp_rect.height * 0.05 )
149 // draw a clock with arrow indicating the direction
150 center = cvPoint( (comp_rect.x + comp_rect.width/2),
151 (comp_rect.y + comp_rect.height/2) );
153 cvCircle( dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0 );
154 cvLine( dst, center, cvPoint( cvRound( center.x + magnitude*cos(angle*CV_PI/180)),
155 cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, CV_AA, 0 );
160 int main(int argc, char** argv)
162 IplImage* motion = 0;
163 CvCapture* capture = 0;
167 if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
168 capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
170 capture = cvCaptureFromFile( argv[1] );
174 cvNamedWindow( "Motion", 1 );
178 IplImage* image = cvQueryFrame( capture );
184 motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 );
186 motion->origin = image->origin;
189 update_mhi( image, motion, 30 );
190 cvShowImage( "Motion", motion );
192 if( cvWaitKey(10) >= 0 )
195 cvReleaseCapture( &capture );
196 cvDestroyWindow( "Motion" );