fixed error in gcgraph which led to problems in opencv_stitching GC seam finder,...
authorAlexey Spizhevoy <no@email>
Thu, 2 Jun 2011 12:13:06 +0000 (12:13 +0000)
committerAlexey Spizhevoy <no@email>
Thu, 2 Jun 2011 12:13:06 +0000 (12:13 +0000)
modules/imgproc/src/gcgraph.hpp
modules/stitching/main.cpp
modules/stitching/matchers.cpp
modules/stitching/precomp.hpp

index a6bfff2..7f0f501 100644 (file)
@@ -97,7 +97,7 @@ template <class TWeight>
 void GCGraph<TWeight>::create( unsigned int vtxCount, unsigned int edgeCount )
 {
     vtcs.reserve( vtxCount );
-    edges.reserve( edgeCount );
+    edges.reserve( edgeCount + 2 );
     flow = 0;
 }
 
@@ -118,6 +118,9 @@ void GCGraph<TWeight>::addEdges( int i, int j, TWeight w, TWeight revw )
     CV_Assert( w>=0 && revw>=0 );
     CV_Assert( i != j );
 
+    if( !edges.size() )
+        edges.resize( 2 );
+
     Edge fromI, toI;
     fromI.dst = j;
     fromI.next = vtcs[i].first;
index 90d0528..fe952e6 100644 (file)
@@ -71,7 +71,7 @@ void printUsage()
         "  --try_gpu (yes|no)\n"\r
         "      Try to use GPU. The default value is 'no'. All default values\n"\r
         "      are for CPU mode.\n"\r
-        "\nMotion Estimation:\n"\r
+        "\nMotion Estimation Flags:\n"\r
         "  --work_megapix <float>\n"\r
         "      Resolution for image registration step. The default is 0.6 Mpx.\n"\r
         "  --match_conf <float>\n"\r
@@ -83,7 +83,7 @@ void printUsage()
         "      Bundle adjustment cost function. The default is 'focal_ray'.\n"\r
         "  --wave_correct (no|yes)\n"\r
         "      Perform wave effect correction. The default is 'yes'.\n"\r
-        "\nCompositing:\n"\r
+        "\nCompositing Flags:\n"\r
         "  --warp (plane|cylindrical|spherical)\n" \r
         "      Warp surface type. The default is 'spherical'.\n"\r
         "  --seam_megapix <float>\n"\r
index 3d0639e..07c8fb9 100644 (file)
 // 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
index 1223f92..c0ce981 100644 (file)
@@ -49,6 +49,7 @@
 #include <vector>\r
 #include <algorithm>\r
 #include <utility>\r
+#include <set>\r
 #include "opencv2/core/core.hpp"\r
 #include "opencv2/core/internal.hpp"\r
 #include "opencv2/imgproc/imgproc.hpp"\r