video_homography.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * video_homography.cpp
  3. *
  4. * Created on: Oct 18, 2010
  5. * Author: erublee
  6. */
  7. #include <iostream>
  8. #include "opencv2/opencv_modules.hpp"
  9. #ifdef HAVE_OPENCV_CALIB3D
  10. #include "opencv2/calib3d.hpp"
  11. #include "opencv2/videoio.hpp"
  12. #include "opencv2/highgui.hpp"
  13. #include "opencv2/imgproc.hpp"
  14. #include "opencv2/features2d.hpp"
  15. #include "opencv2/xfeatures2d.hpp"
  16. #include <list>
  17. #include <vector>
  18. using namespace std;
  19. using namespace cv;
  20. using namespace cv::xfeatures2d;
  21. static void help(char **av)
  22. {
  23. cout << "\nThis program demonstrated the use of features2d with the Fast corner detector and brief descriptors\n"
  24. << "to track planar objects by computing their homography from the key (training) image to the query (test) image\n\n" << endl;
  25. cout << "usage: " << av[0] << " <video device number>\n" << endl;
  26. cout << "The following keys do stuff:" << endl;
  27. cout << " t : grabs a reference frame to match against" << endl;
  28. cout << " l : makes the reference frame new every frame" << endl;
  29. cout << " q or escape: quit" << endl;
  30. }
  31. namespace
  32. {
  33. void drawMatchesRelative(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
  34. std::vector<cv::DMatch>& matches, Mat& img, const vector<unsigned char>& mask = vector<
  35. unsigned char> ())
  36. {
  37. for (int i = 0; i < (int)matches.size(); i++)
  38. {
  39. if (mask.empty() || mask[i])
  40. {
  41. Point2f pt_new = query[matches[i].queryIdx].pt;
  42. Point2f pt_old = train[matches[i].trainIdx].pt;
  43. cv::line(img, pt_new, pt_old, Scalar(125, 255, 125), 1);
  44. cv::circle(img, pt_new, 2, Scalar(255, 0, 125), 1);
  45. }
  46. }
  47. }
  48. //Takes a descriptor and turns it into an xy point
  49. void keypoints2points(const vector<KeyPoint>& in, vector<Point2f>& out)
  50. {
  51. out.clear();
  52. out.reserve(in.size());
  53. for (size_t i = 0; i < in.size(); ++i)
  54. {
  55. out.push_back(in[i].pt);
  56. }
  57. }
  58. //Takes an xy point and appends that to a keypoint structure
  59. void points2keypoints(const vector<Point2f>& in, vector<KeyPoint>& out)
  60. {
  61. out.clear();
  62. out.reserve(in.size());
  63. for (size_t i = 0; i < in.size(); ++i)
  64. {
  65. out.push_back(KeyPoint(in[i], 1));
  66. }
  67. }
  68. //Uses computed homography H to warp original input points to new planar position
  69. void warpKeypoints(const Mat& H, const vector<KeyPoint>& in, vector<KeyPoint>& out)
  70. {
  71. vector<Point2f> pts;
  72. keypoints2points(in, pts);
  73. vector<Point2f> pts_w(pts.size());
  74. Mat m_pts_w(pts_w);
  75. perspectiveTransform(Mat(pts), m_pts_w, H);
  76. points2keypoints(pts_w, out);
  77. }
  78. //Converts matching indices to xy points
  79. void matches2points(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
  80. const std::vector<cv::DMatch>& matches, std::vector<cv::Point2f>& pts_train,
  81. std::vector<Point2f>& pts_query)
  82. {
  83. pts_train.clear();
  84. pts_query.clear();
  85. pts_train.reserve(matches.size());
  86. pts_query.reserve(matches.size());
  87. size_t i = 0;
  88. for (; i < matches.size(); i++)
  89. {
  90. const DMatch & dmatch = matches[i];
  91. pts_query.push_back(query[dmatch.queryIdx].pt);
  92. pts_train.push_back(train[dmatch.trainIdx].pt);
  93. }
  94. }
  95. void resetH(Mat&H)
  96. {
  97. H = Mat::eye(3, 3, CV_32FC1);
  98. }
  99. }
  100. int main(int ac, char ** av)
  101. {
  102. if (ac != 2)
  103. {
  104. help(av);
  105. return 1;
  106. }
  107. Ptr<BriefDescriptorExtractor> brief = BriefDescriptorExtractor::create(32);
  108. VideoCapture capture;
  109. capture.open(atoi(av[1]));
  110. if (!capture.isOpened())
  111. {
  112. help(av);
  113. cout << "capture device " << atoi(av[1]) << " failed to open!" << endl;
  114. return 1;
  115. }
  116. cout << "following keys do stuff:" << endl;
  117. cout << "t : grabs a reference frame to match against" << endl;
  118. cout << "l : makes the reference frame new every frame" << endl;
  119. cout << "q or escape: quit" << endl;
  120. Mat frame;
  121. vector<DMatch> matches;
  122. BFMatcher desc_matcher(brief->defaultNorm());
  123. vector<Point2f> train_pts, query_pts;
  124. vector<KeyPoint> train_kpts, query_kpts;
  125. vector<unsigned char> match_mask;
  126. Mat gray;
  127. bool ref_live = true;
  128. Mat train_desc, query_desc;
  129. Ptr<FastFeatureDetector> detector = FastFeatureDetector::create(10, true);
  130. Mat H_prev = Mat::eye(3, 3, CV_32FC1);
  131. for (;;)
  132. {
  133. capture >> frame;
  134. if (frame.empty())
  135. break;
  136. cvtColor(frame, gray, COLOR_RGB2GRAY);
  137. detector->detect(gray, query_kpts); //Find interest points
  138. brief->compute(gray, query_kpts, query_desc); //Compute brief descriptors at each keypoint location
  139. if (!train_kpts.empty())
  140. {
  141. vector<KeyPoint> test_kpts;
  142. warpKeypoints(H_prev.inv(), query_kpts, test_kpts);
  143. //Mat mask = windowedMatchingMask(test_kpts, train_kpts, 25, 25);
  144. desc_matcher.match(query_desc, train_desc, matches, Mat());
  145. drawKeypoints(frame, test_kpts, frame, Scalar(255, 0, 0), DrawMatchesFlags::DRAW_OVER_OUTIMG);
  146. matches2points(train_kpts, query_kpts, matches, train_pts, query_pts);
  147. if (matches.size() > 5)
  148. {
  149. Mat H = findHomography(train_pts, query_pts, RANSAC, 4, match_mask);
  150. if (countNonZero(Mat(match_mask)) > 15)
  151. {
  152. H_prev = H;
  153. }
  154. else
  155. resetH(H_prev);
  156. drawMatchesRelative(train_kpts, query_kpts, matches, frame, match_mask);
  157. }
  158. else
  159. resetH(H_prev);
  160. }
  161. else
  162. {
  163. H_prev = Mat::eye(3, 3, CV_32FC1);
  164. Mat out;
  165. drawKeypoints(gray, query_kpts, out);
  166. frame = out;
  167. }
  168. imshow("frame", frame);
  169. if (ref_live)
  170. {
  171. train_kpts = query_kpts;
  172. query_desc.copyTo(train_desc);
  173. }
  174. char key = (char)waitKey(2);
  175. switch (key)
  176. {
  177. case 'l':
  178. ref_live = true;
  179. resetH(H_prev);
  180. break;
  181. case 't':
  182. ref_live = false;
  183. train_kpts = query_kpts;
  184. query_desc.copyTo(train_desc);
  185. resetH(H_prev);
  186. break;
  187. case 27:
  188. case 'q':
  189. return 0;
  190. break;
  191. }
  192. }
  193. return 0;
  194. }
  195. #else
  196. int main()
  197. {
  198. std::cerr << "OpenCV was built without calib3d module" << std::endl;
  199. return 0;
  200. }
  201. #endif