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
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
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
}\r
}\r
\r
-PERF_TEST( stitch2, b12 )\r
+PERF_TEST_P( stitch, b12, testing::Values("surf", "orb"))\r
{\r
Mat pano;\r
\r
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
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
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
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
}\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
}\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
"\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"
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;
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]));
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);
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())
{