Refactored videostab module. Added MoreAccurateMotionWobbleSuppressor class

This commit is contained in:
Alexey Spizhevoy 2012-04-05 13:23:42 +00:00
parent f32b645b96
commit fa09f3d121
9 changed files with 163 additions and 101 deletions

View File

@ -56,13 +56,18 @@ CV_EXPORTS float calcBlurriness(const Mat &frame);
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_; }
@ -72,8 +77,6 @@ public:
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_;

View File

@ -44,6 +44,8 @@
#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"
@ -105,13 +107,25 @@ protected:
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

View File

@ -59,7 +59,7 @@ class CV_EXPORTS InpainterBase
{
public:
InpainterBase()
: radius_(0), frames_(0), motions_(0),
: radius_(0), motionModel_(UNKNOWN), frames_(0), motions_(0),
stabilizedFrames_(0), stabilizationMotions_(0) {}
virtual ~InpainterBase() {}
@ -70,6 +70,11 @@ public:
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_; }
@ -82,8 +87,6 @@ public:
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_;

View File

@ -184,6 +184,8 @@ private:
int frameCount_;
bool isPrePassDone_;
bool doWobbleSuppression_;
std::vector<Mat> motions2_;
Mat suppressedFrame_;
};

View File

@ -46,6 +46,7 @@
#include <vector>
#include "opencv2/core/core.hpp"
#include "opencv2/videostab/global_motion.hpp"
#include "opencv2/videostab/log.hpp"
namespace cv
{
@ -55,33 +56,48 @@ namespace videostab
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

View File

@ -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()
: ransacParams_(RansacParams::affine2dMotionStd())
{

View File

@ -53,7 +53,7 @@ namespace videostab
StabilizerBase::StabilizerBase()
{
setLog(new NullLog());
setLog(new LogToStdout());
setFrameSource(new NullFrameSource());
setMotionEstimator(new PyrLkRobustMotionEstimator());
setDeblurer(new NullDeblurer());
@ -304,6 +304,8 @@ void TwoPassStabilizer::reset()
StabilizerBase::reset();
frameCount_ = 0;
isPrePassDone_ = false;
doWobbleSuppression_ = false;
motions2_.clear();
suppressedFrame_ = Mat();
}
@ -333,10 +335,20 @@ void TwoPassStabilizer::runPrePassIfNecessary()
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();
@ -386,10 +398,15 @@ void TwoPassStabilizer::setUp(const Mat &firstFrame)
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);
}
@ -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_);
}

View File

@ -51,9 +51,30 @@ namespace cv
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

View File

@ -29,43 +29,6 @@ void run();
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()
{
@ -76,8 +39,6 @@ void run()
while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty())
{
nframes++;
if (!saveMotionsPath.empty())
saveMotionsIfNecessary();
if (!outputPath.empty())
{
if (!writer.isOpened())
@ -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()
{
cout << "OpenCV video stabilizer.\n"
@ -173,6 +107,8 @@ void printHelp()
" --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"
@ -210,6 +146,7 @@ int main(int argc, const char **argv)
"{ | dist-thresh | 5.0 | }"
"{ | color-inpaint | no | }"
"{ | color-inpaint-radius | 2 | }"
"{ | wobble-suppress | no | }"
"{ o | output | stabilized.avi | }"
"{ | fps | auto | }"
"{ q | quiet | false | }"
@ -226,7 +163,9 @@ int main(int argc, const char **argv)
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();
@ -236,6 +175,19 @@ int main(int argc, const char **argv)
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
{
@ -289,10 +241,11 @@ int main(int argc, const char **argv)
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")
@ -342,9 +295,7 @@ int main(int argc, const char **argv)
{
inpainters->setRadius(argi("radius"));
stabilizer->setInpainter(inpainters_);
}
stabilizer->setLog(new LogToStdout());
}
if (arg("output") != "no")
outputPath = arg("output");