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