Added ORB features finder into stitching module
authorAndrey Kamaev <no@email>
Wed, 19 Oct 2011 10:48:45 +0000 (10:48 +0000)
committerAndrey Kamaev <no@email>
Wed, 19 Oct 2011 10:48:45 +0000 (10:48 +0000)
modules/stitching/include/opencv2/stitching/detail/matchers.hpp
modules/stitching/perf/perf_stich.cpp
modules/stitching/src/matchers.cpp
samples/cpp/stitching_detailed.cpp

index 70769d5..665de73 100644 (file)
@@ -89,6 +89,17 @@ private:
     Ptr<SURF> surf;\r
 };\r
 \r
+class CV_EXPORTS OrbFeaturesFinder : public FeaturesFinder\r
+{\r
+public:\r
+    OrbFeaturesFinder(size_t n_features = 1500, const ORB::CommonParams & detector_params = ORB::CommonParams(1.3, 5));\r
+\r
+private:\r
+    void find(const Mat &image, ImageFeatures &features);\r
+\r
+    Ptr<ORB> orb;\r
+};\r
+\r
 \r
 #ifndef ANDROID\r
 class CV_EXPORTS SurfFeaturesFinderGpu : public FeaturesFinder\r
index 5b65c89..c31ce27 100644 (file)
@@ -6,11 +6,9 @@ using namespace std;
 using namespace cv;\r
 using namespace perf;\r
 \r
+typedef TestBaseWithParam<String> stitch;\r
 \r
-/*\r
-// Stitcher::Status Stitcher::stitch(InputArray imgs, OutputArray pano)\r
-*/\r
-PERF_TEST( stitch3, a123 )\r
+PERF_TEST_P( stitch, a123, testing::Values("surf", "orb"))\r
 {\r
     Mat pano;\r
     \r
@@ -20,12 +18,21 @@ PERF_TEST( stitch3, a123 )
     imgs.push_back( imread( getDataPath("stitching/a3.jpg") ) );\r
 \r
     Stitcher::Status status;\r
+    Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"\r
+            ? (detail::FeaturesFinder*)new detail::OrbFeaturesFinder()\r
+            : (detail::FeaturesFinder*)new detail::SurfFeaturesFinder();\r
 \r
-    declare.time(30 * 20);\r
+    Ptr<detail::FeaturesMatcher> featuresMatcher = GetParam() == "orb"\r
+            ? new detail::BestOf2NearestMatcher(false, 0.3f)\r
+            : new detail::BestOf2NearestMatcher(false, 0.65f);\r
+\r
+    declare.time(30 * 20).iterations(50);\r
 \r
     while(next())\r
     {\r
         Stitcher stitcher = Stitcher::createDefault();\r
+        stitcher.setFeaturesFinder(featuresFinder);\r
+        stitcher.setFeaturesMatcher(featuresMatcher);\r
 \r
         startTimer();\r
         status = stitcher.stitch(imgs, pano);\r
@@ -33,7 +40,7 @@ PERF_TEST( stitch3, a123 )
     }\r
 }\r
 \r
-PERF_TEST( stitch2, b12 )\r
+PERF_TEST_P( stitch, b12, testing::Values("surf", "orb"))\r
 {\r
     Mat pano;\r
     \r
@@ -42,12 +49,21 @@ PERF_TEST( stitch2, b12 )
     imgs.push_back( imread( getDataPath("stitching/b2.jpg") ) );\r
 \r
     Stitcher::Status status;\r
+    Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"\r
+            ? (detail::FeaturesFinder*)new detail::OrbFeaturesFinder()\r
+            : (detail::FeaturesFinder*)new detail::SurfFeaturesFinder();\r
+\r
+    Ptr<detail::FeaturesMatcher> featuresMatcher = GetParam() == "orb"\r
+            ? new detail::BestOf2NearestMatcher(false, 0.3f)\r
+            : new detail::BestOf2NearestMatcher(false, 0.65f);\r
 \r
-    declare.time(30 * 20);\r
+    declare.time(30 * 20).iterations(50);\r
 \r
     while(next())\r
     {\r
         Stitcher stitcher = Stitcher::createDefault();\r
+        stitcher.setFeaturesFinder(featuresFinder);\r
+        stitcher.setFeaturesMatcher(featuresMatcher);\r
 \r
         startTimer();\r
         status = stitcher.stitch(imgs, pano);\r
index 9cc841d..b1a2f84 100644 (file)
@@ -148,7 +148,20 @@ private:
 void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)\r
 {\r
     matches_info.matches.clear();\r
-    FlannBasedMatcher matcher;\r
+\r
+    CV_Assert(features1.descriptors.type() == features2.descriptors.type());\r
+    CV_Assert(features2.descriptors.depth() == CV_8U || features2.descriptors.depth() == CV_32F);\r
+\r
+    Ptr<flann::IndexParams> indexParams = new flann::KDTreeIndexParams();\r
+    Ptr<flann::SearchParams> searchParams = new flann::SearchParams();\r
+\r
+    if (features2.descriptors.depth() == CV_8U)\r
+    {\r
+        indexParams->setAlgorithm(cvflann::FLANN_INDEX_LSH);\r
+        searchParams->setAlgorithm(cvflann::FLANN_INDEX_LSH);\r
+    }\r
+\r
+    FlannBasedMatcher matcher(indexParams, searchParams);\r
     vector< vector<DMatch> > pair_matches;\r
     MatchesSet matches;\r
 \r
@@ -166,6 +179,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
             matches.insert(make_pair(m0.queryIdx, m0.trainIdx));\r
         }\r
     }\r
+    LOG("\n1->2 matches: " << matches_info.matches.size() << endl);\r
 \r
     // Find 2->1 matches\r
     pair_matches.clear();\r
@@ -180,6 +194,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
             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
+    LOG("1->2 & 2->1 matches: " << matches_info.matches.size() << endl);\r
 }\r
 \r
 #ifndef ANDROID\r
@@ -304,11 +319,10 @@ SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int
     }\r
 }\r
 \r
-\r
 void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)\r
 {\r
     Mat gray_image;\r
-    CV_Assert(image.depth() == CV_8U);\r
+    CV_Assert(image.type() == CV_8UC3);\r
     cvtColor(image, gray_image, CV_BGR2GRAY);\r
     if (surf == 0)\r
     {\r
@@ -323,6 +337,19 @@ void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
     }\r
 }\r
 \r
+OrbFeaturesFinder::OrbFeaturesFinder(size_t n_features, const ORB::CommonParams & detector_params)\r
+{\r
+    orb = new ORB(n_features, detector_params);\r
+}\r
+\r
+void OrbFeaturesFinder::find(const Mat &image, ImageFeatures &features)\r
+{\r
+    Mat gray_image;\r
+    CV_Assert(image.type() == CV_8UC3);\r
+    cvtColor(image, gray_image, CV_BGR2GRAY);\r
+\r
+    (*orb)(gray_image, Mat(), features.keypoints, features.descriptors);\r
+}\r
 \r
 #ifndef ANDROID\r
 SurfFeaturesFinderGpu::SurfFeaturesFinderGpu(double hess_thresh, int num_octaves, int num_layers,\r
index 6e10007..d6fd68f 100644 (file)
@@ -74,8 +74,10 @@ void printUsage()
         "\nMotion Estimation Flags:\n"
         "  --work_megapix <float>\n"
         "      Resolution for image registration step. The default is 0.6 Mpx.\n"
+        "  --features (surf|orb)\n"
+        "      Type of features used for images matching. The default is surf.\n"
         "  --match_conf <float>\n"
-        "      Confidence for feature matching step. The default is 0.65.\n"
+        "      Confidence for feature matching step. The default is 0.65 for surf and 0.3 for orb.\n"
         "  --conf_thresh <float>\n"
         "      Threshold for two images are from the same panorama confidence.\n"
         "      The default is 1.0.\n"
@@ -123,6 +125,7 @@ double work_megapix = 0.6;
 double seam_megapix = 0.1;
 double compose_megapix = -1;
 float conf_thresh = 1.f;
+string features = "surf";
 string ba_cost_func = "ray";
 string ba_refine_mask = "xxxxx";
 bool do_wave_correct = true;
@@ -188,6 +191,13 @@ int parseCmdArgs(int argc, char** argv)
             result_name = argv[i + 1];
             i++;
         }
+        else if (string(argv[i]) == "--features")
+        {
+            features = argv[i + 1];
+            if (features == "orb")
+                match_conf = 0.3f;
+            i++;
+        }
         else if (string(argv[i]) == "--match_conf")
         {
             match_conf = static_cast<float>(atof(argv[i + 1]));
@@ -334,12 +344,24 @@ int main(int argc, char* argv[])
     int64 t = getTickCount();
 
     Ptr<FeaturesFinder> finder;
+    if (features == "surf")
+    {
 #ifndef ANDROID
-    if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)
-        finder = new SurfFeaturesFinderGpu();
-    else
+        if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)
+            finder = new SurfFeaturesFinderGpu();
+        else
 #endif
-        finder = new SurfFeaturesFinder();
+            finder = new SurfFeaturesFinder();
+    }
+    else if (features == "orb")
+    {
+        finder = new OrbFeaturesFinder();
+    }
+    else
+    {
+        cout << "Unknown 2D features type: '" << features << "'.\n";
+        return -1;
+    }
 
     Mat full_img, img;
     vector<ImageFeatures> features(num_images);
@@ -548,27 +570,27 @@ int main(int argc, char* argv[])
     compensator->feed(corners, images_warped, masks_warped);
 
     Ptr<SeamFinder> seam_finder;
-    if (seam_find_type == "no")\r
-        seam_finder = new detail::NoSeamFinder();\r
-    else if (seam_find_type == "voronoi")\r
-        seam_finder = new detail::VoronoiSeamFinder();\r
-    else if (seam_find_type == "gc_color")\r
-    {\r
-#ifndef ANDROID\r
-        if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)\r
-            seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR);\r
-        else\r
-#endif\r
-            seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR);\r
-    }\r
-    else if (seam_find_type == "gc_colorgrad")\r
-    {\r
-#ifndef ANDROID\r
-        if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)\r
-            seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR_GRAD);\r
-        else\r
-#endif\r
-            seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR_GRAD);\r
+    if (seam_find_type == "no")
+        seam_finder = new detail::NoSeamFinder();
+    else if (seam_find_type == "voronoi")
+        seam_finder = new detail::VoronoiSeamFinder();
+    else if (seam_find_type == "gc_color")
+    {
+#ifndef ANDROID
+        if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)
+            seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR);
+        else
+#endif
+            seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR);
+    }
+    else if (seam_find_type == "gc_colorgrad")
+    {
+#ifndef ANDROID
+        if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)
+            seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR_GRAD);
+        else
+#endif
+            seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR_GRAD);
     }
     if (seam_finder.empty())
     {