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