camshift.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "opencv2/core/utility.hpp"
  2. #include "opencv2/core/ocl.hpp"
  3. #include "opencv2/video/tracking.hpp"
  4. #include "opencv2/imgproc.hpp"
  5. #include "opencv2/videoio.hpp"
  6. #include "opencv2/highgui.hpp"
  7. #include <iostream>
  8. #include <cctype>
  9. static cv::UMat image;
  10. static bool backprojMode = false;
  11. static bool selectObject = false;
  12. static int trackObject = 0;
  13. static bool showHist = true;
  14. static cv::Rect selection;
  15. static int vmin = 10, vmax = 256, smin = 30;
  16. static void onMouse(int event, int x, int y, int, void*)
  17. {
  18. static cv::Point origin;
  19. if (selectObject)
  20. {
  21. selection.x = std::min(x, origin.x);
  22. selection.y = std::min(y, origin.y);
  23. selection.width = std::abs(x - origin.x);
  24. selection.height = std::abs(y - origin.y);
  25. selection &= cv::Rect(0, 0, image.cols, image.rows);
  26. }
  27. switch (event)
  28. {
  29. case cv::EVENT_LBUTTONDOWN:
  30. origin = cv::Point(x, y);
  31. selection = cv::Rect(x, y, 0, 0);
  32. selectObject = true;
  33. break;
  34. case cv::EVENT_LBUTTONUP:
  35. selectObject = false;
  36. if (selection.width > 0 && selection.height > 0)
  37. trackObject = -1;
  38. break;
  39. default:
  40. break;
  41. }
  42. }
  43. static void help()
  44. {
  45. std::cout << "\nThis is a demo that shows mean-shift based tracking using Transparent API\n"
  46. "You select a color objects such as your face and it tracks it.\n"
  47. "This reads from video camera (0 by default, or the camera number the user enters\n"
  48. "Usage: \n"
  49. " ./camshiftdemo [camera number]\n";
  50. std::cout << "\n\nHot keys: \n"
  51. "\tESC - quit the program\n"
  52. "\ts - stop the tracking\n"
  53. "\tb - switch to/from backprojection view\n"
  54. "\th - show/hide object histogram\n"
  55. "\tp - pause video\n"
  56. "\tc - use OpenCL or not\n"
  57. "To initialize tracking, select the object with mouse\n";
  58. }
  59. int main(int argc, const char ** argv)
  60. {
  61. help();
  62. cv::VideoCapture cap;
  63. cv::Rect trackWindow;
  64. int hsize = 16;
  65. float hranges[2] = { 0, 180 };
  66. const char * const keys = { "{@camera_number| 0 | camera number}" };
  67. cv::CommandLineParser parser(argc, argv, keys);
  68. int camNum = parser.get<int>(0);
  69. cap.open(camNum);
  70. if (!cap.isOpened())
  71. {
  72. help();
  73. std::cout << "***Could not initialize capturing...***\n";
  74. std::cout << "Current parameter's value: \n";
  75. parser.printMessage();
  76. return EXIT_FAILURE;
  77. }
  78. cv::namedWindow("Histogram", cv::WINDOW_NORMAL);
  79. cv::namedWindow("CamShift Demo", cv::WINDOW_NORMAL);
  80. cv::setMouseCallback("CamShift Demo", onMouse);
  81. cv::createTrackbar("Vmin", "CamShift Demo", &vmin, 256);
  82. cv::createTrackbar("Vmax", "CamShift Demo", &vmax, 256);
  83. cv::createTrackbar("Smin", "CamShift Demo", &smin, 256);
  84. cv::Mat frame, histimg(200, 320, CV_8UC3, cv::Scalar::all(0));
  85. cv::UMat hsv, hist, hue, mask, backproj;
  86. bool paused = false;
  87. for ( ; ; )
  88. {
  89. if (!paused)
  90. {
  91. cap >> frame;
  92. if (frame.empty())
  93. break;
  94. }
  95. frame.copyTo(image);
  96. if (!paused)
  97. {
  98. cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
  99. if (trackObject)
  100. {
  101. int _vmin = vmin, _vmax = vmax;
  102. cv::inRange(hsv, cv::Scalar(0, smin, std::min(_vmin, _vmax)),
  103. cv::Scalar(180, 256, std::max(_vmin, _vmax)), mask);
  104. int fromTo[2] = { 0,0 };
  105. hue.create(hsv.size(), hsv.depth());
  106. cv::mixChannels(std::vector<cv::UMat>(1, hsv), std::vector<cv::UMat>(1, hue), fromTo, 1);
  107. if (trackObject < 0)
  108. {
  109. cv::UMat roi(hue, selection), maskroi(mask, selection);
  110. cv::calcHist(std::vector<cv::Mat>(1, roi.getMat(cv::ACCESS_READ)), std::vector<int>(1, 0),
  111. maskroi, hist, std::vector<int>(1, hsize), std::vector<float>(hranges, hranges + 2));
  112. cv::normalize(hist, hist, 0, 255, cv::NORM_MINMAX);
  113. trackWindow = selection;
  114. trackObject = 1;
  115. histimg = cv::Scalar::all(0);
  116. int binW = histimg.cols / hsize;
  117. cv::Mat buf (1, hsize, CV_8UC3);
  118. for (int i = 0; i < hsize; i++)
  119. buf.at<cv::Vec3b>(i) = cv::Vec3b(cv::saturate_cast<uchar>(i*180./hsize), 255, 255);
  120. cv::cvtColor(buf, buf, cv::COLOR_HSV2BGR);
  121. {
  122. cv::Mat _hist = hist.getMat(cv::ACCESS_READ);
  123. for (int i = 0; i < hsize; i++)
  124. {
  125. int val = cv::saturate_cast<int>(_hist.at<float>(i)*histimg.rows/255);
  126. cv::rectangle(histimg, cv::Point(i*binW, histimg.rows),
  127. cv::Point((i+1)*binW, histimg.rows - val),
  128. cv::Scalar(buf.at<cv::Vec3b>(i)), -1, 8);
  129. }
  130. }
  131. }
  132. cv::calcBackProject(std::vector<cv::UMat>(1, hue), std::vector<int>(1, 0), hist, backproj,
  133. std::vector<float>(hranges, hranges + 2), 1.0);
  134. cv::bitwise_and(backproj, mask, backproj);
  135. cv::RotatedRect trackBox = cv::CamShift(backproj, trackWindow,
  136. cv::TermCriteria(cv::TermCriteria::EPS | cv::TermCriteria::COUNT, 10, 1));
  137. if (trackWindow.area() <= 1)
  138. {
  139. int cols = backproj.cols, rows = backproj.rows, r = (std::min(cols, rows) + 5)/6;
  140. trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r,
  141. trackWindow.x + r, trackWindow.y + r) &
  142. cv::Rect(0, 0, cols, rows);
  143. }
  144. if (backprojMode)
  145. cv::cvtColor(backproj, image, cv::COLOR_GRAY2BGR);
  146. {
  147. cv::Mat _image = image.getMat(cv::ACCESS_RW);
  148. cv::ellipse(_image, trackBox, cv::Scalar(0, 0, 255), 3, cv::LINE_AA);
  149. }
  150. }
  151. }
  152. else if (trackObject < 0)
  153. paused = false;
  154. if (selectObject && selection.width > 0 && selection.height > 0)
  155. {
  156. cv::UMat roi(image, selection);
  157. cv::bitwise_not(roi, roi);
  158. }
  159. cv::imshow("CamShift Demo", image);
  160. if (showHist)
  161. cv::imshow("Histogram", histimg);
  162. char c = (char)cv::waitKey(10);
  163. if (c == 27)
  164. break;
  165. switch(c)
  166. {
  167. case 'b':
  168. backprojMode = !backprojMode;
  169. break;
  170. case 't':
  171. trackObject = 0;
  172. histimg = cv::Scalar::all(0);
  173. break;
  174. case 'h':
  175. showHist = !showHist;
  176. if (!showHist)
  177. cv::destroyWindow("Histogram");
  178. else
  179. cv::namedWindow("Histogram", cv::WINDOW_AUTOSIZE);
  180. break;
  181. case 'p':
  182. paused = !paused;
  183. break;
  184. case 'c':
  185. cv::ocl::setUseOpenCL(!cv::ocl::useOpenCL());
  186. default:
  187. break;
  188. }
  189. }
  190. return EXIT_SUCCESS;
  191. }