Commit fa09f3d1 authored by Alexey Spizhevoy's avatar Alexey Spizhevoy

Refactored videostab module. Added MoreAccurateMotionWobbleSuppressor class

parent f32b645b
...@@ -56,13 +56,18 @@ CV_EXPORTS float calcBlurriness(const Mat &frame); ...@@ -56,13 +56,18 @@ CV_EXPORTS float calcBlurriness(const Mat &frame);
class CV_EXPORTS DeblurerBase class CV_EXPORTS DeblurerBase
{ {
public: public:
DeblurerBase() : radius_(0), frames_(0), motions_(0) {} DeblurerBase() : radius_(0), frames_(0), motions_(0), blurrinessRates_(0) {}
virtual ~DeblurerBase() {} virtual ~DeblurerBase() {}
virtual void setRadius(int val) { radius_ = val; } virtual void setRadius(int val) { radius_ = val; }
virtual int radius() const { return radius_; } 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 void setFrames(const std::vector<Mat> &val) { frames_ = &val; }
virtual const std::vector<Mat>& frames() const { return *frames_; } virtual const std::vector<Mat>& frames() const { return *frames_; }
...@@ -72,8 +77,6 @@ public: ...@@ -72,8 +77,6 @@ public:
virtual void setBlurrinessRates(const std::vector<float> &val) { blurrinessRates_ = &val; } virtual void setBlurrinessRates(const std::vector<float> &val) { blurrinessRates_ = &val; }
virtual const std::vector<float>& blurrinessRates() const { return *blurrinessRates_; } virtual const std::vector<float>& blurrinessRates() const { return *blurrinessRates_; }
virtual void deblur(int idx, Mat &frame) = 0;
protected: protected:
int radius_; int radius_;
const std::vector<Mat> *frames_; const std::vector<Mat> *frames_;
......
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
#define __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__ #define __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__
#include <vector> #include <vector>
#include <string>
#include <fstream>
#include "opencv2/core/core.hpp" #include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp" #include "opencv2/features2d/features2d.hpp"
#include "opencv2/videostab/optical_flow.hpp" #include "opencv2/videostab/optical_flow.hpp"
...@@ -105,13 +107,25 @@ protected: ...@@ -105,13 +107,25 @@ protected:
MotionModel motionModel_; MotionModel motionModel_;
}; };
class CV_EXPORTS EyeMotionEstimator : public GlobalMotionEstimatorBase class CV_EXPORTS FromFileMotionReader : public GlobalMotionEstimatorBase
{ {
public: public:
virtual Mat estimate(const Mat &/*frame0*/, const Mat &/*frame1*/) FromFileMotionReader(const std::string &path);
{ virtual Mat estimate(const Mat &frame0, const Mat &frame1);
return Mat::eye(3, 3, CV_32F);
} 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 class CV_EXPORTS PyrLkRobustMotionEstimator : public GlobalMotionEstimatorBase
......
...@@ -59,7 +59,7 @@ class CV_EXPORTS InpainterBase ...@@ -59,7 +59,7 @@ class CV_EXPORTS InpainterBase
{ {
public: public:
InpainterBase() InpainterBase()
: radius_(0), frames_(0), motions_(0), : radius_(0), motionModel_(UNKNOWN), frames_(0), motions_(0),
stabilizedFrames_(0), stabilizationMotions_(0) {} stabilizedFrames_(0), stabilizationMotions_(0) {}
virtual ~InpainterBase() {} virtual ~InpainterBase() {}
...@@ -70,6 +70,11 @@ public: ...@@ -70,6 +70,11 @@ public:
virtual void setMotionModel(MotionModel val) { motionModel_ = val; } virtual void setMotionModel(MotionModel val) { motionModel_ = val; }
virtual MotionModel motionModel() const { return motionModel_; } 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 void setFrames(const std::vector<Mat> &val) { frames_ = &val; }
virtual const std::vector<Mat>& frames() const { return *frames_; } virtual const std::vector<Mat>& frames() const { return *frames_; }
...@@ -82,8 +87,6 @@ public: ...@@ -82,8 +87,6 @@ public:
virtual void setStabilizationMotions(const std::vector<Mat> &val) { stabilizationMotions_ = &val; } virtual void setStabilizationMotions(const std::vector<Mat> &val) { stabilizationMotions_ = &val; }
virtual const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; } virtual const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; }
virtual void inpaint(int idx, Mat &frame, Mat &mask) = 0;
protected: protected:
int radius_; int radius_;
MotionModel motionModel_; MotionModel motionModel_;
......
...@@ -184,6 +184,8 @@ private: ...@@ -184,6 +184,8 @@ private:
int frameCount_; int frameCount_;
bool isPrePassDone_; bool isPrePassDone_;
bool doWobbleSuppression_;
std::vector<Mat> motions2_;
Mat suppressedFrame_; Mat suppressedFrame_;
}; };
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <vector> #include <vector>
#include "opencv2/core/core.hpp" #include "opencv2/core/core.hpp"
#include "opencv2/videostab/global_motion.hpp" #include "opencv2/videostab/global_motion.hpp"
#include "opencv2/videostab/log.hpp"
namespace cv namespace cv
{ {
...@@ -55,33 +56,48 @@ namespace videostab ...@@ -55,33 +56,48 @@ namespace videostab
class CV_EXPORTS WobbleSuppressorBase class CV_EXPORTS WobbleSuppressorBase
{ {
public: public:
WobbleSuppressorBase();
virtual ~WobbleSuppressorBase() {} virtual ~WobbleSuppressorBase() {}
virtual void setFrames(const std::vector<Mat> &val) { frames_ = &val; } void setMotionEstimator(Ptr<GlobalMotionEstimatorBase> val) { motionEstimator_ = val; }
virtual const std::vector<Mat>& frames() const { return *frames_; } 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 void setMotions(const std::vector<Mat> &val) { motions_ = &val; }
virtual const std::vector<Mat>& motions() const { return *motions_; } virtual const std::vector<Mat>& motions() const { return *motions_; }
virtual void setStabilizedFrames(const std::vector<Mat> &val) { stabilizedFrames_ = &val; } virtual void setMotions2(const std::vector<Mat> &val) { motions2_ = &val; }
virtual const std::vector<Mat>& stabilizedFrames() const { return *stabilizedFrames_; } virtual const std::vector<Mat>& motions2() const { return *motions2_; }
virtual void setStabilizationMotions(const std::vector<Mat> &val) { stabilizationMotions_ = &val; } virtual void setStabilizationMotions(const std::vector<Mat> &val) { stabilizationMotions_ = &val; }
virtual const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; } virtual const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; }
virtual void suppress(int idx, Mat &frame) = 0;
protected: protected:
const std::vector<Mat> *frames_; Ptr<GlobalMotionEstimatorBase> motionEstimator_;
int frameCount_;
const std::vector<Mat> *motions_; const std::vector<Mat> *motions_;
const std::vector<Mat> *stabilizedFrames_; const std::vector<Mat> *motions2_;
const std::vector<Mat> *stabilizationMotions_; const std::vector<Mat> *stabilizationMotions_;
}; };
class CV_EXPORTS NullWobbleSuppressor : public WobbleSuppressorBase class CV_EXPORTS NullWobbleSuppressor : public WobbleSuppressorBase
{ {
public: 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 } // namespace videostab
......
...@@ -288,6 +288,41 @@ Mat estimateGlobalMotionRobust( ...@@ -288,6 +288,41 @@ Mat estimateGlobalMotionRobust(
} }
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() PyrLkRobustMotionEstimator::PyrLkRobustMotionEstimator()
: ransacParams_(RansacParams::affine2dMotionStd()) : ransacParams_(RansacParams::affine2dMotionStd())
{ {
......
...@@ -53,7 +53,7 @@ namespace videostab ...@@ -53,7 +53,7 @@ namespace videostab
StabilizerBase::StabilizerBase() StabilizerBase::StabilizerBase()
{ {
setLog(new NullLog()); setLog(new LogToStdout());
setFrameSource(new NullFrameSource()); setFrameSource(new NullFrameSource());
setMotionEstimator(new PyrLkRobustMotionEstimator()); setMotionEstimator(new PyrLkRobustMotionEstimator());
setDeblurer(new NullDeblurer()); setDeblurer(new NullDeblurer());
...@@ -304,6 +304,8 @@ void TwoPassStabilizer::reset() ...@@ -304,6 +304,8 @@ void TwoPassStabilizer::reset()
StabilizerBase::reset(); StabilizerBase::reset();
frameCount_ = 0; frameCount_ = 0;
isPrePassDone_ = false; isPrePassDone_ = false;
doWobbleSuppression_ = false;
motions2_.clear();
suppressedFrame_ = Mat(); suppressedFrame_ = Mat();
} }
...@@ -333,10 +335,20 @@ void TwoPassStabilizer::runPrePassIfNecessary() ...@@ -333,10 +335,20 @@ void TwoPassStabilizer::runPrePassIfNecessary()
Mat prevFrame, frame; Mat prevFrame, frame;
WobbleSuppressorBase *wobbleSuppressor = static_cast<WobbleSuppressorBase*>(wobbleSuppressor_);
doWobbleSuppression_ = dynamic_cast<NullWobbleSuppressor*>(wobbleSuppressor) == 0;
while (!(frame = frameSource_->nextFrame()).empty()) while (!(frame = frameSource_->nextFrame()).empty())
{ {
if (frameCount_ > 0) if (frameCount_ > 0)
{
motions_.push_back(motionEstimator_->estimate(prevFrame, frame)); motions_.push_back(motionEstimator_->estimate(prevFrame, frame));
if (doWobbleSuppression_)
{
motions2_.push_back(
wobbleSuppressor_->motionEstimator()->estimate(prevFrame, frame));
}
}
else else
{ {
frameSize_ = frame.size(); frameSize_ = frame.size();
...@@ -386,10 +398,15 @@ void TwoPassStabilizer::setUp(const Mat &firstFrame) ...@@ -386,10 +398,15 @@ void TwoPassStabilizer::setUp(const Mat &firstFrame)
for (int i = -radius_; i <= 0; ++i) for (int i = -radius_; i <= 0; ++i)
at(i, frames_) = firstFrame; at(i, frames_) = firstFrame;
wobbleSuppressor_->setFrames(frames_); WobbleSuppressorBase *wobbleSuppressor = static_cast<WobbleSuppressorBase*>(wobbleSuppressor_);
doWobbleSuppression_ = dynamic_cast<NullWobbleSuppressor*>(wobbleSuppressor) == 0;
if (doWobbleSuppression_)
{
wobbleSuppressor_->setFrameCount(frameCount_);
wobbleSuppressor_->setMotions(motions_); wobbleSuppressor_->setMotions(motions_);
wobbleSuppressor_->setStabilizedFrames(stabilizedFrames_); wobbleSuppressor_->setMotions2(motions2_);
wobbleSuppressor_->setStabilizationMotions(stabilizationMotions_); wobbleSuppressor_->setStabilizationMotions(stabilizationMotions_);
}
StabilizerBase::setUp(firstFrame); StabilizerBase::setUp(firstFrame);
} }
...@@ -407,9 +424,9 @@ Mat TwoPassStabilizer::estimateStabilizationMotion() ...@@ -407,9 +424,9 @@ Mat TwoPassStabilizer::estimateStabilizationMotion()
} }
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_); return StabilizerBase::postProcessFrame(suppressedFrame_);
} }
......
...@@ -51,9 +51,30 @@ namespace cv ...@@ -51,9 +51,30 @@ namespace cv
namespace videostab 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 } // namespace videostab
......
...@@ -29,43 +29,6 @@ void run(); ...@@ -29,43 +29,6 @@ void run();
void saveMotionsIfNecessary(); void saveMotionsIfNecessary();
void printHelp(); 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() void run()
{ {
...@@ -76,8 +39,6 @@ void run() ...@@ -76,8 +39,6 @@ void run()
while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty()) while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty())
{ {
nframes++; nframes++;
if (!saveMotionsPath.empty())
saveMotionsIfNecessary();
if (!outputPath.empty()) if (!outputPath.empty())
{ {
if (!writer.isOpened()) if (!writer.isOpened())
...@@ -99,33 +60,6 @@ void run() ...@@ -99,33 +60,6 @@ void run()
} }
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() void printHelp()
{ {
cout << "OpenCV video stabilizer.\n" cout << "OpenCV video stabilizer.\n"
...@@ -173,6 +107,8 @@ void printHelp() ...@@ -173,6 +107,8 @@ void printHelp()
" --color-inpaint-radius=<float_number>\n" " --color-inpaint-radius=<float_number>\n"
" Set color inpainting radius (for ns and telea options only).\n" " Set color inpainting radius (for ns and telea options only).\n"
" The default is 2.0\n\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" " -o, --output=(no|<file_path>)\n"
" Set output file path explicitely. The default is stabilized.avi.\n" " Set output file path explicitely. The default is stabilized.avi.\n"
" --fps=(<int_number>|auto)\n" " --fps=(<int_number>|auto)\n"
...@@ -210,6 +146,7 @@ int main(int argc, const char **argv) ...@@ -210,6 +146,7 @@ int main(int argc, const char **argv)
"{ | dist-thresh | 5.0 | }" "{ | dist-thresh | 5.0 | }"
"{ | color-inpaint | no | }" "{ | color-inpaint | no | }"
"{ | color-inpaint-radius | 2 | }" "{ | color-inpaint-radius | 2 | }"
"{ | wobble-suppress | no | }"
"{ o | output | stabilized.avi | }" "{ o | output | stabilized.avi | }"
"{ | fps | auto | }" "{ | fps | auto | }"
"{ q | quiet | false | }" "{ q | quiet | false | }"
...@@ -226,7 +163,9 @@ int main(int argc, const char **argv) ...@@ -226,7 +163,9 @@ int main(int argc, const char **argv)
StabilizerBase *stabilizer; StabilizerBase *stabilizer;
bool isTwoPass = arg("est-trim") == "yes" || arg("save-motions") != "no"; bool isTwoPass =
arg("est-trim") == "yes" || arg("wobble-suppress") == "yes";
if (isTwoPass) if (isTwoPass)
{ {
TwoPassStabilizer *twoPassStabilizer = new TwoPassStabilizer(); TwoPassStabilizer *twoPassStabilizer = new TwoPassStabilizer();
...@@ -236,6 +175,19 @@ int main(int argc, const char **argv) ...@@ -236,6 +175,19 @@ int main(int argc, const char **argv)
twoPassStabilizer->setMotionStabilizer(new GaussianMotionFilter(argi("radius"))); twoPassStabilizer->setMotionStabilizer(new GaussianMotionFilter(argi("radius")));
else else
twoPassStabilizer->setMotionStabilizer(new GaussianMotionFilter(argi("radius"), argf("stdev"))); 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 else
{ {
...@@ -289,10 +241,11 @@ int main(int argc, const char **argv) ...@@ -289,10 +241,11 @@ int main(int argc, const char **argv)
stabilizer->setMotionEstimator(est_); stabilizer->setMotionEstimator(est_);
} }
else else
stabilizer->setMotionEstimator(new GlobalMotionReader(arg("load-motions"))); stabilizer->setMotionEstimator(new FromFileMotionReader("motions." + arg("load-motions")));
if (arg("save-motions") != "no") if (arg("save-motions") != "no")
saveMotionsPath = arg("save-motions"); stabilizer->setMotionEstimator(
new ToFileMotionWriter("motions." + arg("save-motions"), stabilizer->motionEstimator()));
stabilizer->setRadius(argi("radius")); stabilizer->setRadius(argi("radius"));
if (arg("deblur") == "yes") if (arg("deblur") == "yes")
...@@ -344,8 +297,6 @@ int main(int argc, const char **argv) ...@@ -344,8 +297,6 @@ int main(int argc, const char **argv)
stabilizer->setInpainter(inpainters_); stabilizer->setInpainter(inpainters_);
} }
stabilizer->setLog(new LogToStdout());
if (arg("output") != "no") if (arg("output") != "no")
outputPath = arg("output"); outputPath = arg("output");
......
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