Commit f299bde3 authored by Andrey Kamaev's avatar Andrey Kamaev

Added ORB features finder into stitching module

parent 40ee754e
...@@ -89,6 +89,17 @@ private: ...@@ -89,6 +89,17 @@ private:
Ptr<SURF> surf; Ptr<SURF> 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> orb;
};
#ifndef ANDROID #ifndef ANDROID
class CV_EXPORTS SurfFeaturesFinderGpu : public FeaturesFinder class CV_EXPORTS SurfFeaturesFinderGpu : public FeaturesFinder
......
...@@ -6,11 +6,9 @@ using namespace std; ...@@ -6,11 +6,9 @@ using namespace std;
using namespace cv; using namespace cv;
using namespace perf; using namespace perf;
typedef TestBaseWithParam<String> stitch;
/* PERF_TEST_P( stitch, a123, testing::Values("surf", "orb"))
// Stitcher::Status Stitcher::stitch(InputArray imgs, OutputArray pano)
*/
PERF_TEST( stitch3, a123 )
{ {
Mat pano; Mat pano;
...@@ -20,12 +18,21 @@ PERF_TEST( stitch3, a123 ) ...@@ -20,12 +18,21 @@ PERF_TEST( stitch3, a123 )
imgs.push_back( imread( getDataPath("stitching/a3.jpg") ) ); imgs.push_back( imread( getDataPath("stitching/a3.jpg") ) );
Stitcher::Status status; Stitcher::Status status;
Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"
? (detail::FeaturesFinder*)new detail::OrbFeaturesFinder()
: (detail::FeaturesFinder*)new detail::SurfFeaturesFinder();
declare.time(30 * 20); Ptr<detail::FeaturesMatcher> featuresMatcher = GetParam() == "orb"
? new detail::BestOf2NearestMatcher(false, 0.3f)
: new detail::BestOf2NearestMatcher(false, 0.65f);
declare.time(30 * 20).iterations(50);
while(next()) while(next())
{ {
Stitcher stitcher = Stitcher::createDefault(); Stitcher stitcher = Stitcher::createDefault();
stitcher.setFeaturesFinder(featuresFinder);
stitcher.setFeaturesMatcher(featuresMatcher);
startTimer(); startTimer();
status = stitcher.stitch(imgs, pano); status = stitcher.stitch(imgs, pano);
...@@ -33,7 +40,7 @@ PERF_TEST( stitch3, a123 ) ...@@ -33,7 +40,7 @@ PERF_TEST( stitch3, a123 )
} }
} }
PERF_TEST( stitch2, b12 ) PERF_TEST_P( stitch, b12, testing::Values("surf", "orb"))
{ {
Mat pano; Mat pano;
...@@ -42,12 +49,21 @@ PERF_TEST( stitch2, b12 ) ...@@ -42,12 +49,21 @@ PERF_TEST( stitch2, b12 )
imgs.push_back( imread( getDataPath("stitching/b2.jpg") ) ); imgs.push_back( imread( getDataPath("stitching/b2.jpg") ) );
Stitcher::Status status; Stitcher::Status status;
Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"
? (detail::FeaturesFinder*)new detail::OrbFeaturesFinder()
: (detail::FeaturesFinder*)new detail::SurfFeaturesFinder();
Ptr<detail::FeaturesMatcher> 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()) while(next())
{ {
Stitcher stitcher = Stitcher::createDefault(); Stitcher stitcher = Stitcher::createDefault();
stitcher.setFeaturesFinder(featuresFinder);
stitcher.setFeaturesMatcher(featuresMatcher);
startTimer(); startTimer();
status = stitcher.stitch(imgs, pano); status = stitcher.stitch(imgs, pano);
......
...@@ -148,7 +148,20 @@ private: ...@@ -148,7 +148,20 @@ private:
void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info) void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)
{ {
matches_info.matches.clear(); 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<flann::IndexParams> indexParams = new flann::KDTreeIndexParams();
Ptr<flann::SearchParams> 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<DMatch> > pair_matches; vector< vector<DMatch> > pair_matches;
MatchesSet matches; MatchesSet matches;
...@@ -166,6 +179,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat ...@@ -166,6 +179,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
matches.insert(make_pair(m0.queryIdx, m0.trainIdx)); matches.insert(make_pair(m0.queryIdx, m0.trainIdx));
} }
} }
LOG("\n1->2 matches: " << matches_info.matches.size() << endl);
// Find 2->1 matches // Find 2->1 matches
pair_matches.clear(); pair_matches.clear();
...@@ -180,6 +194,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat ...@@ -180,6 +194,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
if (matches.find(make_pair(m0.trainIdx, m0.queryIdx)) == matches.end()) if (matches.find(make_pair(m0.trainIdx, m0.queryIdx)) == matches.end())
matches_info.matches.push_back(DMatch(m0.trainIdx, m0.queryIdx, m0.distance)); 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 #ifndef ANDROID
...@@ -304,11 +319,10 @@ SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int ...@@ -304,11 +319,10 @@ SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int
} }
} }
void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features) void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
{ {
Mat gray_image; Mat gray_image;
CV_Assert(image.depth() == CV_8U); CV_Assert(image.type() == CV_8UC3);
cvtColor(image, gray_image, CV_BGR2GRAY); cvtColor(image, gray_image, CV_BGR2GRAY);
if (surf == 0) if (surf == 0)
{ {
...@@ -323,6 +337,19 @@ void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features) ...@@ -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 #ifndef ANDROID
SurfFeaturesFinderGpu::SurfFeaturesFinderGpu(double hess_thresh, int num_octaves, int num_layers, SurfFeaturesFinderGpu::SurfFeaturesFinderGpu(double hess_thresh, int num_octaves, int num_layers,
......
...@@ -74,8 +74,10 @@ void printUsage() ...@@ -74,8 +74,10 @@ void printUsage()
"\nMotion Estimation Flags:\n" "\nMotion Estimation Flags:\n"
" --work_megapix <float>\n" " --work_megapix <float>\n"
" Resolution for image registration step. The default is 0.6 Mpx.\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" " --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" " --conf_thresh <float>\n"
" Threshold for two images are from the same panorama confidence.\n" " Threshold for two images are from the same panorama confidence.\n"
" The default is 1.0.\n" " The default is 1.0.\n"
...@@ -123,6 +125,7 @@ double work_megapix = 0.6; ...@@ -123,6 +125,7 @@ double work_megapix = 0.6;
double seam_megapix = 0.1; double seam_megapix = 0.1;
double compose_megapix = -1; double compose_megapix = -1;
float conf_thresh = 1.f; float conf_thresh = 1.f;
string features = "surf";
string ba_cost_func = "ray"; string ba_cost_func = "ray";
string ba_refine_mask = "xxxxx"; string ba_refine_mask = "xxxxx";
bool do_wave_correct = true; bool do_wave_correct = true;
...@@ -188,6 +191,13 @@ int parseCmdArgs(int argc, char** argv) ...@@ -188,6 +191,13 @@ int parseCmdArgs(int argc, char** argv)
result_name = argv[i + 1]; result_name = argv[i + 1];
i++; 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") else if (string(argv[i]) == "--match_conf")
{ {
match_conf = static_cast<float>(atof(argv[i + 1])); match_conf = static_cast<float>(atof(argv[i + 1]));
...@@ -334,12 +344,24 @@ int main(int argc, char* argv[]) ...@@ -334,12 +344,24 @@ int main(int argc, char* argv[])
int64 t = getTickCount(); int64 t = getTickCount();
Ptr<FeaturesFinder> finder; Ptr<FeaturesFinder> finder;
if (features == "surf")
{
#ifndef ANDROID #ifndef ANDROID
if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0) if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)
finder = new SurfFeaturesFinderGpu(); finder = new SurfFeaturesFinderGpu();
else else
#endif #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; Mat full_img, img;
vector<ImageFeatures> features(num_images); vector<ImageFeatures> features(num_images);
...@@ -548,27 +570,27 @@ int main(int argc, char* argv[]) ...@@ -548,27 +570,27 @@ int main(int argc, char* argv[])
compensator->feed(corners, images_warped, masks_warped); compensator->feed(corners, images_warped, masks_warped);
Ptr<SeamFinder> seam_finder; Ptr<SeamFinder> seam_finder;
if (seam_find_type == "no") if (seam_find_type == "no")
seam_finder = new detail::NoSeamFinder(); seam_finder = new detail::NoSeamFinder();
else if (seam_find_type == "voronoi") else if (seam_find_type == "voronoi")
seam_finder = new detail::VoronoiSeamFinder(); seam_finder = new detail::VoronoiSeamFinder();
else if (seam_find_type == "gc_color") else if (seam_find_type == "gc_color")
{ {
#ifndef ANDROID #ifndef ANDROID
if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0) if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)
seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR); seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR);
else else
#endif #endif
seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR); seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR);
} }
else if (seam_find_type == "gc_colorgrad") else if (seam_find_type == "gc_colorgrad")
{ {
#ifndef ANDROID #ifndef ANDROID
if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0) if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0)
seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR_GRAD); seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR_GRAD);
else else
#endif #endif
seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR_GRAD); seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR_GRAD);
} }
if (seam_finder.empty()) if (seam_finder.empty())
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment