some samples updated according to new CommandLineParser class
[profile/ivi/opencv.git] / samples / c / motempl.c
1 #include "opencv2/video/tracking.hpp"
2 #include "opencv2/imgproc/imgproc.hpp"
3 #include "opencv2/highgui/highgui.hpp"
4 #include <time.h>
5 #include <stdio.h>
6 #include <ctype.h>
7
8 void help()
9 {
10         printf(
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"
15                         "Call:\n"
16                         "./motempl [camera number 0-n or file name, default is camera 0]\n"
17                         );
18 }
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)
25 const int N = 4;
26
27 // ring image buffer
28 IplImage **buf = 0;
29 int last = 0;
30
31 // temporary images
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
37
38 // parameters:
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 )
43 {
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;
47     IplImage* silh;
48     CvSeq* seq;
49     CvRect comp_rect;
50     double count;
51     double angle;
52     CvPoint center;
53     double magnitude;
54     CvScalar color;
55
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 ) {
59         if( buf == 0 ) {
60             buf = (IplImage**)malloc(N*sizeof(buf[0]));
61             memset( buf, 0, N*sizeof(buf[0]));
62         }
63
64         for( i = 0; i < N; i++ ) {
65             cvReleaseImage( &buf[i] );
66             buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
67             cvZero( buf[i] );
68         }
69         cvReleaseImage( &mhi );
70         cvReleaseImage( &orient );
71         cvReleaseImage( &segmask );
72         cvReleaseImage( &mask );
73
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 );
79     }
80
81     cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
82
83     idx2 = (last + 1) % N; // index of (last - (N-1))th frame
84     last = idx2;
85
86     silh = buf[idx2];
87     cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
88
89     cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it
90     cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
91
92     // convert MHI to blue 8u image
93     cvCvtScale( mhi, mask, 255./MHI_DURATION,
94                 (MHI_DURATION - timestamp)*255./MHI_DURATION );
95     cvZero( dst );
96     cvMerge( mask, 0, 0, 0, dst );
97
98     // calculate motion gradient orientation and valid orientation mask
99     cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
100
101     if( !storage )
102         storage = cvCreateMemStorage(0);
103     else
104         cvClearMemStorage(storage);
105
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 );
109
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++ ) {
113
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);
117             magnitude = 100;
118         }
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
122                 continue;
123             color = CV_RGB(255,0,0);
124             magnitude = 30;
125         }
126
127         // select component ROI
128         cvSetImageROI( silh, comp_rect );
129         cvSetImageROI( mhi, comp_rect );
130         cvSetImageROI( orient, comp_rect );
131         cvSetImageROI( mask, comp_rect );
132
133         // calculate orientation
134         angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);
135         angle = 360.0 - angle;  // adjust for images with top-left origin
136
137         count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI
138
139         cvResetImageROI( mhi );
140         cvResetImageROI( orient );
141         cvResetImageROI( mask );
142         cvResetImageROI( silh );
143
144         // check for the case of little motion
145         if( count < comp_rect.width*comp_rect.height * 0.05 )
146             continue;
147
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) );
151
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 );
155     }
156 }
157
158
159 int main(int argc, char** argv)
160 {
161     IplImage* motion = 0;
162     CvCapture* capture = 0;
163     help();
164     if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
165         capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
166     else if( argc == 2 )
167         capture = cvCaptureFromFile( argv[1] );
168
169     if( capture )
170     {
171         cvNamedWindow( "Motion", 1 );
172
173         for(;;)
174         {
175             IplImage* image = cvQueryFrame( capture );
176             if( !image )
177                 break;
178
179             if( !motion )
180             {
181                 motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 );
182                 cvZero( motion );
183                 motion->origin = image->origin;
184             }
185
186             update_mhi( image, motion, 30 );
187             cvShowImage( "Motion", motion );
188
189             if( cvWaitKey(10) >= 0 )
190                 break;
191         }
192         cvReleaseCapture( &capture );
193         cvDestroyWindow( "Motion" );
194     }
195
196     return 0;
197 }
198
199 #ifdef _EiC
200 main(1,"motempl.c");
201 #endif