CV_EXPORTS float calcBlurriness(const Mat &frame);
-class CV_EXPORTS IDeblurer
+class CV_EXPORTS DeblurerBase
{
public:
- IDeblurer() : radius_(0), frames_(0), motions_(0) {}
+ DeblurerBase() : radius_(0), frames_(0), motions_(0) {}
- virtual ~IDeblurer() {}
+ virtual ~DeblurerBase() {}
virtual void setRadius(int val) { radius_ = val; }
- int radius() const { return radius_; }
+ virtual int radius() const { return radius_; }
virtual void setFrames(const std::vector<Mat> &val) { frames_ = &val; }
- const std::vector<Mat>& frames() const { return *frames_; }
+ virtual const std::vector<Mat>& frames() const { return *frames_; }
virtual void setMotions(const std::vector<Mat> &val) { motions_ = &val; }
- const std::vector<Mat>& motions() const { return *motions_; }
+ virtual const std::vector<Mat>& motions() const { return *motions_; }
virtual void setBlurrinessRates(const std::vector<float> &val) { blurrinessRates_ = &val; }
- const std::vector<float>& blurrinessRates() const { return *blurrinessRates_; }
+ virtual const std::vector<float>& blurrinessRates() const { return *blurrinessRates_; }
+
+ virtual void update() {}
virtual void deblur(int idx, Mat &frame) = 0;
const std::vector<float> *blurrinessRates_;
};
-class CV_EXPORTS NullDeblurer : public IDeblurer
+class CV_EXPORTS NullDeblurer : public DeblurerBase
{
public:
virtual void deblur(int /*idx*/, Mat &/*frame*/) {}
};
-class CV_EXPORTS WeightingDeblurer : public IDeblurer
+class CV_EXPORTS WeightingDeblurer : public DeblurerBase
{
public:
WeightingDeblurer();
float minInlierRatio_;
};
+CV_EXPORTS Mat getMotion(int from, int to, const Mat *motions, int size);
+
CV_EXPORTS Mat getMotion(int from, int to, const std::vector<Mat> &motions);
} // namespace videostab
namespace videostab
{
-class CV_EXPORTS IInpainter
+class CV_EXPORTS InpainterBase
{
public:
- IInpainter()
+ InpainterBase()
: radius_(0), frames_(0), motions_(0),
stabilizedFrames_(0), stabilizationMotions_(0) {}
- virtual ~IInpainter() {}
+ virtual ~InpainterBase() {}
virtual void setRadius(int val) { radius_ = val; }
- int radius() const { return radius_; }
+ virtual int radius() const { return radius_; }
virtual void setFrames(const std::vector<Mat> &val) { frames_ = &val; }
- const std::vector<Mat>& frames() const { return *frames_; }
+ virtual const std::vector<Mat>& frames() const { return *frames_; }
virtual void setMotions(const std::vector<Mat> &val) { motions_ = &val; }
- 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; }
- const std::vector<Mat>& stabilizedFrames() const { return *stabilizedFrames_; }
+ virtual const std::vector<Mat>& stabilizedFrames() const { return *stabilizedFrames_; }
virtual void setStabilizationMotions(const std::vector<Mat> &val) { stabilizationMotions_ = &val; }
- const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; }
+ virtual const std::vector<Mat>& stabilizationMotions() const { return *stabilizationMotions_; }
+
+ virtual void update() {}
virtual void inpaint(int idx, Mat &frame, Mat &mask) = 0;
const std::vector<Mat> *stabilizationMotions_;
};
-class CV_EXPORTS NullInpainter : public IInpainter
+class CV_EXPORTS NullInpainter : public InpainterBase
{
public:
virtual void inpaint(int /*idx*/, Mat &/*frame*/, Mat &/*mask*/) {}
};
-class CV_EXPORTS InpaintingPipeline : public IInpainter
+class CV_EXPORTS InpaintingPipeline : public InpainterBase
{
public:
- void pushBack(Ptr<IInpainter> inpainter) { inpainters_.push_back(inpainter); }
+ void pushBack(Ptr<InpainterBase> inpainter) { inpainters_.push_back(inpainter); }
bool empty() const { return inpainters_.empty(); }
virtual void setRadius(int val);
virtual void setStabilizedFrames(const std::vector<Mat> &val);
virtual void setStabilizationMotions(const std::vector<Mat> &val);
+ virtual void update();
+
virtual void inpaint(int idx, Mat &frame, Mat &mask);
private:
- std::vector<Ptr<IInpainter> > inpainters_;
+ std::vector<Ptr<InpainterBase> > inpainters_;
};
-class CV_EXPORTS ConsistentMosaicInpainter : public IInpainter
+class CV_EXPORTS ConsistentMosaicInpainter : public InpainterBase
{
public:
ConsistentMosaicInpainter();
float stdevThresh_;
};
-class CV_EXPORTS MotionInpainter : public IInpainter
+class CV_EXPORTS MotionInpainter : public InpainterBase
{
public:
MotionInpainter();
Mat_<uchar> flowMask_;
};
-class CV_EXPORTS ColorAverageInpainter : public IInpainter
+class CV_EXPORTS ColorAverageInpainter : public InpainterBase
{
public:
virtual void inpaint(int idx, Mat &frame, Mat &mask);
FastMarchingMethod fmm_;
};
-class CV_EXPORTS ColorInpainter : public IInpainter
+class CV_EXPORTS ColorInpainter : public InpainterBase
{
public:
ColorInpainter(int method = INPAINT_TELEA, double radius = 2.)
namespace videostab
{
-class CV_EXPORTS IMotionFilter
+class CV_EXPORTS IMotionStabilizer
{
public:
- virtual ~IMotionFilter() {}
- virtual int radius() const = 0;
- virtual Mat apply(int index, std::vector<Mat> &Ms) const = 0;
+ virtual void stabilize(const Mat *motions, int size, Mat *stabilizationMotions) const = 0;
};
-class CV_EXPORTS GaussianMotionFilter : public IMotionFilter
+class CV_EXPORTS MotionFilterBase : public IMotionStabilizer
{
public:
- GaussianMotionFilter(int radius, float stdev);
+ MotionFilterBase() : radius_(0) {}
+ virtual ~MotionFilterBase() {}
+
+ virtual void setRadius(int val) { radius_ = val; }
virtual int radius() const { return radius_; }
- virtual Mat apply(int idx, std::vector<Mat> &motions) const;
-private:
+ virtual void update() {}
+
+ virtual Mat stabilize(int index, const Mat *motions, int size) const = 0;
+ virtual void stabilize(const Mat *motions, int size, Mat *stabilizationMotions) const;
+
+protected:
int radius_;
+};
+
+class CV_EXPORTS GaussianMotionFilter : public MotionFilterBase
+{
+public:
+ GaussianMotionFilter() : stdev_(-1.f) {}
+
+ void setStdev(float val) { stdev_ = val; }
+ float stdev() const { return stdev_; }
+
+ virtual void update();
+
+ virtual Mat stabilize(int index, const Mat *motions, int size) const;
+
+private:
+ float stdev_;
std::vector<float> weight_;
};
namespace videostab
{
-class CV_EXPORTS Stabilizer : public IFrameSource
+class CV_EXPORTS StabilizerBase
{
public:
- Stabilizer();
+ virtual ~StabilizerBase() {}
void setLog(Ptr<ILog> log) { log_ = log; }
Ptr<ILog> log() const { return log_; }
- void setFrameSource(Ptr<IFrameSource> val) { frameSource_ = val; reset(); }
+ void setRadius(int val) { radius_ = val; }
+ int radius() const { return radius_; }
+
+ void setFrameSource(Ptr<IFrameSource> val) { frameSource_ = val; }
Ptr<IFrameSource> frameSource() const { return frameSource_; }
void setMotionEstimator(Ptr<IGlobalMotionEstimator> val) { motionEstimator_ = val; }
Ptr<IGlobalMotionEstimator> motionEstimator() const { return motionEstimator_; }
- void setMotionFilter(Ptr<IMotionFilter> val) { motionFilter_ = val; reset(); }
- Ptr<IMotionFilter> motionFilter() const { return motionFilter_; }
-
- void setDeblurer(Ptr<IDeblurer> val) { deblurer_ = val; reset(); }
- Ptr<IDeblurer> deblurrer() const { return deblurer_; }
-
- void setEstimateTrimRatio(bool val) { mustEstimateTrimRatio_ = val; reset(); }
- bool mustEstimateTrimRatio() const { return mustEstimateTrimRatio_; }
+ void setDeblurer(Ptr<DeblurerBase> val) { deblurer_ = val; }
+ Ptr<DeblurerBase> deblurrer() const { return deblurer_; }
- void setTrimRatio(float val) { trimRatio_ = val; reset(); }
+ void setTrimRatio(float val) { trimRatio_ = val; }
float trimRatio() const { return trimRatio_; }
- void setInclusionConstraint(bool val) { inclusionConstraint_ = val; }
- bool inclusionConstraint() const { return inclusionConstraint_; }
+ void setCorrectionForInclusion(bool val) { doCorrectionForInclusion_ = val; }
+ bool doCorrectionForInclusion() const { return doCorrectionForInclusion_; }
void setBorderMode(int val) { borderMode_ = val; }
int borderMode() const { return borderMode_; }
- void setInpainter(Ptr<IInpainter> val) { inpainter_ = val; reset(); }
- Ptr<IInpainter> inpainter() const { return inpainter_; }
+ void setInpainter(Ptr<InpainterBase> val) { inpainter_ = val; }
+ Ptr<InpainterBase> inpainter() const { return inpainter_; }
- virtual void reset();
- virtual Mat nextFrame();
+protected:
+ StabilizerBase();
-private:
- void estimateMotionsAndTrimRatio();
- void processFirstFrame(Mat &frame);
- bool processNextFrame();
- void stabilizeFrame(int idx);
+ void setUp(int cacheSize, const Mat &frame);
+ Mat nextStabilizedFrame();
+ bool doOneIteration();
+ void stabilizeFrame(const Mat &stabilizationMotion);
+ virtual void setUp(Mat &firstFrame) = 0;
+ virtual void stabilizeFrame() = 0;
+ virtual void estimateMotion() = 0;
+
+ Ptr<ILog> log_;
Ptr<IFrameSource> frameSource_;
Ptr<IGlobalMotionEstimator> motionEstimator_;
- Ptr<IMotionFilter> motionFilter_;
- Ptr<IDeblurer> deblurer_;
- Ptr<IInpainter> inpainter_;
- bool mustEstimateTrimRatio_;
+ Ptr<DeblurerBase> deblurer_;
+ Ptr<InpainterBase> inpainter_;
+ int radius_;
float trimRatio_;
- bool inclusionConstraint_;
- int borderMode_;
- Ptr<ILog> log_;
+ bool doCorrectionForInclusion_;
+ int borderMode_;
Size frameSize_;
Mat frameMask_;
- int radius_;
int curPos_;
int curStabilizedPos_;
- bool auxPassWasDone_;
bool doDeblurring_;
Mat preProcessedFrame_;
bool doInpainting_;
Mat inpaintingMask_;
std::vector<Mat> frames_;
- std::vector<Mat> motions_; // motions_[i] is the motion from i to i+1 frame
+ std::vector<Mat> motions_; // motions_[i] is the motion from i-th to i+1-th frame
std::vector<float> blurrinessRates_;
std::vector<Mat> stabilizedFrames_;
std::vector<Mat> stabilizedMasks_;
std::vector<Mat> stabilizationMotions_;
};
+class CV_EXPORTS OnePassStabilizer : public StabilizerBase, public IFrameSource
+{
+public:
+ OnePassStabilizer();
+
+ void setMotionFilter(Ptr<MotionFilterBase> val) { motionFilter_ = val; }
+ Ptr<MotionFilterBase> motionFilter() const { return motionFilter_; }
+
+ virtual void reset() { resetImpl(); }
+ virtual Mat nextFrame() { return nextStabilizedFrame(); }
+
+private:
+ void resetImpl();
+
+ virtual void setUp(Mat &firstFrame);
+ virtual void estimateMotion();
+ virtual void stabilizeFrame();
+
+ Ptr<MotionFilterBase> motionFilter_;
+};
+
+class CV_EXPORTS TwoPassStabilizer : public StabilizerBase, public IFrameSource
+{
+public:
+ TwoPassStabilizer();
+
+ void setMotionStabilizer(Ptr<IMotionStabilizer> val) { motionStabilizer_ = val; }
+ Ptr<IMotionStabilizer> motionStabilizer() const { return motionStabilizer_; }
+
+ void setEstimateTrimRatio(bool val) { mustEstTrimRatio_ = val; }
+ bool mustEstimateTrimaRatio() const { return mustEstTrimRatio_; }
+
+ virtual void reset() { resetImpl(); }
+ virtual Mat nextFrame();
+
+private:
+ void resetImpl();
+ void runPrePassIfNecessary();
+
+ virtual void setUp(Mat &firstFrame);
+ virtual void estimateMotion() { /* do nothing as motion was estimation in pre-pass */ }
+ virtual void stabilizeFrame();
+
+ Ptr<IMotionStabilizer> motionStabilizer_;
+ bool mustEstTrimRatio_;
+
+ int frameCount_;
+ bool isPrePassDone_;
+};
+
} // namespace videostab
} // namespace cv
}
-Mat getMotion(int from, int to, const vector<Mat> &motions)
+Mat getMotion(int from, int to, const Mat *motions, int size)
{
Mat M = Mat::eye(3, 3, CV_32F);
if (to > from)
{
for (int i = from; i < to; ++i)
- M = at(i, motions) * M;
+ M = at(i, motions, size) * M;
}
else if (from > to)
{
for (int i = to; i < from; ++i)
- M = at(i, motions) * M;
+ M = at(i, motions, size) * M;
M = M.inv();
}
return M;
}
+
+Mat getMotion(int from, int to, const vector<Mat> &motions)
+{
+ return getMotion(from, to, &motions[0], motions.size());
+}
+
} // namespace videostab
} // namespace cv
{
for (size_t i = 0; i < inpainters_.size(); ++i)
inpainters_[i]->setRadius(val);
- IInpainter::setRadius(val);
+ InpainterBase::setRadius(val);
}
{
for (size_t i = 0; i < inpainters_.size(); ++i)
inpainters_[i]->setFrames(val);
- IInpainter::setFrames(val);
+ InpainterBase::setFrames(val);
}
{
for (size_t i = 0; i < inpainters_.size(); ++i)
inpainters_[i]->setMotions(val);
- IInpainter::setMotions(val);
+ InpainterBase::setMotions(val);
}
{
for (size_t i = 0; i < inpainters_.size(); ++i)
inpainters_[i]->setStabilizedFrames(val);
- IInpainter::setStabilizedFrames(val);
+ InpainterBase::setStabilizedFrames(val);
}
{
for (size_t i = 0; i < inpainters_.size(); ++i)
inpainters_[i]->setStabilizationMotions(val);
- IInpainter::setStabilizationMotions(val);
+ InpainterBase::setStabilizationMotions(val);
+}
+
+
+void InpaintingPipeline::update()
+{
+ for (size_t i = 0; i < inpainters_.size(); ++i)
+ inpainters_[i]->update();
+ InpainterBase::update();
}
namespace videostab
{
-GaussianMotionFilter::GaussianMotionFilter(int radius, float stdev) : radius_(radius)
+void MotionFilterBase::stabilize(const Mat *motions, int size, Mat *stabilizationMotions) const
{
+ for (int i = 0; i < size; ++i)
+ stabilizationMotions[i] = stabilize(i, motions, size);
+}
+
+
+void GaussianMotionFilter::update()
+{
+ float sigma = stdev_ > 0.f ? stdev_ : sqrt(static_cast<float>(radius_));
float sum = 0;
weight_.resize(2*radius_ + 1);
for (int i = -radius_; i <= radius_; ++i)
- sum += weight_[radius_ + i] = std::exp(-i*i/(stdev*stdev));
+ sum += weight_[radius_ + i] = std::exp(-i*i/(sigma*sigma));
for (int i = -radius_; i <= radius_; ++i)
weight_[radius_ + i] /= sum;
}
-Mat GaussianMotionFilter::apply(int idx, vector<Mat> &motions) const
+Mat GaussianMotionFilter::stabilize(int index, const Mat *motions, int size) const
{
- const Mat &cur = at(idx, motions);
+ const Mat &cur = at(index, motions, size);
Mat res = Mat::zeros(cur.size(), cur.type());
float sum = 0.f;
- for (int i = std::max(idx - radius_, 0); i <= idx + radius_; ++i)
+ for (int i = std::max(index - radius_, 0); i <= index + radius_; ++i)
{
- res += weight_[radius_ + i - idx] * getMotion(idx, i, motions);
- sum += weight_[radius_ + i - idx];
+ res += weight_[radius_ + i - index] * getMotion(index, i, motions, size);
+ sum += weight_[radius_ + i - index];
}
return res / sum;
}
return 0.3f*bgr.x + 0.59f*bgr.y + 0.11f*bgr.z;
}
+template <typename T> inline T& at(int index, const T *items, int size)
+{
+ return items[cv::borderInterpolate(index, size, cv::BORDER_WRAP)];
+}
+
+template <typename T> inline const T& at(int index, const T *items, int size)
+{
+ return items[cv::borderInterpolate(index, size, cv::BORDER_WRAP)];
+}
+
template <typename T> inline T& at(int index, std::vector<T> &items)
{
- return items[cv::borderInterpolate(index, items.size(), cv::BORDER_WRAP)];
+ return at(index, &items[0], items.size());
}
template <typename T> inline const T& at(int index, const std::vector<T> &items)
namespace videostab
{
-Stabilizer::Stabilizer()
+StabilizerBase::StabilizerBase()
{
+ setLog(new NullLog());
setFrameSource(new NullFrameSource());
setMotionEstimator(new PyrLkRobustMotionEstimator());
- setMotionFilter(new GaussianMotionFilter(15, sqrt(15.f)));
setDeblurer(new NullDeblurer());
setInpainter(new NullInpainter());
- setEstimateTrimRatio(true);
+ setRadius(15);
setTrimRatio(0);
- setInclusionConstraint(false);
+ setCorrectionForInclusion(false);
setBorderMode(BORDER_REPLICATE);
- setLog(new NullLog());
-}
-
-
-void Stabilizer::reset()
-{
- radius_ = 0;
- curPos_ = -1;
- curStabilizedPos_ = -1;
- auxPassWasDone_ = false;
- frames_.clear();
- motions_.clear();
- stabilizedFrames_.clear();
- stabilizationMotions_.clear();
- doDeblurring_ = false;
- doInpainting_ = false;
-}
-
-
-Mat Stabilizer::nextFrame()
-{
- if (mustEstimateTrimRatio_ && !auxPassWasDone_)
- {
- estimateMotionsAndTrimRatio();
- auxPassWasDone_ = true;
- frameSource_->reset();
- }
-
- if (curStabilizedPos_ == curPos_ && curStabilizedPos_ != -1)
- return Mat(); // we've processed all frames already
-
- bool processed;
- do {
- processed = processNextFrame();
- } while (processed && curStabilizedPos_ == -1);
-
- if (curStabilizedPos_ == -1)
- return Mat(); // frame source is empty
-
- const Mat &stabilizedFrame = at(curStabilizedPos_, stabilizedFrames_);
- int dx = static_cast<int>(floor(trimRatio_ * stabilizedFrame.cols));
- int dy = static_cast<int>(floor(trimRatio_ * stabilizedFrame.rows));
- return stabilizedFrame(Rect(dx, dy, stabilizedFrame.cols - 2*dx, stabilizedFrame.rows - 2*dy));
-}
-
-
-void Stabilizer::estimateMotionsAndTrimRatio()
-{
- log_->print("estimating motions and trim ratio");
-
- Size size;
- Mat prevFrame, frame;
- int frameCount = 0;
-
- while (!(frame = frameSource_->nextFrame()).empty())
- {
- if (frameCount > 0)
- motions_.push_back(motionEstimator_->estimate(prevFrame, frame));
- else
- size = frame.size();
- prevFrame = frame;
- frameCount++;
-
- log_->print(".");
- }
-
- radius_ = motionFilter_->radius();
- for (int i = 0; i < radius_; ++i)
- motions_.push_back(Mat::eye(3, 3, CV_32F));
- log_->print("\n");
-
- trimRatio_ = 0;
- for (int i = 0; i < frameCount; ++i)
- {
- Mat S = motionFilter_->apply(i, motions_);
- trimRatio_ = std::max(trimRatio_, estimateOptimalTrimRatio(S, size));
- stabilizationMotions_.push_back(S);
- }
-
- log_->print("estimated trim ratio: %f\n", static_cast<double>(trimRatio_));
}
-void Stabilizer::processFirstFrame(Mat &frame)
+void StabilizerBase::setUp(int cacheSize, const Mat &frame)
{
- log_->print("processing frames");
-
- frameSize_ = frame.size();
- frameMask_.create(frameSize_, CV_8U);
- frameMask_.setTo(255);
-
- radius_ = motionFilter_->radius();
- int cacheSize = 2*radius_ + 1;
-
- frames_.resize(cacheSize);
- stabilizedFrames_.resize(cacheSize);
- stabilizedMasks_.resize(cacheSize);
-
- if (!auxPassWasDone_)
- {
- motions_.resize(cacheSize);
- stabilizationMotions_.resize(cacheSize);
- }
-
- for (int i = -radius_; i < 0; ++i)
- {
- at(i, motions_) = Mat::eye(3, 3, CV_32F);
- at(i, frames_) = frame;
- }
-
- at(0, frames_) = frame;
-
- IInpainter *inpainter = static_cast<IInpainter*>(inpainter_);
+ InpainterBase *inpainter = static_cast<InpainterBase*>(inpainter_);
doInpainting_ = dynamic_cast<NullInpainter*>(inpainter) == 0;
if (doInpainting_)
{
inpainter_->setMotions(motions_);
inpainter_->setStabilizedFrames(stabilizedFrames_);
inpainter_->setStabilizationMotions(stabilizationMotions_);
+ inpainter_->update();
}
- IDeblurer *deblurer = static_cast<IDeblurer*>(deblurer_);
+ DeblurerBase *deblurer = static_cast<DeblurerBase*>(deblurer_);
doDeblurring_ = dynamic_cast<NullDeblurer*>(deblurer) == 0;
if (doDeblurring_)
{
deblurer_->setFrames(frames_);
deblurer_->setMotions(motions_);
deblurer_->setBlurrinessRates(blurrinessRates_);
+ deblurer_->update();
}
+
+ log_->print("processing frames");
+}
+
+
+Mat StabilizerBase::nextStabilizedFrame()
+{
+ if (curStabilizedPos_ == curPos_ && curStabilizedPos_ != -1)
+ return Mat(); // we've processed all frames already
+
+ bool processed;
+ do processed = doOneIteration();
+ while (processed && curStabilizedPos_ == -1);
+
+ if (curStabilizedPos_ == -1)
+ return Mat(); // frame source is empty
+
+ const Mat &stabilizedFrame = at(curStabilizedPos_, stabilizedFrames_);
+ int dx = static_cast<int>(floor(trimRatio_ * stabilizedFrame.cols));
+ int dy = static_cast<int>(floor(trimRatio_ * stabilizedFrame.rows));
+ return stabilizedFrame(Rect(dx, dy, stabilizedFrame.cols - 2*dx, stabilizedFrame.rows - 2*dy));
}
-bool Stabilizer::processNextFrame()
+bool StabilizerBase::doOneIteration()
{
Mat frame = frameSource_->nextFrame();
if (!frame.empty())
if (doDeblurring_)
at(curPos_, blurrinessRates_) = calcBlurriness(frame);
- if (!auxPassWasDone_)
- {
- Mat motionPrevToCur = motionEstimator_->estimate(
- at(curPos_ - 1, frames_), at(curPos_, frames_));
- at(curPos_ - 1, motions_) = motionPrevToCur;
- }
+ estimateMotion();
if (curPos_ >= radius_)
{
curStabilizedPos_ = curPos_ - radius_;
- stabilizeFrame(curStabilizedPos_);
+ stabilizeFrame();
}
}
else
- processFirstFrame(frame);
+ setUp(frame);
log_->print(".");
return true;
curStabilizedPos_++;
at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
at(curStabilizedPos_ + radius_ - 1, motions_) = at(curPos_ - 1, motions_);
- stabilizeFrame(curStabilizedPos_);
+ stabilizeFrame();
log_->print(".");
return true;
}
-void Stabilizer::stabilizeFrame(int idx)
+void StabilizerBase::stabilizeFrame(const Mat &stabilizationMotion)
{
- Mat stabMotion;
- if (!auxPassWasDone_)
- stabMotion = motionFilter_->apply(idx, motions_);
+ Mat stabilizationMotion_;
+ if (doCorrectionForInclusion_)
+ stabilizationMotion_ = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
else
- stabMotion = at(idx, stabilizationMotions_);
-
- if (inclusionConstraint_ && !mustEstimateTrimRatio_)
- stabMotion = ensureInclusionConstraint(stabMotion, frameSize_, trimRatio_);
+ stabilizationMotion_ = stabilizationMotion.clone();
- at(idx, stabilizationMotions_) = stabMotion;
+ at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion_;
if (doDeblurring_)
{
- at(idx, frames_).copyTo(preProcessedFrame_);
- deblurer_->deblur(idx, preProcessedFrame_);
+ at(curStabilizedPos_, frames_).copyTo(preProcessedFrame_);
+ deblurer_->deblur(curStabilizedPos_, preProcessedFrame_);
}
else
- preProcessedFrame_ = at(idx, frames_);
+ preProcessedFrame_ = at(curStabilizedPos_, frames_);
// apply stabilization transformation
warpAffine(
- preProcessedFrame_, at(idx, stabilizedFrames_), stabMotion(Rect(0,0,3,2)),
- frameSize_, INTER_LINEAR, borderMode_);
+ preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
+ stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_LINEAR, borderMode_);
if (doInpainting_)
{
warpAffine(
- frameMask_, at(idx, stabilizedMasks_), stabMotion(Rect(0,0,3,2)), frameSize_,
- INTER_NEAREST);
- erode(at(idx, stabilizedMasks_), at(idx, stabilizedMasks_), Mat());
- at(idx, stabilizedMasks_).copyTo(inpaintingMask_);
- inpainter_->inpaint(idx, at(idx, stabilizedFrames_), inpaintingMask_);
+ frameMask_, at(curStabilizedPos_, stabilizedMasks_),
+ stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_NEAREST);
+
+ erode(at(curStabilizedPos_, stabilizedMasks_), at(curStabilizedPos_, stabilizedMasks_),
+ Mat());
+
+ at(curStabilizedPos_, stabilizedMasks_).copyTo(inpaintingMask_);
+
+ inpainter_->inpaint(
+ curStabilizedPos_, at(curStabilizedPos_, stabilizedFrames_), inpaintingMask_);
}
}
+
+OnePassStabilizer::OnePassStabilizer()
+{
+ setMotionFilter(new GaussianMotionFilter());
+ resetImpl();
+}
+
+
+void OnePassStabilizer::resetImpl()
+{
+ curPos_ = -1;
+ curStabilizedPos_ = -1;
+ frames_.clear();
+ motions_.clear();
+ stabilizedFrames_.clear();
+ stabilizationMotions_.clear();
+ doDeblurring_ = false;
+ doInpainting_ = false;
+}
+
+
+void OnePassStabilizer::setUp(Mat &firstFrame)
+{
+ frameSize_ = firstFrame.size();
+ frameMask_.create(frameSize_, CV_8U);
+ frameMask_.setTo(255);
+
+ int cacheSize = 2*radius_ + 1;
+
+ frames_.resize(cacheSize);
+ stabilizedFrames_.resize(cacheSize);
+ stabilizedMasks_.resize(cacheSize);
+ motions_.resize(cacheSize);
+ stabilizationMotions_.resize(cacheSize);
+
+ for (int i = -radius_; i < 0; ++i)
+ {
+ at(i, motions_) = Mat::eye(3, 3, CV_32F);
+ at(i, frames_) = firstFrame;
+ }
+
+ at(0, frames_) = firstFrame;
+
+ motionFilter_->setRadius(radius_);
+ motionFilter_->update();
+
+ StabilizerBase::setUp(cacheSize, firstFrame);
+}
+
+
+void OnePassStabilizer::estimateMotion()
+{
+ at(curPos_ - 1, motions_) = motionEstimator_->estimate(
+ at(curPos_ - 1, frames_), at(curPos_, frames_));
+}
+
+
+void OnePassStabilizer::stabilizeFrame()
+{
+ Mat stabilizationMotion = motionFilter_->stabilize(curStabilizedPos_, &motions_[0], motions_.size());
+ StabilizerBase::stabilizeFrame(stabilizationMotion);
+}
+
+
+TwoPassStabilizer::TwoPassStabilizer()
+{
+ setMotionStabilizer(new GaussianMotionFilter());
+ setEstimateTrimRatio(true);
+ resetImpl();
+}
+
+
+Mat TwoPassStabilizer::nextFrame()
+{
+ runPrePassIfNecessary();
+ return StabilizerBase::nextStabilizedFrame();
+}
+
+
+void TwoPassStabilizer::resetImpl()
+{
+ isPrePassDone_ = false;
+ frameCount_ = 0;
+ curPos_ = -1;
+ curStabilizedPos_ = -1;
+ frames_.clear();
+ motions_.clear();
+ stabilizedFrames_.clear();
+ stabilizationMotions_.clear();
+ doDeblurring_ = false;
+ doInpainting_ = false;
+}
+
+
+void TwoPassStabilizer::runPrePassIfNecessary()
+{
+ if (!isPrePassDone_)
+ {
+ log_->print("first pass: estimating motions");
+
+ Mat prevFrame, frame;
+
+ while (!(frame = frameSource_->nextFrame()).empty())
+ {
+ if (frameCount_ > 0)
+ motions_.push_back(motionEstimator_->estimate(prevFrame, frame));
+ else
+ {
+ frameSize_ = frame.size();
+ frameMask_.create(frameSize_, CV_8U);
+ frameMask_.setTo(255);
+ }
+
+ prevFrame = frame;
+ frameCount_++;
+
+ log_->print(".");
+ }
+
+ for (int i = 0; i < radius_; ++i)
+ motions_.push_back(Mat::eye(3, 3, CV_32F));
+ log_->print("\n");
+
+ IMotionStabilizer *motionStabilizer = static_cast<IMotionStabilizer*>(motionStabilizer_);
+ MotionFilterBase *motionFilterBase = dynamic_cast<MotionFilterBase*>(motionStabilizer);
+ if (motionFilterBase)
+ {
+ motionFilterBase->setRadius(radius_);
+ motionFilterBase->update();
+ }
+
+ stabilizationMotions_.resize(frameCount_);
+ motionStabilizer_->stabilize(&motions_[0], frameCount_, &stabilizationMotions_[0]);
+
+ if (mustEstTrimRatio_)
+ {
+ trimRatio_ = 0;
+ for (int i = 0; i < frameCount_; ++i)
+ {
+ Mat S = stabilizationMotions_[i];
+ trimRatio_ = std::max(trimRatio_, estimateOptimalTrimRatio(S, frameSize_));
+ }
+ log_->print("estimated trim ratio: %f\n", static_cast<double>(trimRatio_));
+ }
+
+ isPrePassDone_ = true;
+ frameSource_->reset();
+ }
+}
+
+
+void TwoPassStabilizer::setUp(Mat &firstFrame)
+{
+ int cacheSize = 2*radius_ + 1;
+
+ frames_.resize(cacheSize);
+ stabilizedFrames_.resize(cacheSize);
+ stabilizedMasks_.resize(cacheSize);
+
+ for (int i = -radius_; i <= 0; ++i)
+ at(i, frames_) = firstFrame;
+
+ StabilizerBase::setUp(cacheSize, firstFrame);
+}
+
+
+void TwoPassStabilizer::stabilizeFrame()
+{
+ StabilizerBase::stabilizeFrame(stabilizationMotions_[curStabilizedPos_]);
+}
+
} // namespace videostab
} // namespace cv
using namespace cv;
using namespace cv::videostab;
-Ptr<Stabilizer> stabilizer;
+Ptr<IFrameSource> stabilizedFrames;
double outputFps;
string outputPath;
bool quietMode;
VideoWriter writer;
Mat stabilizedFrame;
- while (!(stabilizedFrame = stabilizer->nextFrame()).empty())
+ while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty())
{
if (!outputPath.empty())
{
" Do color inpainting. The defailt is no.\n"
" --color-inpaint-radius=<float_number>\n"
" Set color inpainting radius (for ns and telea options only).\n\n"
- " -o, --output=<file_path>\n"
+ " -o, --output=(no|<file_path>)\n"
" Set output file path explicitely. The default is stabilized.avi.\n"
" --fps=<int_number>\n"
" Set output video FPS explicitely. By default the source FPS is used.\n"
{
printHelp();
return 0;
+ }
+
+ StabilizerBase *stabilizer;
+ GaussianMotionFilter *motionFilter = 0;
+
+ if (!cmd.get<string>("stdev").empty())
+ {
+ motionFilter = new GaussianMotionFilter();
+ motionFilter->setStdev(cmd.get<float>("stdev"));
}
- stabilizer = new Stabilizer();
+ bool isTwoPass = cmd.get<string>("est-trim") == "yes";
+
+ if (isTwoPass)
+ {
+ TwoPassStabilizer *twoPassStabilizer = new TwoPassStabilizer();
+ if (!cmd.get<string>("est-trim").empty())
+ twoPassStabilizer->setEstimateTrimRatio(cmd.get<string>("est-trim") == "yes");
+ if (motionFilter)
+ twoPassStabilizer->setMotionStabilizer(motionFilter);
+ stabilizer = twoPassStabilizer;
+ }
+ else
+ {
+ OnePassStabilizer *onePassStabilizer= new OnePassStabilizer();
+ if (motionFilter)
+ onePassStabilizer->setMotionFilter(motionFilter);
+ stabilizer = onePassStabilizer;
+ }
string inputPath = cmd.get<string>("1");
if (inputPath.empty())
stabilizer->setMotionEstimator(motionEstimator);
- int smoothRadius = -1;
- float smoothStdev = -1;
if (!cmd.get<string>("radius").empty())
- smoothRadius = cmd.get<int>("radius");
- if (!cmd.get<string>("stdev").empty())
- smoothStdev = cmd.get<float>("stdev");
- if (smoothRadius > 0 && smoothStdev > 0)
- stabilizer->setMotionFilter(new GaussianMotionFilter(smoothRadius, smoothStdev));
- else if (smoothRadius > 0 && smoothStdev < 0)
- stabilizer->setMotionFilter(new GaussianMotionFilter(smoothRadius, sqrt(static_cast<float>(smoothRadius))));
+ stabilizer->setRadius(cmd.get<int>("radius"));
if (cmd.get<string>("deblur") == "yes")
{
stabilizer->setDeblurer(deblurer);
}
- if (!cmd.get<string>("est-trim").empty())
- stabilizer->setEstimateTrimRatio(cmd.get<string>("est-trim") == "yes");
-
if (!cmd.get<string>("trim-ratio").empty())
stabilizer->setTrimRatio(cmd.get<float>("trim-ratio"));
if (!cmd.get<string>("incl-constr").empty())
- stabilizer->setInclusionConstraint(cmd.get<string>("incl-constr") == "yes");
+ stabilizer->setCorrectionForInclusion(cmd.get<string>("incl-constr") == "yes");
if (cmd.get<string>("border-mode") == "reflect")
stabilizer->setBorderMode(BORDER_REFLECT);
stabilizer->setLog(new LogToStdout());
- outputPath = cmd.get<string>("output");
+ outputPath = cmd.get<string>("output") != "no" ? cmd.get<string>("output") : "";
if (!cmd.get<string>("fps").empty())
outputFps = cmd.get<double>("fps");
quietMode = cmd.get<bool>("quiet");
- // run video processing
+ stabilizedFrames = dynamic_cast<IFrameSource*>(stabilizer);
+
run();
}
catch (const exception &e)
{
cout << "error: " << e.what() << endl;
- stabilizer.release();
+ stabilizedFrames.release();
return -1;
}
- stabilizer.release();
+ stabilizedFrames.release();
return 0;
}