class CV_EXPORTS DeblurerBase
{
public:
- DeblurerBase() : radius_(0), frames_(0), motions_(0) {}
+ DeblurerBase() : radius_(0), frames_(0), motions_(0), blurrinessRates_(0) {}
virtual ~DeblurerBase() {}
virtual void setRadius(int val) { radius_ = val; }
virtual int radius() const { return radius_; }
+ virtual void deblur(int idx, Mat &frame) = 0;
+
+
+ // data from stabilizer
+
virtual void setFrames(const std::vector<Mat> &val) { frames_ = &val; }
virtual const std::vector<Mat>& frames() const { return *frames_; }
virtual void setBlurrinessRates(const std::vector<float> &val) { blurrinessRates_ = &val; }
virtual const std::vector<float>& blurrinessRates() const { return *blurrinessRates_; }
- virtual void deblur(int idx, Mat &frame) = 0;
-
protected:
int radius_;
const std::vector<Mat> *frames_;
#define __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__
#include <vector>
+#include <string>
+#include <fstream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/videostab/optical_flow.hpp"
MotionModel motionModel_;
};
-class CV_EXPORTS EyeMotionEstimator : public GlobalMotionEstimatorBase
+class CV_EXPORTS FromFileMotionReader : public GlobalMotionEstimatorBase
{
public:
- virtual Mat estimate(const Mat &/*frame0*/, const Mat &/*frame1*/)
- {
- return Mat::eye(3, 3, CV_32F);
- }
+ FromFileMotionReader(const std::string &path);
+ virtual Mat estimate(const Mat &frame0, const Mat &frame1);
+
+private:
+ std::ifstream file_;
+};
+
+class CV_EXPORTS ToFileMotionWriter : public GlobalMotionEstimatorBase
+{
+public:
+ ToFileMotionWriter(const std::string &path, Ptr<GlobalMotionEstimatorBase> estimator);
+ virtual Mat estimate(const Mat &frame0, const Mat &frame1);
+
+private:
+ std::ofstream file_;
+ Ptr<GlobalMotionEstimatorBase> estimator_;
};
class CV_EXPORTS PyrLkRobustMotionEstimator : public GlobalMotionEstimatorBase
{
public:
InpainterBase()
- : radius_(0), frames_(0), motions_(0),
+ : radius_(0), motionModel_(UNKNOWN), frames_(0), motions_(0),
stabilizedFrames_(0), stabilizationMotions_(0) {}
virtual ~InpainterBase() {}
virtual void setMotionModel(MotionModel val) { motionModel_ = val; }
virtual MotionModel motionModel() const { return motionModel_; }
+ virtual void inpaint(int idx, Mat &frame, Mat &mask) = 0;
+
+
+ // data from stabilizer
+
virtual void setFrames(const std::vector<Mat> &val) { frames_ = &val; }
virtual const std::vector<Mat>& frames() const { return *frames_; }
virtual void setStabilizationMotions(const std::vector<Mat> &val) { stabilizationMotions_ = &val; }
virtual const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; }
- virtual void inpaint(int idx, Mat &frame, Mat &mask) = 0;
-
protected:
int radius_;
MotionModel motionModel_;
int frameCount_;
bool isPrePassDone_;
+ bool doWobbleSuppression_;
+ std::vector<Mat> motions2_;
Mat suppressedFrame_;
};
#include <vector>
#include "opencv2/core/core.hpp"
#include "opencv2/videostab/global_motion.hpp"
+#include "opencv2/videostab/log.hpp"
namespace cv
{
class CV_EXPORTS WobbleSuppressorBase
{
public:
+ WobbleSuppressorBase();
+
virtual ~WobbleSuppressorBase() {}
- virtual void setFrames(const std::vector<Mat> &val) { frames_ = &val; }
- virtual const std::vector<Mat>& frames() const { return *frames_; }
+ void setMotionEstimator(Ptr<GlobalMotionEstimatorBase> val) { motionEstimator_ = val; }
+ Ptr<GlobalMotionEstimatorBase> motionEstimator() const { return motionEstimator_; }
+
+ virtual void suppress(int idx, const Mat &frame, Mat &result) = 0;
+
+
+ // data from stabilizer
+
+ virtual void setFrameCount(int val) { frameCount_ = val; }
+ virtual int frameCount() const { return frameCount_; }
virtual void setMotions(const std::vector<Mat> &val) { motions_ = &val; }
virtual const std::vector<Mat>& motions() const { return *motions_; }
- virtual void setStabilizedFrames(const std::vector<Mat> &val) { stabilizedFrames_ = &val; }
- virtual const std::vector<Mat>& stabilizedFrames() const { return *stabilizedFrames_; }
+ virtual void setMotions2(const std::vector<Mat> &val) { motions2_ = &val; }
+ virtual const std::vector<Mat>& motions2() const { return *motions2_; }
virtual void setStabilizationMotions(const std::vector<Mat> &val) { stabilizationMotions_ = &val; }
virtual const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; }
- virtual void suppress(int idx, Mat &frame) = 0;
-
protected:
- const std::vector<Mat> *frames_;
+ Ptr<GlobalMotionEstimatorBase> motionEstimator_;
+ int frameCount_;
const std::vector<Mat> *motions_;
- const std::vector<Mat> *stabilizedFrames_;
+ const std::vector<Mat> *motions2_;
const std::vector<Mat> *stabilizationMotions_;
};
class CV_EXPORTS NullWobbleSuppressor : public WobbleSuppressorBase
{
public:
- virtual void suppress(int idx, Mat &result);
+ virtual void suppress(int idx, const Mat &frame, Mat &result);
+};
+
+class CV_EXPORTS MoreAccurateMotionWobbleSuppressor : public WobbleSuppressorBase
+{
+public:
+ virtual void suppress(int idx, const Mat &frame, Mat &result);
};
} // namespace videostab
}
+FromFileMotionReader::FromFileMotionReader(const string &path)
+{
+ file_.open(path.c_str());
+ CV_Assert(file_.is_open());
+}
+
+
+Mat FromFileMotionReader::estimate(const Mat &/*frame0*/, const Mat &/*frame1*/)
+{
+ Mat_<float> M(3, 3);
+ file_ >> M(0,0) >> M(0,1) >> M(0,2)
+ >> M(1,0) >> M(1,1) >> M(1,2)
+ >> M(2,0) >> M(2,1) >> M(2,2);
+ return M;
+}
+
+
+ToFileMotionWriter::ToFileMotionWriter(const string &path, Ptr<GlobalMotionEstimatorBase> estimator)
+{
+ file_.open(path.c_str());
+ CV_Assert(file_.is_open());
+ estimator_ = estimator;
+}
+
+
+Mat ToFileMotionWriter::estimate(const Mat &frame0, const Mat &frame1)
+{
+ Mat_<float> M = estimator_->estimate(frame0, frame1);
+ file_ << M(0,0) << " " << M(0,1) << " " << M(0,2) << " "
+ << M(1,0) << " " << M(1,1) << " " << M(1,2) << " "
+ << M(2,0) << " " << M(2,1) << " " << M(2,2) << endl;
+ return M;
+}
+
+
PyrLkRobustMotionEstimator::PyrLkRobustMotionEstimator()
: ransacParams_(RansacParams::affine2dMotionStd())
{
StabilizerBase::StabilizerBase()
{
- setLog(new NullLog());
+ setLog(new LogToStdout());
setFrameSource(new NullFrameSource());
setMotionEstimator(new PyrLkRobustMotionEstimator());
setDeblurer(new NullDeblurer());
StabilizerBase::reset();
frameCount_ = 0;
isPrePassDone_ = false;
+ doWobbleSuppression_ = false;
+ motions2_.clear();
suppressedFrame_ = Mat();
}
Mat prevFrame, frame;
+ WobbleSuppressorBase *wobbleSuppressor = static_cast<WobbleSuppressorBase*>(wobbleSuppressor_);
+ doWobbleSuppression_ = dynamic_cast<NullWobbleSuppressor*>(wobbleSuppressor) == 0;
+
while (!(frame = frameSource_->nextFrame()).empty())
{
if (frameCount_ > 0)
+ {
motions_.push_back(motionEstimator_->estimate(prevFrame, frame));
+ if (doWobbleSuppression_)
+ {
+ motions2_.push_back(
+ wobbleSuppressor_->motionEstimator()->estimate(prevFrame, frame));
+ }
+ }
else
{
frameSize_ = frame.size();
for (int i = -radius_; i <= 0; ++i)
at(i, frames_) = firstFrame;
- wobbleSuppressor_->setFrames(frames_);
- wobbleSuppressor_->setMotions(motions_);
- wobbleSuppressor_->setStabilizedFrames(stabilizedFrames_);
- wobbleSuppressor_->setStabilizationMotions(stabilizationMotions_);
+ WobbleSuppressorBase *wobbleSuppressor = static_cast<WobbleSuppressorBase*>(wobbleSuppressor_);
+ doWobbleSuppression_ = dynamic_cast<NullWobbleSuppressor*>(wobbleSuppressor) == 0;
+ if (doWobbleSuppression_)
+ {
+ wobbleSuppressor_->setFrameCount(frameCount_);
+ wobbleSuppressor_->setMotions(motions_);
+ wobbleSuppressor_->setMotions2(motions2_);
+ wobbleSuppressor_->setStabilizationMotions(stabilizationMotions_);
+ }
StabilizerBase::setUp(firstFrame);
}
}
-Mat TwoPassStabilizer::postProcessFrame(const Mat &/*frame*/)
+Mat TwoPassStabilizer::postProcessFrame(const Mat &frame)
{
- wobbleSuppressor_->suppress(curStabilizedPos_, suppressedFrame_);
+ wobbleSuppressor_->suppress(curStabilizedPos_, frame, suppressedFrame_);
return StabilizerBase::postProcessFrame(suppressedFrame_);
}
namespace videostab
{
-void NullWobbleSuppressor::suppress(int idx, Mat &result)
+WobbleSuppressorBase::WobbleSuppressorBase()
+ : motions_(0), stabilizationMotions_(0)
{
- result = at(idx, *stabilizedFrames_);
+ PyrLkRobustMotionEstimator *est = new PyrLkRobustMotionEstimator();
+ est->setMotionModel(HOMOGRAPHY);
+ est->setRansacParams(RansacParams::homography2dMotionStd());
+ setMotionEstimator(est);
+}
+
+
+void NullWobbleSuppressor::suppress(int /*idx*/, const Mat &frame, Mat &result)
+{
+ result = frame;
+}
+
+
+void MoreAccurateMotionWobbleSuppressor::suppress(int idx, const Mat &frame, Mat &result)
+{
+ CV_Assert(motions_ && stabilizationMotions_);
+
+ // TODO implement
+ CV_Error(CV_StsNotImplemented, "MoreAccurateMotionWobbleSuppressor");
+
+ result = frame;
}
} // namespace videostab
void saveMotionsIfNecessary();
void printHelp();
-class GlobalMotionReader : public GlobalMotionEstimatorBase
-{
-public:
- GlobalMotionReader(string path)
- {
- ifstream f(path.c_str());
- if (!f.is_open())
- throw runtime_error("can't open motions file: " + path);
- int size; f >> size;
- motions_.resize(size);
- for (int i = 0; i < size; ++i)
- {
- Mat_<float> M(3, 3);
- for (int l = 0; l < 3; ++l)
- for (int s = 0; s < 3; ++s)
- f >> M(l,s);
- motions_[i] = M;
- }
- pos_ = 0;
- }
-
- virtual Mat estimate(const Mat &/*frame0*/, const Mat &/*frame1*/)
- {
- if (pos_ >= motions_.size())
- {
- stringstream text;
- text << "can't load motion between frames " << pos_ << " and " << pos_+1;
- throw runtime_error(text.str());
- }
- return motions_[pos_++];
- }
-
-private:
- vector<Mat> motions_;
- size_t pos_;
-};
-
void run()
{
while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty())
{
nframes++;
- if (!saveMotionsPath.empty())
- saveMotionsIfNecessary();
if (!outputPath.empty())
{
if (!writer.isOpened())
}
-void saveMotionsIfNecessary()
-{
- static bool areMotionsSaved = false;
- if (!areMotionsSaved)
- {
- IFrameSource *frameSource = static_cast<IFrameSource*>(stabilizedFrames);
- TwoPassStabilizer *twoPassStabilizer = dynamic_cast<TwoPassStabilizer*>(frameSource);
- if (twoPassStabilizer)
- {
- ofstream f(saveMotionsPath.c_str());
- const vector<Mat> &motions = twoPassStabilizer->motions();
- f << motions.size() << endl;
- for (size_t i = 0; i < motions.size(); ++i)
- {
- Mat_<float> M = motions[i];
- for (int l = 0, k = 0; l < 3; ++l)
- for (int s = 0; s < 3; ++s, ++k)
- f << M(l,s) << " ";
- f << endl;
- }
- }
- areMotionsSaved = true;
- cout << "motions are saved";
- }
-}
-
-
void printHelp()
{
cout << "OpenCV video stabilizer.\n"
" --color-inpaint-radius=<float_number>\n"
" Set color inpainting radius (for ns and telea options only).\n"
" The default is 2.0\n\n"
+ " --wobble-suppress=(yes|no)\n"
+ " Perform wobble suppression. The default is no.\n\n"
" -o, --output=(no|<file_path>)\n"
" Set output file path explicitely. The default is stabilized.avi.\n"
" --fps=(<int_number>|auto)\n"
"{ | dist-thresh | 5.0 | }"
"{ | color-inpaint | no | }"
"{ | color-inpaint-radius | 2 | }"
+ "{ | wobble-suppress | no | }"
"{ o | output | stabilized.avi | }"
"{ | fps | auto | }"
"{ q | quiet | false | }"
StabilizerBase *stabilizer;
- bool isTwoPass = arg("est-trim") == "yes" || arg("save-motions") != "no";
+ bool isTwoPass =
+ arg("est-trim") == "yes" || arg("wobble-suppress") == "yes";
+
if (isTwoPass)
{
TwoPassStabilizer *twoPassStabilizer = new TwoPassStabilizer();
twoPassStabilizer->setMotionStabilizer(new GaussianMotionFilter(argi("radius")));
else
twoPassStabilizer->setMotionStabilizer(new GaussianMotionFilter(argi("radius"), argf("stdev")));
+ if (arg("wobble-suppress") == "yes")
+ {
+ twoPassStabilizer->setWobbleSuppressor(new MoreAccurateMotionWobbleSuppressor());
+ if (arg("load-motions") != "no")
+ twoPassStabilizer->wobbleSuppressor()->setMotionEstimator(
+ new FromFileMotionReader("motions2." + arg("load-motions")));
+ if (arg("save-motions") != "no")
+ {
+ Ptr<GlobalMotionEstimatorBase> est = twoPassStabilizer->wobbleSuppressor()->motionEstimator();
+ twoPassStabilizer->wobbleSuppressor()->setMotionEstimator(
+ new ToFileMotionWriter("motions2." + arg("save-motions"), est));
+ }
+ }
}
else
{
stabilizer->setMotionEstimator(est_);
}
else
- stabilizer->setMotionEstimator(new GlobalMotionReader(arg("load-motions")));
+ stabilizer->setMotionEstimator(new FromFileMotionReader("motions." + arg("load-motions")));
if (arg("save-motions") != "no")
- saveMotionsPath = arg("save-motions");
+ stabilizer->setMotionEstimator(
+ new ToFileMotionWriter("motions." + arg("save-motions"), stabilizer->motionEstimator()));
stabilizer->setRadius(argi("radius"));
if (arg("deblur") == "yes")
{
inpainters->setRadius(argi("radius"));
stabilizer->setInpainter(inpainters_);
- }
-
- stabilizer->setLog(new LogToStdout());
+ }
if (arg("output") != "no")
outputPath = arg("output");