From f299bde3a95ad84edb614da7712826dd6790e3ab Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Wed, 19 Oct 2011 10:48:45 +0000 Subject: [PATCH] Added ORB features finder into stitching module --- .../include/opencv2/stitching/detail/matchers.hpp | 11 ++++ modules/stitching/perf/perf_stich.cpp | 30 +++++++-- modules/stitching/src/matchers.cpp | 33 +++++++++- samples/cpp/stitching_detailed.cpp | 74 ++++++++++++++-------- 4 files changed, 112 insertions(+), 36 deletions(-) diff --git a/modules/stitching/include/opencv2/stitching/detail/matchers.hpp b/modules/stitching/include/opencv2/stitching/detail/matchers.hpp index 70769d5..665de73 100644 --- a/modules/stitching/include/opencv2/stitching/detail/matchers.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/matchers.hpp @@ -89,6 +89,17 @@ private: Ptr surf; }; +class CV_EXPORTS OrbFeaturesFinder : public FeaturesFinder +{ +public: + OrbFeaturesFinder(size_t n_features = 1500, const ORB::CommonParams & detector_params = ORB::CommonParams(1.3, 5)); + +private: + void find(const Mat &image, ImageFeatures &features); + + Ptr orb; +}; + #ifndef ANDROID class CV_EXPORTS SurfFeaturesFinderGpu : public FeaturesFinder diff --git a/modules/stitching/perf/perf_stich.cpp b/modules/stitching/perf/perf_stich.cpp index 5b65c89..c31ce27 100644 --- a/modules/stitching/perf/perf_stich.cpp +++ b/modules/stitching/perf/perf_stich.cpp @@ -6,11 +6,9 @@ using namespace std; using namespace cv; using namespace perf; +typedef TestBaseWithParam stitch; -/* -// Stitcher::Status Stitcher::stitch(InputArray imgs, OutputArray pano) -*/ -PERF_TEST( stitch3, a123 ) +PERF_TEST_P( stitch, a123, testing::Values("surf", "orb")) { Mat pano; @@ -20,12 +18,21 @@ PERF_TEST( stitch3, a123 ) imgs.push_back( imread( getDataPath("stitching/a3.jpg") ) ); Stitcher::Status status; + Ptr featuresFinder = GetParam() == "orb" + ? (detail::FeaturesFinder*)new detail::OrbFeaturesFinder() + : (detail::FeaturesFinder*)new detail::SurfFeaturesFinder(); - declare.time(30 * 20); + Ptr featuresMatcher = GetParam() == "orb" + ? new detail::BestOf2NearestMatcher(false, 0.3f) + : new detail::BestOf2NearestMatcher(false, 0.65f); + + declare.time(30 * 20).iterations(50); while(next()) { Stitcher stitcher = Stitcher::createDefault(); + stitcher.setFeaturesFinder(featuresFinder); + stitcher.setFeaturesMatcher(featuresMatcher); startTimer(); status = stitcher.stitch(imgs, pano); @@ -33,7 +40,7 @@ PERF_TEST( stitch3, a123 ) } } -PERF_TEST( stitch2, b12 ) +PERF_TEST_P( stitch, b12, testing::Values("surf", "orb")) { Mat pano; @@ -42,12 +49,21 @@ PERF_TEST( stitch2, b12 ) imgs.push_back( imread( getDataPath("stitching/b2.jpg") ) ); Stitcher::Status status; + Ptr featuresFinder = GetParam() == "orb" + ? (detail::FeaturesFinder*)new detail::OrbFeaturesFinder() + : (detail::FeaturesFinder*)new detail::SurfFeaturesFinder(); + + Ptr featuresMatcher = GetParam() == "orb" + ? new detail::BestOf2NearestMatcher(false, 0.3f) + : new detail::BestOf2NearestMatcher(false, 0.65f); - declare.time(30 * 20); + declare.time(30 * 20).iterations(50); while(next()) { Stitcher stitcher = Stitcher::createDefault(); + stitcher.setFeaturesFinder(featuresFinder); + stitcher.setFeaturesMatcher(featuresMatcher); startTimer(); status = stitcher.stitch(imgs, pano); diff --git a/modules/stitching/src/matchers.cpp b/modules/stitching/src/matchers.cpp index 9cc841d..b1a2f84 100644 --- a/modules/stitching/src/matchers.cpp +++ b/modules/stitching/src/matchers.cpp @@ -148,7 +148,20 @@ private: void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info) { matches_info.matches.clear(); - FlannBasedMatcher matcher; + + CV_Assert(features1.descriptors.type() == features2.descriptors.type()); + CV_Assert(features2.descriptors.depth() == CV_8U || features2.descriptors.depth() == CV_32F); + + Ptr indexParams = new flann::KDTreeIndexParams(); + Ptr searchParams = new flann::SearchParams(); + + if (features2.descriptors.depth() == CV_8U) + { + indexParams->setAlgorithm(cvflann::FLANN_INDEX_LSH); + searchParams->setAlgorithm(cvflann::FLANN_INDEX_LSH); + } + + FlannBasedMatcher matcher(indexParams, searchParams); vector< vector > pair_matches; MatchesSet matches; @@ -166,6 +179,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat matches.insert(make_pair(m0.queryIdx, m0.trainIdx)); } } + LOG("\n1->2 matches: " << matches_info.matches.size() << endl); // Find 2->1 matches pair_matches.clear(); @@ -180,6 +194,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat if (matches.find(make_pair(m0.trainIdx, m0.queryIdx)) == matches.end()) matches_info.matches.push_back(DMatch(m0.trainIdx, m0.queryIdx, m0.distance)); } + LOG("1->2 & 2->1 matches: " << matches_info.matches.size() << endl); } #ifndef ANDROID @@ -304,11 +319,10 @@ SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int } } - void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features) { Mat gray_image; - CV_Assert(image.depth() == CV_8U); + CV_Assert(image.type() == CV_8UC3); cvtColor(image, gray_image, CV_BGR2GRAY); if (surf == 0) { @@ -323,6 +337,19 @@ void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features) } } +OrbFeaturesFinder::OrbFeaturesFinder(size_t n_features, const ORB::CommonParams & detector_params) +{ + orb = new ORB(n_features, detector_params); +} + +void OrbFeaturesFinder::find(const Mat &image, ImageFeatures &features) +{ + Mat gray_image; + CV_Assert(image.type() == CV_8UC3); + cvtColor(image, gray_image, CV_BGR2GRAY); + + (*orb)(gray_image, Mat(), features.keypoints, features.descriptors); +} #ifndef ANDROID SurfFeaturesFinderGpu::SurfFeaturesFinderGpu(double hess_thresh, int num_octaves, int num_layers, diff --git a/samples/cpp/stitching_detailed.cpp b/samples/cpp/stitching_detailed.cpp index 6e10007..d6fd68f 100644 --- a/samples/cpp/stitching_detailed.cpp +++ b/samples/cpp/stitching_detailed.cpp @@ -74,8 +74,10 @@ void printUsage() "\nMotion Estimation Flags:\n" " --work_megapix \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 \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 \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(atof(argv[i + 1])); @@ -334,12 +344,24 @@ int main(int argc, char* argv[]) int64 t = getTickCount(); Ptr 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 features(num_images); @@ -548,27 +570,27 @@ int main(int argc, char* argv[]) compensator->feed(corners, images_warped, masks_warped); Ptr seam_finder; - 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_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()) { -- 2.7.4