Update the trunk to the OpenCV's CVS (2008-07-14)
[opencv] / samples / c / motempl.c
1 #ifdef _CH_
2 #pragma package <opencv>
3 #endif
4
5 #ifndef _EiC
6 // motion templates sample code
7 #include "cv.h"
8 #include "highgui.h"
9 #include <time.h>
10 #include <math.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #endif
14
15 // various tracking parameters (in seconds)
16 const double MHI_DURATION = 1;
17 const double MAX_TIME_DELTA = 0.5;
18 const double MIN_TIME_DELTA = 0.05;
19 // number of cyclic frame buffer used for motion detection
20 // (should, probably, depend on FPS)
21 const int N = 4;
22
23 // ring image buffer
24 IplImage **buf = 0;
25 int last = 0;
26
27 // temporary images
28 IplImage *mhi = 0; // MHI
29 IplImage *orient = 0; // orientation
30 IplImage *mask = 0; // valid orientation mask
31 IplImage *segmask = 0; // motion segmentation map
32 CvMemStorage* storage = 0; // temporary storage
33
34 // parameters:
35 //  img - input video frame
36 //  dst - resultant motion picture
37 //  args - optional parameters
38 void  update_mhi( IplImage* img, IplImage* dst, int diff_threshold )
39 {
40     double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds
41     CvSize size = cvSize(img->width,img->height); // get current frame size
42     int i, idx1 = last, idx2;
43     IplImage* silh;
44     CvSeq* seq;
45     CvRect comp_rect;
46     double count;
47     double angle;
48     CvPoint center;
49     double magnitude;          
50     CvScalar color;
51
52     // allocate images at the beginning or
53     // reallocate them if the frame size is changed
54     if( !mhi || mhi->width != size.width || mhi->height != size.height ) {
55         if( buf == 0 ) {
56             buf = (IplImage**)malloc(N*sizeof(buf[0]));
57             memset( buf, 0, N*sizeof(buf[0]));
58         }
59         
60         for( i = 0; i < N; i++ ) {
61             cvReleaseImage( &buf[i] );
62             buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
63             cvZero( buf[i] );
64         }
65         cvReleaseImage( &mhi );
66         cvReleaseImage( &orient );
67         cvReleaseImage( &segmask );
68         cvReleaseImage( &mask );
69         
70         mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
71         cvZero( mhi ); // clear MHI at the beginning
72         orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );
73         segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );
74         mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
75     }
76
77     cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
78
79     idx2 = (last + 1) % N; // index of (last - (N-1))th frame
80     last = idx2;
81
82     silh = buf[idx2];
83     cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
84     
85     cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it
86     cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
87
88     // convert MHI to blue 8u image
89     cvCvtScale( mhi, mask, 255./MHI_DURATION,
90                 (MHI_DURATION - timestamp)*255./MHI_DURATION );
91     cvZero( dst );
92     cvCvtPlaneToPix( mask, 0, 0, 0, dst );
93
94     // calculate motion gradient orientation and valid orientation mask
95     cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
96     
97     if( !storage )
98         storage = cvCreateMemStorage(0);
99     else
100         cvClearMemStorage(storage);
101     
102     // segment motion: get sequence of motion components
103     // segmask is marked motion components map. It is not used further
104     seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA );
105
106     // iterate through the motion components,
107     // One more iteration (i == -1) corresponds to the whole image (global motion)
108     for( i = -1; i < seq->total; i++ ) {
109
110         if( i < 0 ) { // case of the whole image
111             comp_rect = cvRect( 0, 0, size.width, size.height );
112             color = CV_RGB(255,255,255);
113             magnitude = 100;
114         }
115         else { // i-th motion component
116             comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
117             if( comp_rect.width + comp_rect.height < 100 ) // reject very small components
118                 continue;
119             color = CV_RGB(255,0,0);
120             magnitude = 30;
121         }
122
123         // select component ROI
124         cvSetImageROI( silh, comp_rect );
125         cvSetImageROI( mhi, comp_rect );
126         cvSetImageROI( orient, comp_rect );
127         cvSetImageROI( mask, comp_rect );
128
129         // calculate orientation
130         angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);
131         angle = 360.0 - angle;  // adjust for images with top-left origin
132
133         count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI
134
135         cvResetImageROI( mhi );
136         cvResetImageROI( orient );
137         cvResetImageROI( mask );
138         cvResetImageROI( silh );
139
140         // check for the case of little motion
141         if( count < comp_rect.width*comp_rect.height * 0.05 )
142             continue;
143
144         // draw a clock with arrow indicating the direction
145         center = cvPoint( (comp_rect.x + comp_rect.width/2),
146                           (comp_rect.y + comp_rect.height/2) );
147
148         cvCircle( dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0 );
149         cvLine( dst, center, cvPoint( cvRound( center.x + magnitude*cos(angle*CV_PI/180)),
150                 cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, CV_AA, 0 );
151     }
152 }
153
154
155 int main(int argc, char** argv)
156 {
157     IplImage* motion = 0;
158     CvCapture* capture = 0;
159     
160     if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
161         capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
162     else if( argc == 2 )
163         capture = cvCaptureFromFile( argv[1] );
164
165     if( capture )
166     {
167         cvNamedWindow( "Motion", 1 );
168         
169         for(;;)
170         {
171             IplImage* image;
172             if( !cvGrabFrame( capture ))
173                 break;
174             image = cvRetrieveFrame( capture );
175
176             if( image )
177             {
178                 if( !motion )
179                 {
180                     motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 );
181                     cvZero( motion );
182                     motion->origin = image->origin;
183                 }
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