// or tort (including negligence or otherwise) arising in any way out of\r
// the use of this software, even if advised of the possibility of such damage.\r
//\r
-//M*/
-#include <algorithm>
-#include <functional>
-#include "matchers.hpp"
-#include "util.hpp"
-
-using namespace std;
-using namespace cv;
-using namespace cv::gpu;
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-void FeaturesFinder::operator ()(const Mat &image, ImageFeatures &features)
-{
- find(image, features);
- features.img_size = image.size();
- //features.img = image.clone();
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- class CpuSurfFeaturesFinder : public FeaturesFinder
- {
- public:
- CpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers,
- int num_octaves_descr, int num_layers_descr)
- {
- detector_ = new SurfFeatureDetector(hess_thresh, num_octaves, num_layers);
- extractor_ = new SurfDescriptorExtractor(num_octaves_descr, num_layers_descr);
- }
-
- protected:
- void find(const Mat &image, ImageFeatures &features);
-
- private:
- Ptr<FeatureDetector> detector_;
- Ptr<DescriptorExtractor> extractor_;
- };
-
-
- class GpuSurfFeaturesFinder : public FeaturesFinder
- {
- public:
- GpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers,
- int num_octaves_descr, int num_layers_descr)
- {
- surf_.keypointsRatio = 0.1f;
- surf_.hessianThreshold = hess_thresh;
- surf_.extended = false;
- num_octaves_ = num_octaves;
- num_layers_ = num_layers;
- num_octaves_descr_ = num_octaves_descr;
- num_layers_descr_ = num_layers_descr;
- }
-
- protected:
- void find(const Mat &image, ImageFeatures &features);
-
- private:
- SURF_GPU surf_;
- int num_octaves_, num_layers_;
- int num_octaves_descr_, num_layers_descr_;
- };
-
-
- void CpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
- {
- Mat gray_image;
- CV_Assert(image.depth() == CV_8U);
- cvtColor(image, gray_image, CV_BGR2GRAY);
- detector_->detect(gray_image, features.keypoints);
- extractor_->compute(gray_image, features.keypoints, features.descriptors);
- }
-
-
- void GpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
- {
- GpuMat gray_image;
- CV_Assert(image.depth() == CV_8U);
- cvtColor(GpuMat(image), gray_image, CV_BGR2GRAY);
-
- GpuMat d_keypoints;
- GpuMat d_descriptors;
- surf_.nOctaves = num_octaves_;
- surf_.nOctaveLayers = num_layers_;
- surf_(gray_image, GpuMat(), d_keypoints);
-
- surf_.nOctaves = num_octaves_descr_;
- surf_.nOctaveLayers = num_layers_descr_;
- surf_(gray_image, GpuMat(), d_keypoints, d_descriptors, true);
- surf_.downloadKeypoints(d_keypoints, features.keypoints);
-
- d_descriptors.download(features.descriptors);
- }
-} // anonymous namespace
-
-
-SurfFeaturesFinder::SurfFeaturesFinder(bool try_use_gpu, double hess_thresh, int num_octaves, int num_layers,
- int num_octaves_descr, int num_layers_descr)
-{
- if (try_use_gpu && getCudaEnabledDeviceCount() > 0)
- impl_ = new GpuSurfFeaturesFinder(hess_thresh, num_octaves, num_layers, num_octaves_descr, num_layers_descr);
- else
- impl_ = new CpuSurfFeaturesFinder(hess_thresh, num_octaves, num_layers, num_octaves_descr, num_layers_descr);
-}
-
-
-void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
-{
- (*impl_)(image, features);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-MatchesInfo::MatchesInfo() : src_img_idx(-1), dst_img_idx(-1), num_inliers(0), confidence(0) {}
-
-MatchesInfo::MatchesInfo(const MatchesInfo &other) { *this = other; }
-
-const MatchesInfo& MatchesInfo::operator =(const MatchesInfo &other)
-{
- src_img_idx = other.src_img_idx;
- dst_img_idx = other.dst_img_idx;
- matches = other.matches;
- inliers_mask = other.inliers_mask;
- num_inliers = other.num_inliers;
- H = other.H.clone();
- confidence = other.confidence;
- return *this;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-struct DistIdxPair
-{
- bool operator<(const DistIdxPair &other) const { return dist < other.dist; }
- double dist;
- int idx;
-};
-
-
-struct MatchPairsBody
-{
- MatchPairsBody(const MatchPairsBody& other)
- : matcher(other.matcher), features(other.features),
- pairwise_matches(other.pairwise_matches), near_pairs(other.near_pairs) {}
-
- MatchPairsBody(FeaturesMatcher &matcher, const vector<ImageFeatures> &features,
- vector<MatchesInfo> &pairwise_matches, vector<pair<int,int> > &near_pairs)
- : matcher(matcher), features(features),
- pairwise_matches(pairwise_matches), near_pairs(near_pairs) {}
-
- void operator ()(const BlockedRange &r) const
- {
- const int num_images = static_cast<int>(features.size());
- for (int i = r.begin(); i < r.end(); ++i)
- {
- int from = near_pairs[i].first;
- int to = near_pairs[i].second;
- int pair_idx = from*num_images + to;
-
- matcher(features[from], features[to], pairwise_matches[pair_idx]);
- pairwise_matches[pair_idx].src_img_idx = from;
- pairwise_matches[pair_idx].dst_img_idx = to;
-
- size_t dual_pair_idx = to*num_images + from;
-
- pairwise_matches[dual_pair_idx] = pairwise_matches[pair_idx];
- pairwise_matches[dual_pair_idx].src_img_idx = to;
- pairwise_matches[dual_pair_idx].dst_img_idx = from;
-
- if (!pairwise_matches[pair_idx].H.empty())
- pairwise_matches[dual_pair_idx].H = pairwise_matches[pair_idx].H.inv();
-
- for (size_t j = 0; j < pairwise_matches[dual_pair_idx].matches.size(); ++j)
- swap(pairwise_matches[dual_pair_idx].matches[j].queryIdx,
- pairwise_matches[dual_pair_idx].matches[j].trainIdx);
- LOG(".");
- }
- }
-
- FeaturesMatcher &matcher;
- const vector<ImageFeatures> &features;
- vector<MatchesInfo> &pairwise_matches;
- vector<pair<int,int> > &near_pairs;
-
-private:
- void operator =(const MatchPairsBody&);
-};
-
-
-void FeaturesMatcher::operator ()(const vector<ImageFeatures> &features, vector<MatchesInfo> &pairwise_matches)
-{
- const int num_images = static_cast<int>(features.size());
-
- vector<pair<int,int> > near_pairs;
- for (int i = 0; i < num_images - 1; ++i)
- for (int j = i + 1; j < num_images; ++j)
- near_pairs.push_back(make_pair(i, j));
-
- pairwise_matches.resize(num_images * num_images);
- MatchPairsBody body(*this, features, pairwise_matches, near_pairs);
-
- if (is_thread_safe_)
- parallel_for(BlockedRange(0, static_cast<int>(near_pairs.size())), body);
- else
- body(BlockedRange(0, static_cast<int>(near_pairs.size())));
- LOGLN("");
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- // These two classes are aimed to find features matches only, not to
- // estimate homography
-
- class CpuMatcher : public FeaturesMatcher
- {
- public:
- CpuMatcher(float match_conf) : FeaturesMatcher(true), match_conf_(match_conf) {}
- void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info);
-
- private:
- float match_conf_;
- };
-
-
- class GpuMatcher : public FeaturesMatcher
- {
- public:
- GpuMatcher(float match_conf) : match_conf_(match_conf) {}
- void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info);
-
- private:
- float match_conf_;
- GpuMat descriptors1_, descriptors2_;
- GpuMat train_idx_, distance_, all_dist_;
- };
-
-
- void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)
- {
- matches_info.matches.clear();
- FlannBasedMatcher matcher;
- vector< vector<DMatch> > pair_matches;
-
- // Find 1->2 matches
- matcher.knnMatch(features1.descriptors, features2.descriptors, pair_matches, 2);
- for (size_t i = 0; i < pair_matches.size(); ++i)
- {
- if (pair_matches[i].size() < 2)
- continue;
- const DMatch& m0 = pair_matches[i][0];
- const DMatch& m1 = pair_matches[i][1];
- if (m0.distance < (1.f - match_conf_) * m1.distance)
- matches_info.matches.push_back(m0);
- }
-
- // Find 2->1 matches
- pair_matches.clear();
- matcher.knnMatch(features2.descriptors, features1.descriptors, pair_matches, 2);
- for (size_t i = 0; i < pair_matches.size(); ++i)
- {
- if (pair_matches[i].size() < 2)
- continue;
- const DMatch& m0 = pair_matches[i][0];
- const DMatch& m1 = pair_matches[i][1];
- if (m0.distance < (1.f - match_conf_) * m1.distance)
- matches_info.matches.push_back(DMatch(m0.trainIdx, m0.queryIdx, m0.distance));
- }
- }
-
-
- void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)
- {
- matches_info.matches.clear();
- descriptors1_.upload(features1.descriptors);
- descriptors2_.upload(features2.descriptors);
- BruteForceMatcher_GPU< L2<float> > matcher;
- vector< vector<DMatch> > pair_matches;
-
- // Find 1->2 matches
- matcher.knnMatch(descriptors1_, descriptors2_, train_idx_, distance_, all_dist_, 2);
- matcher.knnMatchDownload(train_idx_, distance_, pair_matches);
- for (size_t i = 0; i < pair_matches.size(); ++i)
- {
- if (pair_matches[i].size() < 2)
- continue;
- const DMatch& m0 = pair_matches[i][0];
- const DMatch& m1 = pair_matches[i][1];
- if (m0.distance < (1.f - match_conf_) * m1.distance)
- matches_info.matches.push_back(m0);
- }
-
- // Find 2->1 matches
- pair_matches.clear();
- matcher.knnMatch(descriptors2_, descriptors1_, train_idx_, distance_, all_dist_, 2);
- matcher.knnMatchDownload(train_idx_, distance_, pair_matches);
- for (size_t i = 0; i < pair_matches.size(); ++i)
- {
- if (pair_matches[i].size() < 2)
- continue;
- const DMatch& m0 = pair_matches[i][0];
- const DMatch& m1 = pair_matches[i][1];
- if (m0.distance < (1.f - match_conf_) * m1.distance)
- matches_info.matches.push_back(DMatch(m0.trainIdx, m0.queryIdx, m0.distance));
- }
- }
-
-} // anonymous namespace
-
-
-BestOf2NearestMatcher::BestOf2NearestMatcher(bool try_use_gpu, float match_conf, int num_matches_thresh1, int num_matches_thresh2)
-{
- if (try_use_gpu && getCudaEnabledDeviceCount() > 0)
- impl_ = new GpuMatcher(match_conf);
- else
- impl_ = new CpuMatcher(match_conf);
-
- is_thread_safe_ = impl_->isThreadSafe();
- num_matches_thresh1_ = num_matches_thresh1;
- num_matches_thresh2_ = num_matches_thresh2;
-}
-
-
-void BestOf2NearestMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2,
- MatchesInfo &matches_info)
-{
- (*impl_)(features1, features2, matches_info);
-
- //Mat out;
- //drawMatches(features1.img, features1.keypoints, features2.img, features2.keypoints, matches_info.matches, out);
- //stringstream ss;
- //ss << features1.img_idx << features2.img_idx << ".png";
- //imwrite(ss.str(), out);
-
- // Check if it makes sense to find homography
- if (matches_info.matches.size() < static_cast<size_t>(num_matches_thresh1_))
- return;
-
- // Construct point-point correspondences for homography estimation
- Mat src_points(1, matches_info.matches.size(), CV_32FC2);
- Mat dst_points(1, matches_info.matches.size(), CV_32FC2);
- for (size_t i = 0; i < matches_info.matches.size(); ++i)
- {
- const DMatch& m = matches_info.matches[i];
-
- Point2f p = features1.keypoints[m.queryIdx].pt;
- p.x -= features1.img_size.width * 0.5f;
- p.y -= features1.img_size.height * 0.5f;
- src_points.at<Point2f>(0, i) = p;
-
- p = features2.keypoints[m.trainIdx].pt;
- p.x -= features2.img_size.width * 0.5f;
- p.y -= features2.img_size.height * 0.5f;
- dst_points.at<Point2f>(0, i) = p;
- }
-
- // Find pair-wise motion
- matches_info.H = findHomography(src_points, dst_points, matches_info.inliers_mask, CV_RANSAC);
-
- // Find number of inliers
- matches_info.num_inliers = 0;
- for (size_t i = 0; i < matches_info.inliers_mask.size(); ++i)
- if (matches_info.inliers_mask[i])
- matches_info.num_inliers++;
-
- matches_info.confidence = matches_info.num_inliers / (8 + 0.3*matches_info.matches.size());
-
- // Check if we should try to refine motion
- if (matches_info.num_inliers < num_matches_thresh2_)
- return;
-
- // Construct point-point correspondences for inliers only
- src_points.create(1, matches_info.num_inliers, CV_32FC2);
- dst_points.create(1, matches_info.num_inliers, CV_32FC2);
- int inlier_idx = 0;
- for (size_t i = 0; i < matches_info.matches.size(); ++i)
- {
- if (!matches_info.inliers_mask[i])
- continue;
-
- const DMatch& m = matches_info.matches[i];
-
- Point2f p = features1.keypoints[m.queryIdx].pt;
- p.x -= features1.img_size.width * 0.5f;
- p.y -= features1.img_size.height * 0.5f;
- src_points.at<Point2f>(0, inlier_idx) = p;
-
- p = features2.keypoints[m.trainIdx].pt;
- p.x -= features2.img_size.width * 0.5f;
- p.y -= features2.img_size.height * 0.5f;
- dst_points.at<Point2f>(0, inlier_idx) = p;
-
- inlier_idx++;
- }
-
- // Rerun motion estimation on inliers only
- matches_info.H = findHomography(src_points, dst_points, CV_RANSAC);
-}
+//M*/\r
+#include <algorithm>\r
+#include <functional>\r
+#include "matchers.hpp"\r
+#include "util.hpp"\r
+\r
+using namespace std;\r
+using namespace cv;\r
+using namespace cv::gpu;\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+void FeaturesFinder::operator ()(const Mat &image, ImageFeatures &features) \r
+{ \r
+ find(image, features);\r
+ features.img_size = image.size();\r
+ //features.img = image.clone();\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+namespace\r
+{\r
+ class CpuSurfFeaturesFinder : public FeaturesFinder\r
+ {\r
+ public:\r
+ CpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers, \r
+ int num_octaves_descr, int num_layers_descr) \r
+ {\r
+ detector_ = new SurfFeatureDetector(hess_thresh, num_octaves, num_layers);\r
+ extractor_ = new SurfDescriptorExtractor(num_octaves_descr, num_layers_descr);\r
+ }\r
+\r
+ protected:\r
+ void find(const Mat &image, ImageFeatures &features);\r
+\r
+ private:\r
+ Ptr<FeatureDetector> detector_;\r
+ Ptr<DescriptorExtractor> extractor_;\r
+ };\r
+\r
+\r
+ class GpuSurfFeaturesFinder : public FeaturesFinder\r
+ {\r
+ public:\r
+ GpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers, \r
+ int num_octaves_descr, int num_layers_descr) \r
+ {\r
+ surf_.keypointsRatio = 0.1f;\r
+ surf_.hessianThreshold = hess_thresh;\r
+ surf_.extended = false;\r
+ num_octaves_ = num_octaves;\r
+ num_layers_ = num_layers;\r
+ num_octaves_descr_ = num_octaves_descr;\r
+ num_layers_descr_ = num_layers_descr;\r
+ }\r
+\r
+ protected:\r
+ void find(const Mat &image, ImageFeatures &features);\r
+\r
+ private:\r
+ SURF_GPU surf_;\r
+ int num_octaves_, num_layers_;\r
+ int num_octaves_descr_, num_layers_descr_;\r
+ };\r
+\r
+\r
+ void CpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)\r
+ {\r
+ Mat gray_image;\r
+ CV_Assert(image.depth() == CV_8U);\r
+ cvtColor(image, gray_image, CV_BGR2GRAY);\r
+ detector_->detect(gray_image, features.keypoints);\r
+ extractor_->compute(gray_image, features.keypoints, features.descriptors);\r
+ }\r
+ \r
+\r
+ void GpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)\r
+ {\r
+ GpuMat gray_image;\r
+ CV_Assert(image.depth() == CV_8U);\r
+ cvtColor(GpuMat(image), gray_image, CV_BGR2GRAY);\r
+\r
+ GpuMat d_keypoints;\r
+ GpuMat d_descriptors;\r
+ surf_.nOctaves = num_octaves_;\r
+ surf_.nOctaveLayers = num_layers_;\r
+ surf_(gray_image, GpuMat(), d_keypoints);\r
+\r
+ surf_.nOctaves = num_octaves_descr_;\r
+ surf_.nOctaveLayers = num_layers_descr_;\r
+ surf_(gray_image, GpuMat(), d_keypoints, d_descriptors, true);\r
+ surf_.downloadKeypoints(d_keypoints, features.keypoints);\r
+\r
+ d_descriptors.download(features.descriptors);\r
+ }\r
+} // anonymous namespace\r
+\r
+\r
+SurfFeaturesFinder::SurfFeaturesFinder(bool try_use_gpu, double hess_thresh, int num_octaves, int num_layers, \r
+ int num_octaves_descr, int num_layers_descr)\r
+{\r
+ if (try_use_gpu && getCudaEnabledDeviceCount() > 0)\r
+ impl_ = new GpuSurfFeaturesFinder(hess_thresh, num_octaves, num_layers, num_octaves_descr, num_layers_descr);\r
+ else\r
+ impl_ = new CpuSurfFeaturesFinder(hess_thresh, num_octaves, num_layers, num_octaves_descr, num_layers_descr);\r
+}\r
+\r
+\r
+void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)\r
+{\r
+ (*impl_)(image, features);\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+MatchesInfo::MatchesInfo() : src_img_idx(-1), dst_img_idx(-1), num_inliers(0), confidence(0) {}\r
+\r
+MatchesInfo::MatchesInfo(const MatchesInfo &other) { *this = other; }\r
+\r
+const MatchesInfo& MatchesInfo::operator =(const MatchesInfo &other)\r
+{\r
+ src_img_idx = other.src_img_idx;\r
+ dst_img_idx = other.dst_img_idx;\r
+ matches = other.matches;\r
+ inliers_mask = other.inliers_mask;\r
+ num_inliers = other.num_inliers;\r
+ H = other.H.clone();\r
+ confidence = other.confidence;\r
+ return *this;\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+struct DistIdxPair\r
+{\r
+ bool operator<(const DistIdxPair &other) const { return dist < other.dist; }\r
+ double dist;\r
+ int idx;\r
+};\r
+\r
+\r
+struct MatchPairsBody\r
+{\r
+ MatchPairsBody(const MatchPairsBody& other)\r
+ : matcher(other.matcher), features(other.features), \r
+ pairwise_matches(other.pairwise_matches), near_pairs(other.near_pairs) {}\r
+\r
+ MatchPairsBody(FeaturesMatcher &matcher, const vector<ImageFeatures> &features, \r
+ vector<MatchesInfo> &pairwise_matches, vector<pair<int,int> > &near_pairs)\r
+ : matcher(matcher), features(features), \r
+ pairwise_matches(pairwise_matches), near_pairs(near_pairs) {}\r
+\r
+ void operator ()(const BlockedRange &r) const \r
+ {\r
+ const int num_images = static_cast<int>(features.size());\r
+ for (int i = r.begin(); i < r.end(); ++i)\r
+ {\r
+ int from = near_pairs[i].first;\r
+ int to = near_pairs[i].second;\r
+ int pair_idx = from*num_images + to;\r
+\r
+ matcher(features[from], features[to], pairwise_matches[pair_idx]);\r
+ pairwise_matches[pair_idx].src_img_idx = from;\r
+ pairwise_matches[pair_idx].dst_img_idx = to;\r
+\r
+ size_t dual_pair_idx = to*num_images + from;\r
+\r
+ pairwise_matches[dual_pair_idx] = pairwise_matches[pair_idx];\r
+ pairwise_matches[dual_pair_idx].src_img_idx = to;\r
+ pairwise_matches[dual_pair_idx].dst_img_idx = from;\r
+\r
+ if (!pairwise_matches[pair_idx].H.empty())\r
+ pairwise_matches[dual_pair_idx].H = pairwise_matches[pair_idx].H.inv();\r
+\r
+ for (size_t j = 0; j < pairwise_matches[dual_pair_idx].matches.size(); ++j)\r
+ swap(pairwise_matches[dual_pair_idx].matches[j].queryIdx,\r
+ pairwise_matches[dual_pair_idx].matches[j].trainIdx);\r
+ LOG(".");\r
+ }\r
+ }\r
+\r
+ FeaturesMatcher &matcher;\r
+ const vector<ImageFeatures> &features;\r
+ vector<MatchesInfo> &pairwise_matches;\r
+ vector<pair<int,int> > &near_pairs;\r
+\r
+private:\r
+ void operator =(const MatchPairsBody&);\r
+};\r
+\r
+\r
+void FeaturesMatcher::operator ()(const vector<ImageFeatures> &features, vector<MatchesInfo> &pairwise_matches)\r
+{\r
+ const int num_images = static_cast<int>(features.size());\r
+\r
+ vector<pair<int,int> > near_pairs;\r
+ for (int i = 0; i < num_images - 1; ++i)\r
+ for (int j = i + 1; j < num_images; ++j)\r
+ near_pairs.push_back(make_pair(i, j));\r
+\r
+ pairwise_matches.resize(num_images * num_images);\r
+ MatchPairsBody body(*this, features, pairwise_matches, near_pairs);\r
+\r
+ if (is_thread_safe_)\r
+ parallel_for(BlockedRange(0, static_cast<int>(near_pairs.size())), body);\r
+ else\r
+ body(BlockedRange(0, static_cast<int>(near_pairs.size())));\r
+ LOGLN("");\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+namespace \r
+{\r
+ class PairLess\r
+ {\r
+ public:\r
+ bool operator()(const pair<int,int>& l, const pair<int,int>& r) const\r
+ {\r
+ return l.first < r.first || (l.first == r.first && l.second < r.second);\r
+ }\r
+ };\r
+ typedef set<pair<int,int>,PairLess> MatchesSet;\r
+\r
+ // These two classes are aimed to find features matches only, not to \r
+ // estimate homography\r
+\r
+ class CpuMatcher : public FeaturesMatcher\r
+ {\r
+ public:\r
+ CpuMatcher(float match_conf) : FeaturesMatcher(true), match_conf_(match_conf) {}\r
+ void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info);\r
+\r
+ private:\r
+ float match_conf_;\r
+ };\r
+\r
+\r
+ class GpuMatcher : public FeaturesMatcher\r
+ {\r
+ public:\r
+ GpuMatcher(float match_conf) : match_conf_(match_conf) {}\r
+ void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info);\r
+\r
+ private:\r
+ float match_conf_;\r
+ GpuMat descriptors1_, descriptors2_;\r
+ GpuMat train_idx_, distance_, all_dist_;\r
+ };\r
+\r
+\r
+ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)\r
+ {\r
+ matches_info.matches.clear();\r
+ FlannBasedMatcher matcher;\r
+ vector< vector<DMatch> > pair_matches; \r
+ MatchesSet matches;\r
+\r
+ // Find 1->2 matches\r
+ matcher.knnMatch(features1.descriptors, features2.descriptors, pair_matches, 2);\r
+ for (size_t i = 0; i < pair_matches.size(); ++i)\r
+ {\r
+ if (pair_matches[i].size() < 2)\r
+ continue;\r
+ const DMatch& m0 = pair_matches[i][0];\r
+ const DMatch& m1 = pair_matches[i][1];\r
+ if (m0.distance < (1.f - match_conf_) * m1.distance)\r
+ {\r
+ matches_info.matches.push_back(m0);\r
+ matches.insert(make_pair(m0.queryIdx, m0.trainIdx));\r
+ }\r
+ }\r
+\r
+ // Find 2->1 matches\r
+ pair_matches.clear();\r
+ matcher.knnMatch(features2.descriptors, features1.descriptors, pair_matches, 2);\r
+ for (size_t i = 0; i < pair_matches.size(); ++i)\r
+ {\r
+ if (pair_matches[i].size() < 2)\r
+ continue;\r
+ const DMatch& m0 = pair_matches[i][0];\r
+ const DMatch& m1 = pair_matches[i][1];\r
+ if (m0.distance < (1.f - match_conf_) * m1.distance)\r
+ if (matches.find(make_pair(m0.trainIdx, m0.queryIdx)) == matches.end())\r
+ matches_info.matches.push_back(DMatch(m0.trainIdx, m0.queryIdx, m0.distance));\r
+ }\r
+ }\r
+ \r
+\r
+ void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)\r
+ {\r
+ matches_info.matches.clear(); \r
+ descriptors1_.upload(features1.descriptors);\r
+ descriptors2_.upload(features2.descriptors);\r
+ BruteForceMatcher_GPU< L2<float> > matcher;\r
+ vector< vector<DMatch> > pair_matches;\r
+ MatchesSet matches;\r
+\r
+ // Find 1->2 matches\r
+ matcher.knnMatch(descriptors1_, descriptors2_, train_idx_, distance_, all_dist_, 2);\r
+ matcher.knnMatchDownload(train_idx_, distance_, pair_matches);\r
+ for (size_t i = 0; i < pair_matches.size(); ++i)\r
+ {\r
+ if (pair_matches[i].size() < 2)\r
+ continue;\r
+ const DMatch& m0 = pair_matches[i][0];\r
+ const DMatch& m1 = pair_matches[i][1];\r
+ if (m0.distance < (1.f - match_conf_) * m1.distance)\r
+ {\r
+ matches_info.matches.push_back(m0);\r
+ matches.insert(make_pair(m0.queryIdx, m0.trainIdx));\r
+ }\r
+ }\r
+\r
+ // Find 2->1 matches\r
+ pair_matches.clear();\r
+ matcher.knnMatch(descriptors2_, descriptors1_, train_idx_, distance_, all_dist_, 2);\r
+ matcher.knnMatchDownload(train_idx_, distance_, pair_matches);\r
+ for (size_t i = 0; i < pair_matches.size(); ++i)\r
+ {\r
+ if (pair_matches[i].size() < 2)\r
+ continue;\r
+ const DMatch& m0 = pair_matches[i][0];\r
+ const DMatch& m1 = pair_matches[i][1];\r
+ if (m0.distance < (1.f - match_conf_) * m1.distance)\r
+ if (matches.find(make_pair(m0.trainIdx, m0.queryIdx)) == matches.end())\r
+ matches_info.matches.push_back(DMatch(m0.trainIdx, m0.queryIdx, m0.distance));\r
+ }\r
+ }\r
+\r
+} // anonymous namespace\r
+\r
+\r
+BestOf2NearestMatcher::BestOf2NearestMatcher(bool try_use_gpu, float match_conf, int num_matches_thresh1, int num_matches_thresh2)\r
+{\r
+ if (try_use_gpu && getCudaEnabledDeviceCount() > 0)\r
+ impl_ = new GpuMatcher(match_conf);\r
+ else\r
+ impl_ = new CpuMatcher(match_conf);\r
+\r
+ is_thread_safe_ = impl_->isThreadSafe();\r
+ num_matches_thresh1_ = num_matches_thresh1;\r
+ num_matches_thresh2_ = num_matches_thresh2;\r
+}\r
+\r
+\r
+void BestOf2NearestMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2,\r
+ MatchesInfo &matches_info)\r
+{\r
+ (*impl_)(features1, features2, matches_info);\r
+\r
+ //Mat out;\r
+ //drawMatches(features1.img, features1.keypoints, features2.img, features2.keypoints, matches_info.matches, out);\r
+ //stringstream ss;\r
+ //ss << features1.img_idx << features2.img_idx << ".png";\r
+ //imwrite(ss.str(), out);\r
+\r
+ // Check if it makes sense to find homography\r
+ if (matches_info.matches.size() < static_cast<size_t>(num_matches_thresh1_))\r
+ return;\r
+\r
+ // Construct point-point correspondences for homography estimation\r
+ Mat src_points(1, matches_info.matches.size(), CV_32FC2);\r
+ Mat dst_points(1, matches_info.matches.size(), CV_32FC2);\r
+ for (size_t i = 0; i < matches_info.matches.size(); ++i)\r
+ {\r
+ const DMatch& m = matches_info.matches[i];\r
+\r
+ Point2f p = features1.keypoints[m.queryIdx].pt;\r
+ p.x -= features1.img_size.width * 0.5f;\r
+ p.y -= features1.img_size.height * 0.5f;\r
+ src_points.at<Point2f>(0, i) = p;\r
+\r
+ p = features2.keypoints[m.trainIdx].pt;\r
+ p.x -= features2.img_size.width * 0.5f;\r
+ p.y -= features2.img_size.height * 0.5f;\r
+ dst_points.at<Point2f>(0, i) = p;\r
+ }\r
+\r
+ // Find pair-wise motion\r
+ matches_info.H = findHomography(src_points, dst_points, matches_info.inliers_mask, CV_RANSAC);\r
+\r
+ // Find number of inliers\r
+ matches_info.num_inliers = 0;\r
+ for (size_t i = 0; i < matches_info.inliers_mask.size(); ++i)\r
+ if (matches_info.inliers_mask[i])\r
+ matches_info.num_inliers++;\r
+\r
+ matches_info.confidence = matches_info.num_inliers / (8 + 0.3*matches_info.matches.size());\r
+\r
+ // Check if we should try to refine motion\r
+ if (matches_info.num_inliers < num_matches_thresh2_)\r
+ return;\r
+\r
+ // Construct point-point correspondences for inliers only\r
+ src_points.create(1, matches_info.num_inliers, CV_32FC2);\r
+ dst_points.create(1, matches_info.num_inliers, CV_32FC2);\r
+ int inlier_idx = 0;\r
+ for (size_t i = 0; i < matches_info.matches.size(); ++i)\r
+ {\r
+ if (!matches_info.inliers_mask[i])\r
+ continue;\r
+\r
+ const DMatch& m = matches_info.matches[i];\r
+\r
+ Point2f p = features1.keypoints[m.queryIdx].pt;\r
+ p.x -= features1.img_size.width * 0.5f;\r
+ p.y -= features1.img_size.height * 0.5f;\r
+ src_points.at<Point2f>(0, inlier_idx) = p;\r
+\r
+ p = features2.keypoints[m.trainIdx].pt;\r
+ p.x -= features2.img_size.width * 0.5f;\r
+ p.y -= features2.img_size.height * 0.5f;\r
+ dst_points.at<Point2f>(0, inlier_idx) = p;\r
+\r
+ inlier_idx++;\r
+ }\r
+\r
+ // Rerun motion estimation on inliers only\r
+ matches_info.H = findHomography(src_points, dst_points, CV_RANSAC);\r
+}\r