Commit 860eda95 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #214 from LaurentBerger/bugfix4269

bugfix4269 included remarks in http://answers.opencv.org/question/59293/...
parents 9064d28d 6122d265
...@@ -13,21 +13,20 @@ using namespace cv::motempl; ...@@ -13,21 +13,20 @@ using namespace cv::motempl;
static void help(void) static void help(void)
{ {
printf( printf(
"\nThis program demonstrated the use of motion templates -- basically using the gradients\n" "\nThis program demonstrated the use of motion templates -- basically using the gradients\n"
"of thresholded layers of decaying frame differencing. New movements are stamped on top with floating system\n" "of thresholded layers of decaying frame differencing. New movements are stamped on top with floating system\n"
"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" "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"
"a file. Gradients of motion history are used to detect direction of motoin etc\n" "a file. Gradients of motion history are used to detect direction of motion etc\n"
"Usage :\n" "Usage :\n"
"./motempl [camera number 0-n or file name, default is camera 0]\n" "./motempl [camera number 0-n or file name, default is camera 0]\n"
); );
} }
// various tracking parameters (in seconds) // various tracking parameters (in seconds)
const double MHI_DURATION = 1; const double MHI_DURATION = 5;
const double MAX_TIME_DELTA = 0.5; const double MAX_TIME_DELTA = 0.5;
const double MIN_TIME_DELTA = 0.05; const double MIN_TIME_DELTA = 0.05;
// number of cyclic frame buffer used for motion detection // number of cyclic frame buffer used for motion detection
// (should, probably, depend on FPS) // (should, probably, depend on FPS)
const int N = 4;
// ring image buffer // ring image buffer
vector<Mat> buf; vector<Mat> buf;
...@@ -41,9 +40,9 @@ vector<Rect> regions; ...@@ -41,9 +40,9 @@ vector<Rect> regions;
// img - input video frame // img - input video frame
// dst - resultant motion picture // dst - resultant motion picture
// args - optional parameters // args - optional parameters
static void update_mhi( const Mat& img, Mat& dst, int diff_threshold ) static void update_mhi(const Mat& img, Mat& dst, int diff_threshold)
{ {
double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds double timestamp = (double)clock() / CLOCKS_PER_SEC; // get current time in seconds
Size size = img.size(); Size size = img.size();
int i, idx1 = last; int i, idx1 = last;
Rect comp_rect; Rect comp_rect;
...@@ -55,57 +54,54 @@ static void update_mhi( const Mat& img, Mat& dst, int diff_threshold ) ...@@ -55,57 +54,54 @@ static void update_mhi( const Mat& img, Mat& dst, int diff_threshold )
// allocate images at the beginning or // allocate images at the beginning or
// reallocate them if the frame size is changed // reallocate them if the frame size is changed
if( mhi.size() != size ) if (mhi.size() != size)
{ {
mhi = Mat::zeros(size, CV_32F); mhi = Mat::zeros(size, CV_32F);
zplane = Mat::zeros(size, CV_8U); zplane = Mat::zeros(size, CV_8U);
buf.resize(N); buf[0] = Mat::zeros(size, CV_8U);
for( i = 0; i < N; i++ ) buf[1] = Mat::zeros(size, CV_8U);
{
buf[i] = Mat::zeros(size, CV_8U);
}
} }
cvtColor( img, buf[last], COLOR_BGR2GRAY ); // convert frame to grayscale cvtColor(img, buf[last], COLOR_BGR2GRAY); // convert frame to grayscale
int idx2 = (last + 1) % N; // index of (last - (N-1))th frame int idx2 = (last + 1) % 2; // index of (last - (N-1))th frame
last = idx2; last = idx2;
Mat silh = buf[idx2]; Mat silh = buf[idx2];
absdiff( buf[idx1], buf[idx2], silh ); // get difference between frames absdiff(buf[idx1], buf[idx2], silh); // get difference between frames
threshold( silh, silh, diff_threshold, 1, THRESH_BINARY ); // and threshold it threshold(silh, silh, diff_threshold, 1, THRESH_BINARY); // and threshold it
updateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI updateMotionHistory(silh, mhi, timestamp, MHI_DURATION); // update MHI
// convert MHI to blue 8u image // convert MHI to blue 8u image
mhi.convertTo( mask, CV_8U, 255./MHI_DURATION, (MHI_DURATION - timestamp)*255./MHI_DURATION ); mhi.convertTo(mask, CV_8U, 255. / MHI_DURATION, (MHI_DURATION - timestamp)*255. / MHI_DURATION);
Mat planes[] = {mask, zplane, zplane}; Mat planes[] = { mask, zplane, zplane };
merge(planes, 3, dst); merge(planes, 3, dst);
// calculate motion gradient orientation and valid orientation mask // calculate motion gradient orientation and valid orientation mask
calcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 ); calcMotionGradient(mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3);
// segment motion: get sequence of motion components // segment motion: get sequence of motion components
// segmask is marked motion components map. It is not used further // segmask is marked motion components map. It is not used further
regions.clear();
segmentMotion(mhi, segmask, regions, timestamp, MAX_TIME_DELTA); segmentMotion(mhi, segmask, regions, timestamp, MAX_TIME_DELTA);
// iterate through the motion components, // iterate through the motion components,
// One more iteration (i == -1) corresponds to the whole image (global motion) // One more iteration (i == -1) corresponds to the whole image (global motion)
for( i = -1; i < (int)regions.size(); i++ ) { for (i = -1; i < (int)regions.size(); i++) {
if( i < 0 ) { // case of the whole image if (i < 0) { // case of the whole image
comp_rect = Rect( 0, 0, size.width, size.height ); comp_rect = Rect(0, 0, size.width, size.height);
color = Scalar(255,255,255); color = Scalar(255, 255, 255);
magnitude = 100; magnitude = 100;
} }
else { // i-th motion component else { // i-th motion component
comp_rect = regions[i]; comp_rect = regions[i];
if( comp_rect.width + comp_rect.height < 100 ) // reject very small components if (comp_rect.width + comp_rect.height < 100) // reject very small components
continue; continue;
color = Scalar(0,0,255); color = Scalar(0, 0, 255);
magnitude = 30; magnitude = 30;
} }
...@@ -116,22 +112,22 @@ static void update_mhi( const Mat& img, Mat& dst, int diff_threshold ) ...@@ -116,22 +112,22 @@ static void update_mhi( const Mat& img, Mat& dst, int diff_threshold )
Mat mask_roi = mask(comp_rect); Mat mask_roi = mask(comp_rect);
// calculate orientation // calculate orientation
angle = calcGlobalOrientation( orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION); angle = calcGlobalOrientation(orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION);
angle = 360.0 - angle; // adjust for images with top-left origin angle = 360.0 - angle; // adjust for images with top-left origin
count = norm( silh, 0, NORM_L1, 0 ); // calculate number of points within silhouette ROI count = norm(silh_roi, NORM_L1);; // calculate number of points within silhouette ROI
// check for the case of little motion // check for the case of little motion
if( count < comp_rect.width*comp_rect.height * 0.05 ) if (count < comp_rect.width*comp_rect.height * 0.05)
continue; continue;
// draw a clock with arrow indicating the direction // draw a clock with arrow indicating the direction
center = Point( (comp_rect.x + comp_rect.width/2), center = Point((comp_rect.x + comp_rect.width / 2),
(comp_rect.y + comp_rect.height/2) ); (comp_rect.y + comp_rect.height / 2));
circle( dst, center, cvRound(magnitude*1.2), color, 3, 16, 0 ); circle(img, center, cvRound(magnitude*1.2), color, 3, 16, 0);
line( dst, center, Point( cvRound( center.x + magnitude*cos(angle*CV_PI/180)), line(img, center, Point(cvRound(center.x + magnitude*cos(angle*CV_PI / 180)),
cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, 16, 0 ); cvRound(center.y - magnitude*sin(angle*CV_PI / 180))), color, 3, 16, 0);
} }
} }
...@@ -142,28 +138,29 @@ int main(int argc, char** argv) ...@@ -142,28 +138,29 @@ int main(int argc, char** argv)
help(); help();
if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) if (argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
cap.open( argc == 2 ? argv[1][0] - '0' : 0 ); cap.open(argc == 2 ? argv[1][0] - '0' : 0);
else if( argc == 2 ) else if (argc == 2)
cap.open( argv[1] ); cap.open(argv[1]);
if( !cap.isOpened() ) if (!cap.isOpened())
{ {
printf("Could not initialize video capture\n"); printf("Could not initialize video capture\n");
return 0; return 0;
} }
buf.resize(2);
Mat image, motion; Mat image, motion;
for(;;) for (;;)
{ {
cap >> image; cap >> image;
if( image.empty() ) if (image.empty())
break; break;
update_mhi( image, motion, 30 ); update_mhi(image, motion, 30);
imshow( "Motion", motion ); imshow("Image", image);
imshow("Motion", motion);
if( waitKey(10) >= 0 ) if (waitKey(10) >= 0)
break; break;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment