motempl.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #include "opencv2/optflow.hpp"
  2. #include "opencv2/imgproc.hpp"
  3. #include "opencv2/videoio.hpp"
  4. #include "opencv2/highgui.hpp"
  5. #include <time.h>
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. using namespace cv;
  9. using namespace std;
  10. using namespace cv::motempl;
  11. static void help(void)
  12. {
  13. printf(
  14. "\nThis program demonstrated the use of motion templates -- basically using the gradients\n"
  15. "of thresholded layers of decaying frame differencing. New movements are stamped on top with floating system\n"
  16. "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"
  17. "a file. Gradients of motion history are used to detect direction of motion etc\n"
  18. "Usage :\n"
  19. "./motempl [camera number 0-n or file name, default is camera 0]\n"
  20. );
  21. }
  22. // various tracking parameters (in seconds)
  23. const double MHI_DURATION = 5;
  24. const double MAX_TIME_DELTA = 0.5;
  25. const double MIN_TIME_DELTA = 0.05;
  26. // number of cyclic frame buffer used for motion detection
  27. // (should, probably, depend on FPS)
  28. // ring image buffer
  29. vector<Mat> buf;
  30. int last = 0;
  31. // temporary images
  32. Mat mhi, orient, mask, segmask, zplane;
  33. vector<Rect> regions;
  34. // parameters:
  35. // img - input video frame
  36. // dst - resultant motion picture
  37. // args - optional parameters
  38. static void update_mhi(const Mat& img, Mat& dst, int diff_threshold)
  39. {
  40. double timestamp = (double)clock() / CLOCKS_PER_SEC; // get current time in seconds
  41. Size size = img.size();
  42. int i, idx1 = last;
  43. Rect comp_rect;
  44. double count;
  45. double angle;
  46. Point center;
  47. double magnitude;
  48. Scalar color;
  49. // allocate images at the beginning or
  50. // reallocate them if the frame size is changed
  51. if (mhi.size() != size)
  52. {
  53. mhi = Mat::zeros(size, CV_32F);
  54. zplane = Mat::zeros(size, CV_8U);
  55. buf[0] = Mat::zeros(size, CV_8U);
  56. buf[1] = Mat::zeros(size, CV_8U);
  57. }
  58. cvtColor(img, buf[last], COLOR_BGR2GRAY); // convert frame to grayscale
  59. int idx2 = (last + 1) % 2; // index of (last - (N-1))th frame
  60. last = idx2;
  61. Mat silh = buf[idx2];
  62. absdiff(buf[idx1], buf[idx2], silh); // get difference between frames
  63. threshold(silh, silh, diff_threshold, 1, THRESH_BINARY); // and threshold it
  64. updateMotionHistory(silh, mhi, timestamp, MHI_DURATION); // update MHI
  65. // convert MHI to blue 8u image
  66. mhi.convertTo(mask, CV_8U, 255. / MHI_DURATION, (MHI_DURATION - timestamp)*255. / MHI_DURATION);
  67. Mat planes[] = { mask, zplane, zplane };
  68. merge(planes, 3, dst);
  69. // calculate motion gradient orientation and valid orientation mask
  70. calcMotionGradient(mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3);
  71. // segment motion: get sequence of motion components
  72. // segmask is marked motion components map. It is not used further
  73. regions.clear();
  74. segmentMotion(mhi, segmask, regions, timestamp, MAX_TIME_DELTA);
  75. // iterate through the motion components,
  76. // One more iteration (i == -1) corresponds to the whole image (global motion)
  77. for (i = -1; i < (int)regions.size(); i++) {
  78. if (i < 0) { // case of the whole image
  79. comp_rect = Rect(0, 0, size.width, size.height);
  80. color = Scalar(255, 255, 255);
  81. magnitude = 100;
  82. }
  83. else { // i-th motion component
  84. comp_rect = regions[i];
  85. if (comp_rect.width + comp_rect.height < 100) // reject very small components
  86. continue;
  87. color = Scalar(0, 0, 255);
  88. magnitude = 30;
  89. }
  90. // select component ROI
  91. Mat silh_roi = silh(comp_rect);
  92. Mat mhi_roi = mhi(comp_rect);
  93. Mat orient_roi = orient(comp_rect);
  94. Mat mask_roi = mask(comp_rect);
  95. // calculate orientation
  96. angle = calcGlobalOrientation(orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION);
  97. angle = 360.0 - angle; // adjust for images with top-left origin
  98. count = norm(silh_roi, NORM_L1);; // calculate number of points within silhouette ROI
  99. // check for the case of little motion
  100. if (count < comp_rect.width*comp_rect.height * 0.05)
  101. continue;
  102. // draw a clock with arrow indicating the direction
  103. center = Point((comp_rect.x + comp_rect.width / 2),
  104. (comp_rect.y + comp_rect.height / 2));
  105. circle(img, center, cvRound(magnitude*1.2), color, 3, 16, 0);
  106. line(img, center, Point(cvRound(center.x + magnitude*cos(angle*CV_PI / 180)),
  107. cvRound(center.y - magnitude*sin(angle*CV_PI / 180))), color, 3, 16, 0);
  108. }
  109. }
  110. int main(int argc, char** argv)
  111. {
  112. VideoCapture cap;
  113. help();
  114. if (argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
  115. cap.open(argc == 2 ? argv[1][0] - '0' : 0);
  116. else if (argc == 2)
  117. cap.open(argv[1]);
  118. if (!cap.isOpened())
  119. {
  120. printf("Could not initialize video capture\n");
  121. return 0;
  122. }
  123. buf.resize(2);
  124. Mat image, motion;
  125. for (;;)
  126. {
  127. cap >> image;
  128. if (image.empty())
  129. break;
  130. update_mhi(image, motion, 30);
  131. imshow("Image", image);
  132. imshow("Motion", motion);
  133. if (waitKey(10) >= 0)
  134. break;
  135. }
  136. return 0;
  137. }