Added support of vertical straightening into stitching

pull/13383/head
Alexey Spizhevoy 14 years ago
parent 48dec9c03a
commit 16f5c67914
  1. 8
      modules/stitching/include/opencv2/stitching/detail/motion_estimators.hpp
  2. 1
      modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp
  3. 1
      modules/stitching/include/opencv2/stitching/detail/warpers.hpp
  4. 4
      modules/stitching/include/opencv2/stitching/stitcher.hpp
  5. 34
      modules/stitching/src/motion_estimators.cpp
  6. 3
      modules/stitching/src/stitcher.cpp
  7. 25
      samples/cpp/stitching_detailed.cpp

@ -170,7 +170,13 @@ private:
}; };
void CV_EXPORTS waveCorrect(std::vector<Mat> &rmats); enum CV_EXPORTS WaveCorrectKind
{
WAVE_CORRECT_HORIZ,
WAVE_CORRECT_VERT
};
void CV_EXPORTS waveCorrect(std::vector<Mat> &rmats, WaveCorrectKind kind);
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

@ -100,6 +100,7 @@ public:
std::vector<Mat> &masks); std::vector<Mat> &masks);
private: private:
// To avoid GCGraph dependency
class Impl; class Impl;
Ptr<Impl> impl_; Ptr<Impl> impl_;
}; };

@ -129,6 +129,7 @@ protected:
void detectResultRoi(Point &dst_tl, Point &dst_br); void detectResultRoi(Point &dst_tl, Point &dst_br);
}; };
#ifndef ANDROID #ifndef ANDROID
class CV_EXPORTS PlaneWarperGpu : public PlaneWarper class CV_EXPORTS PlaneWarperGpu : public PlaneWarper
{ {

@ -96,6 +96,9 @@ public:
void setBundleAdjuster(Ptr<detail::BundleAdjusterBase> bundle_adjuster) void setBundleAdjuster(Ptr<detail::BundleAdjusterBase> bundle_adjuster)
{ bundle_adjuster_ = bundle_adjuster; } { bundle_adjuster_ = bundle_adjuster; }
detail::WaveCorrectKind waveCorrectKind() const { return wave_correct_kind_; }
void setWaveCorrectKind(detail::WaveCorrectKind kind) { wave_correct_kind_ = kind; }
Ptr<WarperCreator> warper() { return warper_; } Ptr<WarperCreator> warper() { return warper_; }
const Ptr<WarperCreator> warper() const { return warper_; } const Ptr<WarperCreator> warper() const { return warper_; }
void setWarper(Ptr<WarperCreator> warper) { warper_ = warper; } void setWarper(Ptr<WarperCreator> warper) { warper_ = warper; }
@ -124,6 +127,7 @@ private:
Ptr<detail::FeaturesFinder> features_finder_; Ptr<detail::FeaturesFinder> features_finder_;
Ptr<detail::FeaturesMatcher> features_matcher_; Ptr<detail::FeaturesMatcher> features_matcher_;
Ptr<detail::BundleAdjusterBase> bundle_adjuster_; Ptr<detail::BundleAdjusterBase> bundle_adjuster_;
detail::WaveCorrectKind wave_correct_kind_;
Ptr<WarperCreator> warper_; Ptr<WarperCreator> warper_;
Ptr<detail::ExposureCompensator> exposure_comp_; Ptr<detail::ExposureCompensator> exposure_comp_;
Ptr<detail::SeamFinder> seam_finder_; Ptr<detail::SeamFinder> seam_finder_;

@ -567,7 +567,7 @@ void BundleAdjusterRay::calcJacobian(Mat &jac)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void waveCorrect(vector<Mat> &rmats) void waveCorrect(vector<Mat> &rmats, WaveCorrectKind kind)
{ {
LOGLN("Wave correcting..."); LOGLN("Wave correcting...");
int64 t = getTickCount(); int64 t = getTickCount();
@ -580,7 +580,14 @@ void waveCorrect(vector<Mat> &rmats)
} }
Mat eigen_vals, eigen_vecs; Mat eigen_vals, eigen_vecs;
eigen(moment, eigen_vals, eigen_vecs); eigen(moment, eigen_vals, eigen_vecs);
Mat rg1 = eigen_vecs.row(2).t();
Mat rg1;
if (kind == WAVE_CORRECT_HORIZ)
rg1 = eigen_vecs.row(2).t();
else if (kind == WAVE_CORRECT_VERT)
rg1 = eigen_vecs.row(0).t();
else
CV_Error(CV_StsBadArg, "unsupported kind of wave correction");
Mat img_k = Mat::zeros(3, 1, CV_32F); Mat img_k = Mat::zeros(3, 1, CV_32F);
for (size_t i = 0; i < rmats.size(); ++i) for (size_t i = 0; i < rmats.size(); ++i)
@ -590,6 +597,29 @@ void waveCorrect(vector<Mat> &rmats)
Mat rg2 = rg0.cross(rg1); Mat rg2 = rg0.cross(rg1);
double conf = 0;
if (kind == WAVE_CORRECT_HORIZ)
{
for (size_t i = 0; i < rmats.size(); ++i)
conf += rg0.dot(rmats[i].col(0));
if (conf < 0)
{
rg0 *= -1;
rg1 *= -1;
}
}
else if (kind == WAVE_CORRECT_VERT)
{
for (size_t i = 0; i < rmats.size(); ++i)
conf -= rg1.dot(rmats[i].col(0));
cout << conf << endl;
if (conf < 0)
{
rg0 *= -1;
rg1 *= -1;
}
}
Mat R = Mat::zeros(3, 3, CV_32F); Mat R = Mat::zeros(3, 3, CV_32F);
Mat tmp = R.row(0); Mat tmp = R.row(0);
Mat(rg0.t()).copyTo(tmp); Mat(rg0.t()).copyTo(tmp);

@ -56,6 +56,7 @@ Stitcher Stitcher::createDefault(bool try_use_gpu)
stitcher.setHorizontalStrightening(true); stitcher.setHorizontalStrightening(true);
stitcher.setFeaturesMatcher(new detail::BestOf2NearestMatcher(try_use_gpu)); stitcher.setFeaturesMatcher(new detail::BestOf2NearestMatcher(try_use_gpu));
stitcher.setBundleAdjuster(new detail::BundleAdjusterRay()); stitcher.setBundleAdjuster(new detail::BundleAdjusterRay());
stitcher.setWaveCorrectKind(detail::WAVE_CORRECT_HORIZ);
#ifndef ANDROID #ifndef ANDROID
if (try_use_gpu && gpu::getCudaEnabledDeviceCount() > 0) if (try_use_gpu && gpu::getCudaEnabledDeviceCount() > 0)
@ -208,7 +209,7 @@ Stitcher::Status Stitcher::stitch(InputArray imgs_, OutputArray pano_)
vector<Mat> rmats; vector<Mat> rmats;
for (size_t i = 0; i < cameras.size(); ++i) for (size_t i = 0; i < cameras.size(); ++i)
rmats.push_back(cameras[i].R); rmats.push_back(cameras[i].R);
detail::waveCorrect(rmats); detail::waveCorrect(rmats, wave_correct_kind_);
for (size_t i = 0; i < cameras.size(); ++i) for (size_t i = 0; i < cameras.size(); ++i)
cameras[i].R = rmats[i]; cameras[i].R = rmats[i];
} }

@ -88,8 +88,8 @@ void printUsage()
" <fx><skew><ppx><aspect><ppy>. The default mask is 'xxxxx'. If bundle\n" " <fx><skew><ppx><aspect><ppy>. The default mask is 'xxxxx'. If bundle\n"
" adjustment doesn't support estimation of selected parameter then\n" " adjustment doesn't support estimation of selected parameter then\n"
" the respective flag is ignored.\n" " the respective flag is ignored.\n"
" --wave_correct (no|yes)\n" " --wave_correct (no|horiz|vert)\n"
" Perform wave effect correction. The default is 'yes'.\n" " Perform wave effect correction. The default is 'horiz'.\n"
" --save_graph <file_name>\n" " --save_graph <file_name>\n"
" Save matches graph represented in DOT language to <file_name> file.\n" " Save matches graph represented in DOT language to <file_name> file.\n"
" Labels description: Nm is number of matches, Ni is number of inliers,\n" " Labels description: Nm is number of matches, Ni is number of inliers,\n"
@ -125,7 +125,8 @@ double compose_megapix = -1;
float conf_thresh = 1.f; float conf_thresh = 1.f;
string ba_cost_func = "ray"; string ba_cost_func = "ray";
string ba_refine_mask = "xxxxx"; string ba_refine_mask = "xxxxx";
bool wave_correct = true; bool do_wave_correct = true;
WaveCorrectKind wave_correct = detail::WAVE_CORRECT_HORIZ;
bool save_graph = false; bool save_graph = false;
std::string save_graph_to; std::string save_graph_to;
string warp_type = "spherical"; string warp_type = "spherical";
@ -215,9 +216,17 @@ int parseCmdArgs(int argc, char** argv)
else if (string(argv[i]) == "--wave_correct") else if (string(argv[i]) == "--wave_correct")
{ {
if (string(argv[i + 1]) == "no") if (string(argv[i + 1]) == "no")
wave_correct = false; do_wave_correct = false;
else if (string(argv[i + 1]) == "yes") else if (string(argv[i + 1]) == "horiz")
wave_correct = true; {
do_wave_correct = true;
wave_correct = detail::WAVE_CORRECT_HORIZ;
}
else if (string(argv[i + 1]) == "vert")
{
do_wave_correct = true;
wave_correct = detail::WAVE_CORRECT_VERT;
}
else else
{ {
cout << "Bad --wave_correct flag value\n"; cout << "Bad --wave_correct flag value\n";
@ -467,12 +476,12 @@ int main(int argc, char* argv[])
nth_element(focals.begin(), focals.begin() + focals.size()/2, focals.end()); nth_element(focals.begin(), focals.begin() + focals.size()/2, focals.end());
float warped_image_scale = static_cast<float>(focals[focals.size() / 2]); float warped_image_scale = static_cast<float>(focals[focals.size() / 2]);
if (wave_correct) if (do_wave_correct)
{ {
vector<Mat> rmats; vector<Mat> rmats;
for (size_t i = 0; i < cameras.size(); ++i) for (size_t i = 0; i < cameras.size(); ++i)
rmats.push_back(cameras[i].R); rmats.push_back(cameras[i].R);
waveCorrect(rmats); waveCorrect(rmats, wave_correct);
for (size_t i = 0; i < cameras.size(); ++i) for (size_t i = 0; i < cameras.size(); ++i)
cameras[i].R = rmats[i]; cameras[i].R = rmats[i];
} }

Loading…
Cancel
Save