1
/***************************************************************************
2
* Copyright (C) 2008, 2009, 2010 by Stephane List *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************/
21
#include "motiondetector.h"
26
// various tracking parameters (in seconds)
27
const double MHI_DURATION = 1;
28
const double MAX_TIME_DELTA = 0.5;
29
const double MIN_TIME_DELTA = 0.05;
30
// number of cyclic frame buffer used for motion detection
31
// (should, probably, depend on FPS)
33
const int MAGNITUDE_GLOBAL = 100;
34
const int MAGNITUDE_COMPONENT = 30;
36
MotionDetector::MotionDetector(QObject *parent)
39
show_component_(true),
52
qDebug() << "MotionDetector::MotionDetector";
56
MotionDetector::~MotionDetector()
58
qDebug() << "MotionDetector::~MotionDetector";
62
void MotionDetector::input(const IplImage & image)
64
//qDebug() << "MotionDetector::input";
67
motion_ = cvCreateImage(cvSize(image.width,image.height), 8, 3 );
69
motion_->origin = image.origin;
72
update_mhi(&image, motion_, threshold_);
75
emit output(*motion_);
79
void MotionDetector::set_motion_color(const QColor & col)
81
//qDebug() << "color set to : " << col;
85
void MotionDetector::set_threshold(int t)
87
//qDebug() << "threshold set to : " << t;
92
// img - input video frame
93
// dst - resultant motion picture
94
// diff_threshold - threshold to avoid motion detection because of noise in the video
95
void MotionDetector::update_mhi(const IplImage* img, IplImage* dst, int diff_threshold )
97
double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds
98
CvSize size = cvSize(img->width,img->height); // get current frame size
99
int i, idx1 = last, idx2;
103
double count, angle, magnitude;
107
//qDebug() << "MotionDetector::update_mhi";
109
// allocate images at the beginning or
110
// reallocate them if the frame size is changed
111
if( !mhi || mhi->width != size.width || mhi->height != size.height ) {
113
buf = (IplImage**)malloc(N*sizeof(buf[0]));
114
memset( buf, 0, N*sizeof(buf[0]));
116
for( i = 0; i < N; i++ ) {
117
cvReleaseImage( &buf[i] );
118
buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
121
cvReleaseImage( &mhi );
122
cvReleaseImage( &orient );
123
cvReleaseImage( &segmask );
124
cvReleaseImage( &mask );
125
cvReleaseImage( &red );
126
cvReleaseImage( &green );
127
cvReleaseImage( &blue );
129
mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
130
cvZero( mhi ); // clear MHI at the beginning
131
orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );
132
segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );
133
mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
134
red = cvCreateImage( size, IPL_DEPTH_8U, 1 );
135
green = cvCreateImage( size, IPL_DEPTH_8U, 1 );
136
blue = cvCreateImage( size, IPL_DEPTH_8U, 1 );
139
cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
141
//emit output(*buf[last]);
143
idx2 = (last + 1) % N; // index of (last - (N-1))th frame
147
cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
149
//emit output(*silh);
151
cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it
153
//emit output(*silh);
155
cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
157
// convert MHI to blue 8u image
158
cvCvtScale( mhi, mask, 255./MHI_DURATION, (MHI_DURATION - timestamp)*255./MHI_DURATION );
160
// convert 8u image to 32u image using custom color
161
cvCvtScale( mask, red, color_.red() / 255.0, 0.);
162
cvCvtScale( mask, green, color_.green() / 255.0, 0.);
163
cvCvtScale( mask, blue, color_.blue() / 255.0, 0.);
166
cvCvtPlaneToPix( blue, green, red, 0, dst );
168
// calculate motion gradient orientation and valid orientation mask
169
cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
172
storage = cvCreateMemStorage(0);
174
cvClearMemStorage(storage);
176
// segment motion: get sequence of motion components
177
// segmask is marked motion components map. It is not used further
178
seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA );
180
// iterate through the motion components,
181
// One more iteration (i == -1) corresponds to the whole image (global motion)
182
for( i = -1; i < seq->total; i++ ) {
184
if( i < 0 ) { // case of the whole image
185
comp_rect = cvRect( 0, 0, size.width, size.height );
186
color = CV_RGB(255,255,255); // white
187
magnitude = MAGNITUDE_GLOBAL;
189
else { // i-th motion component
190
comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
191
if( comp_rect.width + comp_rect.height < 100 ) // reject very small components
193
color = CV_RGB(255,0,0); // red
194
magnitude = MAGNITUDE_COMPONENT;
197
// select component ROI
198
cvSetImageROI( silh, comp_rect );
199
cvSetImageROI( mhi, comp_rect );
200
cvSetImageROI( orient, comp_rect );
201
cvSetImageROI( mask, comp_rect );
203
// calculate orientation
204
angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);
205
angle = 360.0 - angle; // adjust for images with top-left origin
207
count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI
209
cvResetImageROI( mhi );
210
cvResetImageROI( orient );
211
cvResetImageROI( mask );
212
cvResetImageROI( silh );
214
// check for the case of little motion
215
if( count < comp_rect.width*comp_rect.height * 0.05 )
218
if (((magnitude == MAGNITUDE_GLOBAL) && show_global_)
219
|| ((magnitude == MAGNITUDE_COMPONENT) && show_component_))
221
// draw a clock with arrow indicating the direction
222
center = cvPoint(comp_rect.x + comp_rect.width / 2,comp_rect.y + comp_rect.height / 2);
224
magnitude = (magnitude * size.height) / (3 * MAGNITUDE_GLOBAL);
226
cvCircle(dst,center,cvRound(magnitude * 1.2),color,3,CV_AA,0);
228
,cvPoint(cvRound(center.x + magnitude * cos(angle * CV_PI / 180))
229
,cvRound(center.y - magnitude * sin(angle * CV_PI / 180)))
234
//qDebug() << "emit Motion Detected !";