FeatureMatch.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #include "FeatureMatch.h"
  2. /// 高斯核卷积平滑。img 是输入图像,ikernel 是高斯核
  3. /// 返回值为平滑图像
  4. Mat Conv2(const Mat &img, const Mat &ikernel)
  5. {
  6. Mat dest;
  7. Mat kernel;
  8. cv::flip(ikernel, kernel, -1);
  9. Mat source = img;
  10. Point anchor(kernel.cols - kernel.cols / 2 - 1, kernel.rows - kernel.rows / 2 - 1);
  11. int borderMode = cv::BORDER_CONSTANT;
  12. cv::filter2D(source, dest, img.depth(), kernel, anchor, 0, borderMode);
  13. return dest;
  14. }
  15. void GaussianSmooth(Mat src, Mat dst, float sigma)
  16. {
  17. if (src.type() != CV_32FC1)
  18. {
  19. src.convertTo(src, CV_32FC1);
  20. }
  21. int kSize = static_cast<int>(round(2 * sigma) * 2) + 1; // matlab: int kSize = round(2 * sigma) * 2 + 1;
  22. Mat K = cv::getGaussianKernel(kSize, sigma, CV_32FC1); // 获取 Gaussian kernel, sigma是标准差
  23. K = K * K.t();
  24. Mat dstImg = Conv2(src, K);
  25. dstImg.convertTo(dst, CV_8U, 1);
  26. }
  27. //速度最快,但是特征点识别能力最弱
  28. void ORBMatch(Mat img1, Mat img2, vector<KeyPoint>& keypoints1, vector<KeyPoint>& keypoints2,
  29. vector<DMatch>& bestMatches)
  30. {
  31. const float ratio = 0.8;
  32. //1. initinal
  33. //Ptr<FeatureDetector> detector = ORB::create();
  34. //Ptr<DescriptorExtractor> extractor = ORB::create();
  35. Ptr<ORB> orb = ORB::create();
  36. Mat descriptors1, descriptors2;
  37. vector<vector<DMatch>> matches12, matches21;
  38. Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
  39. // 2. detect features and extract the descriptors
  40. //detector->detect(img1, keypoints1);
  41. //extractor->compute(img1, keypoints1, descriptors1);
  42. //detector->detect(img2, keypoints2);
  43. //extractor->compute(img2, keypoints2, descriptors2);
  44. orb->detect(img1, keypoints1);
  45. orb->compute(img1, keypoints1, descriptors1);
  46. orb->detect(img2, keypoints2);
  47. orb->compute(img2, keypoints2, descriptors2);
  48. #ifdef _DEBUG
  49. Mat imgKeypoints1, imgKeypoints2;
  50. drawKeypoints(img1, keypoints1, imgKeypoints1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
  51. drawKeypoints(img2, keypoints2, imgKeypoints2, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
  52. #endif
  53. if (!(keypoints1.size() > 0 && keypoints2.size() > 0))
  54. {
  55. return;
  56. }
  57. //3.Match the descriptors in two directions...
  58. matcher->knnMatch(descriptors1, descriptors2, matches12, 2);
  59. matcher->knnMatch(descriptors2, descriptors1, matches21, 2);
  60. //4. ratio test proposed by David Lowe's paper 0.8
  61. vector<DMatch> goodMatches1, goodMatches2;
  62. goodMatches1 = RatioTest(matches12, ratio);
  63. goodMatches2 = RatioTest(matches21, ratio);
  64. // Symmetric Test
  65. bestMatches = SymmetricTest(goodMatches1, goodMatches2);
  66. #ifdef _DEBUG
  67. cout << "Good matches1:" << goodMatches1.size() << endl;
  68. cout << "Good matches2:" << goodMatches2.size() << endl;
  69. cout << "Best matches:" << bestMatches.size() << endl;
  70. #endif
  71. }
  72. void SURFMatch(Mat img1, Mat img2, vector<KeyPoint>& keypoints1, vector<KeyPoint>& keypoints2,
  73. vector<DMatch>& bestMatches)
  74. {
  75. // Step 1: Detect the keypoints using SURF Detector
  76. double minHessian = 400.0 /*800*/;
  77. //SurfFeatureDetector detector(minHessian);
  78. Ptr<SurfFeatureDetector> detector = SurfFeatureDetector::create();
  79. detector->setHessianThreshold(minHessian);
  80. detector->detect(img1, keypoints1);
  81. detector->detect(img2, keypoints2);
  82. if (!(keypoints1.size()>0 && keypoints2.size()>0))
  83. {
  84. return;
  85. }
  86. // Step 2: Calculate descriptors (feature vectors)
  87. //SurfDescriptorExtractor extractor;
  88. Ptr<SurfDescriptorExtractor> extractor = SurfFeatureDetector::create();
  89. Mat descriptors1, descriptors2;
  90. extractor->compute(img1, keypoints1, descriptors1);
  91. extractor->compute(img2, keypoints2, descriptors2);
  92. #ifdef _DEBUG
  93. Mat imgKeypoints1, imgKeypoints2;
  94. drawKeypoints(img1, keypoints1, imgKeypoints1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
  95. drawKeypoints(img2, keypoints2, imgKeypoints2, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
  96. #endif
  97. // Step 3: Matching descriptor vectors using FLANN matcher
  98. FlannBasedMatcher matcher;
  99. //Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
  100. //Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
  101. // BFMatcher matcher(NORM_L2, true);
  102. vector<DMatch> matches1, matches2;
  103. matcher.match(descriptors1, descriptors2, matches1);
  104. matcher.match(descriptors2, descriptors1, matches2);
  105. vector<DMatch> goodMatches1, goodMatches2;
  106. goodMatches1 = FilterDistance(descriptors1, matches1);
  107. goodMatches2 = FilterDistance(descriptors2, matches2);
  108. for (int i = 0; i < goodMatches1.size(); i++)
  109. {
  110. DMatch temp1 = goodMatches1[i];
  111. for (int j = 0; j < goodMatches2.size(); j++)
  112. {
  113. DMatch temp2 = goodMatches2[j];
  114. if (temp1.queryIdx == temp2.trainIdx && temp2.queryIdx == temp1.trainIdx)
  115. {
  116. bestMatches.push_back(temp1);
  117. break;
  118. }
  119. }
  120. }
  121. #ifdef _DEBUG
  122. // Draw only "good" matches
  123. Mat img_matches;
  124. cv::drawMatches(img1, keypoints1, img2, keypoints2, bestMatches, img_matches, Scalar::all(-1), Scalar::all(-1),
  125. vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
  126. //for (int i = 0; i < (int)bestMatches.size(); i++)
  127. //{
  128. // printf("-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n", i, bestMatches[i].queryIdx, bestMatches[i].trainIdx);
  129. //}
  130. #endif
  131. }
  132. // 对单服图像检测到的特征点较多,优于SURF, 但对同2幅图重复检测时匹配的特征点会跳动
  133. void SIFTMatch(Mat img1, Mat img2, vector<KeyPoint>& keypoints1, vector<KeyPoint>& keypoints2,
  134. vector<DMatch>& bestMatches)
  135. {
  136. const float ratio = 0.8;
  137. Ptr<SiftFeatureDetector> detector = SiftFeatureDetector::create(0, 3, 0.04, 10, 1.2);
  138. Ptr<SiftDescriptorExtractor> extractor = SiftDescriptorExtractor::create();
  139. detector->detect(img1, keypoints1);
  140. detector->detect(img2, keypoints2);
  141. #ifdef _DEBUG
  142. cout << "keypoints1 的数目是:" << keypoints1.size() << ", keypoints2 的数目是:" << keypoints2.size() << endl;
  143. #endif
  144. Mat descriptors1, descriptors2;
  145. extractor->compute(img1, keypoints1, descriptors1);
  146. extractor->compute(img2, keypoints2, descriptors2);
  147. #ifdef _DEBUG
  148. Mat imgKeypoints1, imgKeypoints2;
  149. drawKeypoints(img1, keypoints1, imgKeypoints1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
  150. drawKeypoints(img2, keypoints2, imgKeypoints2, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
  151. #endif
  152. // 当 keypoints1.size() == keypoints2.size() == 1 时,触发 OpenCV Error:
  153. // Assertion failed ((globalDescIdx>=0) && (globalDescIdx < size()))
  154. // in cv::DescriptorMatcher::DescriptorCollection::getLocalIdx,
  155. // .\opencv\sources\modules\features2d\src\matchers.cpp, line 488
  156. // 当 keypoints1.size() 与 keypoints2.size()任意一个等于0时,触发OpenCV Error:
  157. // Unsupported format or combination of formats (type=0) in cv::flann::buildIndex_,
  158. // .\opencv\sources\modules\flann\src\miniflann.cpp, line 315
  159. if ((keypoints2.size() <= 1) || (keypoints1.size() <= 1))
  160. {
  161. return;
  162. }
  163. vector<vector<DMatch>> matches12, matches21;
  164. Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
  165. // knnMatch()的第二个参数对应的 keypoints.size()==0 时,FlannBasedMatcher::train() 报错
  166. // knnMatch()的第二个参数对应的 keypoints.size()==1 时, flannIndex->knnSearch() 报错
  167. matcher->knnMatch(descriptors1, descriptors2, matches12, 2);
  168. matcher->knnMatch(descriptors2, descriptors1, matches21, 2);
  169. // ratio test proposed by David Lowe paper = 0.8
  170. vector<DMatch> goodMatches1, goodMatches2;
  171. goodMatches1 = RatioTest(matches12, ratio);
  172. goodMatches2 = RatioTest(matches21, ratio);
  173. bestMatches = SymmetricTest(goodMatches1, goodMatches2);
  174. #ifdef _DEBUG
  175. Mat output;
  176. cv::drawMatches(img1, keypoints1, img2, keypoints2, bestMatches, output);
  177. #endif
  178. }
  179. //ratio test nearest/second nearest < ratio
  180. vector<DMatch> RatioTest(vector<vector<DMatch>> matches12, double ratio)
  181. {
  182. vector<DMatch> goodMatches;
  183. for (int i = 0; i < (int)matches12.size(); i++)
  184. {
  185. if (matches12[i].size() == 2)
  186. {
  187. if (matches12[i][0].distance < ratio * matches12[i][1].distance)
  188. goodMatches.push_back(matches12[i][0]);
  189. }
  190. else
  191. {
  192. break;
  193. }
  194. }
  195. return goodMatches;
  196. }
  197. // Symmetric Test
  198. vector<DMatch> SymmetricTest(vector<DMatch> goodMatches1, vector<DMatch> goodMatches2)
  199. {
  200. vector<DMatch> betterMatches;
  201. for (int i = 0; i < goodMatches1.size(); i++)
  202. {
  203. for (int j = 0; j < goodMatches2.size(); j++)
  204. {
  205. if (goodMatches1[i].queryIdx == goodMatches2[j].trainIdx && goodMatches2[j].queryIdx == goodMatches1[i].trainIdx)
  206. {
  207. betterMatches.push_back(DMatch(goodMatches1[i].queryIdx, goodMatches1[i].trainIdx, goodMatches1[i].distance));
  208. break;
  209. }
  210. }
  211. }
  212. return betterMatches;
  213. }
  214. vector<DMatch> FilterDistance(Mat descriptors, vector<DMatch> matches)
  215. {
  216. double max_dist = 0; double min_dist = 100;
  217. // Quick calculation of max and min distances between keypoints
  218. for (int i = 0; i < descriptors.rows; i++)
  219. {
  220. double dist = matches[i].distance;
  221. if (dist < min_dist)
  222. min_dist = dist;
  223. if (dist > max_dist)
  224. max_dist = dist;
  225. }
  226. // Draw only "good" matches (i.e. whose distance is less than 2*min_dist,
  227. // or a small arbitary value ( 0.02 ) in the event that min_dist is very small)
  228. // PS.- radiusMatch can also be used here.
  229. std::vector< DMatch > good_matches;
  230. for (int i = 0; i < descriptors.rows; i++)
  231. {
  232. if (matches[i].distance <= 5 * min_dist)
  233. {
  234. good_matches.push_back(matches[i]);
  235. }
  236. }
  237. return good_matches;
  238. }