Split stabilizer into OnePassStabilizer and TwoPassStabilizer
This commit is contained in:
parent
6708869425
commit
984583981c
@ -53,24 +53,26 @@ namespace videostab
|
|||||||
|
|
||||||
CV_EXPORTS float calcBlurriness(const Mat &frame);
|
CV_EXPORTS float calcBlurriness(const Mat &frame);
|
||||||
|
|
||||||
class CV_EXPORTS IDeblurer
|
class CV_EXPORTS DeblurerBase
|
||||||
{
|
{
|
||||||
public:
|
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; }
|
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; }
|
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; }
|
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; }
|
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;
|
virtual void deblur(int idx, Mat &frame) = 0;
|
||||||
|
|
||||||
@ -81,13 +83,13 @@ protected:
|
|||||||
const std::vector<float> *blurrinessRates_;
|
const std::vector<float> *blurrinessRates_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS NullDeblurer : public IDeblurer
|
class CV_EXPORTS NullDeblurer : public DeblurerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void deblur(int /*idx*/, Mat &/*frame*/) {}
|
virtual void deblur(int /*idx*/, Mat &/*frame*/) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS WeightingDeblurer : public IDeblurer
|
class CV_EXPORTS WeightingDeblurer : public DeblurerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WeightingDeblurer();
|
WeightingDeblurer();
|
||||||
|
@ -129,6 +129,8 @@ private:
|
|||||||
float minInlierRatio_;
|
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);
|
CV_EXPORTS Mat getMotion(int from, int to, const std::vector<Mat> &motions);
|
||||||
|
|
||||||
} // namespace videostab
|
} // namespace videostab
|
||||||
|
@ -54,29 +54,31 @@ namespace cv
|
|||||||
namespace videostab
|
namespace videostab
|
||||||
{
|
{
|
||||||
|
|
||||||
class CV_EXPORTS IInpainter
|
class CV_EXPORTS InpainterBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IInpainter()
|
InpainterBase()
|
||||||
: radius_(0), frames_(0), motions_(0),
|
: radius_(0), frames_(0), motions_(0),
|
||||||
stabilizedFrames_(0), stabilizationMotions_(0) {}
|
stabilizedFrames_(0), stabilizationMotions_(0) {}
|
||||||
|
|
||||||
virtual ~IInpainter() {}
|
virtual ~InpainterBase() {}
|
||||||
|
|
||||||
virtual void setRadius(int val) { radius_ = val; }
|
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; }
|
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; }
|
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; }
|
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; }
|
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;
|
virtual void inpaint(int idx, Mat &frame, Mat &mask) = 0;
|
||||||
|
|
||||||
@ -88,16 +90,16 @@ protected:
|
|||||||
const std::vector<Mat> *stabilizationMotions_;
|
const std::vector<Mat> *stabilizationMotions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS NullInpainter : public IInpainter
|
class CV_EXPORTS NullInpainter : public InpainterBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void inpaint(int /*idx*/, Mat &/*frame*/, Mat &/*mask*/) {}
|
virtual void inpaint(int /*idx*/, Mat &/*frame*/, Mat &/*mask*/) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS InpaintingPipeline : public IInpainter
|
class CV_EXPORTS InpaintingPipeline : public InpainterBase
|
||||||
{
|
{
|
||||||
public:
|
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(); }
|
bool empty() const { return inpainters_.empty(); }
|
||||||
|
|
||||||
virtual void setRadius(int val);
|
virtual void setRadius(int val);
|
||||||
@ -106,13 +108,15 @@ public:
|
|||||||
virtual void setStabilizedFrames(const std::vector<Mat> &val);
|
virtual void setStabilizedFrames(const std::vector<Mat> &val);
|
||||||
virtual void setStabilizationMotions(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);
|
virtual void inpaint(int idx, Mat &frame, Mat &mask);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Ptr<IInpainter> > inpainters_;
|
std::vector<Ptr<InpainterBase> > inpainters_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS ConsistentMosaicInpainter : public IInpainter
|
class CV_EXPORTS ConsistentMosaicInpainter : public InpainterBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConsistentMosaicInpainter();
|
ConsistentMosaicInpainter();
|
||||||
@ -126,7 +130,7 @@ private:
|
|||||||
float stdevThresh_;
|
float stdevThresh_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS MotionInpainter : public IInpainter
|
class CV_EXPORTS MotionInpainter : public InpainterBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MotionInpainter();
|
MotionInpainter();
|
||||||
@ -159,7 +163,7 @@ private:
|
|||||||
Mat_<uchar> flowMask_;
|
Mat_<uchar> flowMask_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS ColorAverageInpainter : public IInpainter
|
class CV_EXPORTS ColorAverageInpainter : public InpainterBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void inpaint(int idx, Mat &frame, Mat &mask);
|
virtual void inpaint(int idx, Mat &frame, Mat &mask);
|
||||||
@ -168,7 +172,7 @@ private:
|
|||||||
FastMarchingMethod fmm_;
|
FastMarchingMethod fmm_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS ColorInpainter : public IInpainter
|
class CV_EXPORTS ColorInpainter : public InpainterBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ColorInpainter(int method = INPAINT_TELEA, double radius = 2.)
|
ColorInpainter(int method = INPAINT_TELEA, double radius = 2.)
|
||||||
|
@ -51,23 +51,44 @@ namespace cv
|
|||||||
namespace videostab
|
namespace videostab
|
||||||
{
|
{
|
||||||
|
|
||||||
class CV_EXPORTS IMotionFilter
|
class CV_EXPORTS IMotionStabilizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IMotionFilter() {}
|
virtual void stabilize(const Mat *motions, int size, Mat *stabilizationMotions) const = 0;
|
||||||
virtual int radius() const = 0;
|
|
||||||
virtual Mat apply(int index, std::vector<Mat> &Ms) const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS GaussianMotionFilter : public IMotionFilter
|
class CV_EXPORTS MotionFilterBase : public IMotionStabilizer
|
||||||
{
|
{
|
||||||
public:
|
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 int radius() const { return radius_; }
|
||||||
virtual Mat apply(int idx, std::vector<Mat> &motions) const;
|
|
||||||
|
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:
|
private:
|
||||||
int radius_;
|
float stdev_;
|
||||||
std::vector<float> weight_;
|
std::vector<float> weight_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,79 +58,126 @@ namespace cv
|
|||||||
namespace videostab
|
namespace videostab
|
||||||
{
|
{
|
||||||
|
|
||||||
class CV_EXPORTS Stabilizer : public IFrameSource
|
class CV_EXPORTS StabilizerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Stabilizer();
|
virtual ~StabilizerBase() {}
|
||||||
|
|
||||||
void setLog(Ptr<ILog> log) { log_ = log; }
|
void setLog(Ptr<ILog> log) { log_ = log; }
|
||||||
Ptr<ILog> log() const { return 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_; }
|
Ptr<IFrameSource> frameSource() const { return frameSource_; }
|
||||||
|
|
||||||
void setMotionEstimator(Ptr<IGlobalMotionEstimator> val) { motionEstimator_ = val; }
|
void setMotionEstimator(Ptr<IGlobalMotionEstimator> val) { motionEstimator_ = val; }
|
||||||
Ptr<IGlobalMotionEstimator> motionEstimator() const { return motionEstimator_; }
|
Ptr<IGlobalMotionEstimator> motionEstimator() const { return motionEstimator_; }
|
||||||
|
|
||||||
void setMotionFilter(Ptr<IMotionFilter> val) { motionFilter_ = val; reset(); }
|
void setDeblurer(Ptr<DeblurerBase> val) { deblurer_ = val; }
|
||||||
Ptr<IMotionFilter> motionFilter() const { return motionFilter_; }
|
Ptr<DeblurerBase> deblurrer() const { return deblurer_; }
|
||||||
|
|
||||||
void setDeblurer(Ptr<IDeblurer> val) { deblurer_ = val; reset(); }
|
void setTrimRatio(float val) { trimRatio_ = val; }
|
||||||
Ptr<IDeblurer> deblurrer() const { return deblurer_; }
|
|
||||||
|
|
||||||
void setEstimateTrimRatio(bool val) { mustEstimateTrimRatio_ = val; reset(); }
|
|
||||||
bool mustEstimateTrimRatio() const { return mustEstimateTrimRatio_; }
|
|
||||||
|
|
||||||
void setTrimRatio(float val) { trimRatio_ = val; reset(); }
|
|
||||||
float trimRatio() const { return trimRatio_; }
|
float trimRatio() const { return trimRatio_; }
|
||||||
|
|
||||||
void setInclusionConstraint(bool val) { inclusionConstraint_ = val; }
|
void setCorrectionForInclusion(bool val) { doCorrectionForInclusion_ = val; }
|
||||||
bool inclusionConstraint() const { return inclusionConstraint_; }
|
bool doCorrectionForInclusion() const { return doCorrectionForInclusion_; }
|
||||||
|
|
||||||
void setBorderMode(int val) { borderMode_ = val; }
|
void setBorderMode(int val) { borderMode_ = val; }
|
||||||
int borderMode() const { return borderMode_; }
|
int borderMode() const { return borderMode_; }
|
||||||
|
|
||||||
void setInpainter(Ptr<IInpainter> val) { inpainter_ = val; reset(); }
|
void setInpainter(Ptr<InpainterBase> val) { inpainter_ = val; }
|
||||||
Ptr<IInpainter> inpainter() const { return inpainter_; }
|
Ptr<InpainterBase> inpainter() const { return inpainter_; }
|
||||||
|
|
||||||
virtual void reset();
|
protected:
|
||||||
virtual Mat nextFrame();
|
StabilizerBase();
|
||||||
|
|
||||||
private:
|
void setUp(int cacheSize, const Mat &frame);
|
||||||
void estimateMotionsAndTrimRatio();
|
Mat nextStabilizedFrame();
|
||||||
void processFirstFrame(Mat &frame);
|
bool doOneIteration();
|
||||||
bool processNextFrame();
|
void stabilizeFrame(const Mat &stabilizationMotion);
|
||||||
void stabilizeFrame(int idx);
|
|
||||||
|
|
||||||
|
virtual void setUp(Mat &firstFrame) = 0;
|
||||||
|
virtual void stabilizeFrame() = 0;
|
||||||
|
virtual void estimateMotion() = 0;
|
||||||
|
|
||||||
|
Ptr<ILog> log_;
|
||||||
Ptr<IFrameSource> frameSource_;
|
Ptr<IFrameSource> frameSource_;
|
||||||
Ptr<IGlobalMotionEstimator> motionEstimator_;
|
Ptr<IGlobalMotionEstimator> motionEstimator_;
|
||||||
Ptr<IMotionFilter> motionFilter_;
|
Ptr<DeblurerBase> deblurer_;
|
||||||
Ptr<IDeblurer> deblurer_;
|
Ptr<InpainterBase> inpainter_;
|
||||||
Ptr<IInpainter> inpainter_;
|
int radius_;
|
||||||
bool mustEstimateTrimRatio_;
|
|
||||||
float trimRatio_;
|
float trimRatio_;
|
||||||
bool inclusionConstraint_;
|
bool doCorrectionForInclusion_;
|
||||||
int borderMode_;
|
int borderMode_;
|
||||||
Ptr<ILog> log_;
|
|
||||||
|
|
||||||
Size frameSize_;
|
Size frameSize_;
|
||||||
Mat frameMask_;
|
Mat frameMask_;
|
||||||
int radius_;
|
|
||||||
int curPos_;
|
int curPos_;
|
||||||
int curStabilizedPos_;
|
int curStabilizedPos_;
|
||||||
bool auxPassWasDone_;
|
|
||||||
bool doDeblurring_;
|
bool doDeblurring_;
|
||||||
Mat preProcessedFrame_;
|
Mat preProcessedFrame_;
|
||||||
bool doInpainting_;
|
bool doInpainting_;
|
||||||
Mat inpaintingMask_;
|
Mat inpaintingMask_;
|
||||||
std::vector<Mat> frames_;
|
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<float> blurrinessRates_;
|
||||||
std::vector<Mat> stabilizedFrames_;
|
std::vector<Mat> stabilizedFrames_;
|
||||||
std::vector<Mat> stabilizedMasks_;
|
std::vector<Mat> stabilizedMasks_;
|
||||||
std::vector<Mat> stabilizationMotions_;
|
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 videostab
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
|
||||||
|
@ -296,22 +296,28 @@ Mat PyrLkRobustMotionEstimator::estimate(const Mat &frame0, const Mat &frame1)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
Mat M = Mat::eye(3, 3, CV_32F);
|
||||||
if (to > from)
|
if (to > from)
|
||||||
{
|
{
|
||||||
for (int i = from; i < to; ++i)
|
for (int i = from; i < to; ++i)
|
||||||
M = at(i, motions) * M;
|
M = at(i, motions, size) * M;
|
||||||
}
|
}
|
||||||
else if (from > to)
|
else if (from > to)
|
||||||
{
|
{
|
||||||
for (int i = to; i < from; ++i)
|
for (int i = to; i < from; ++i)
|
||||||
M = at(i, motions) * M;
|
M = at(i, motions, size) * M;
|
||||||
M = M.inv();
|
M = M.inv();
|
||||||
}
|
}
|
||||||
return M;
|
return M;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Mat getMotion(int from, int to, const vector<Mat> &motions)
|
||||||
|
{
|
||||||
|
return getMotion(from, to, &motions[0], motions.size());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace videostab
|
} // namespace videostab
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
@ -57,7 +57,7 @@ void InpaintingPipeline::setRadius(int val)
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < inpainters_.size(); ++i)
|
for (size_t i = 0; i < inpainters_.size(); ++i)
|
||||||
inpainters_[i]->setRadius(val);
|
inpainters_[i]->setRadius(val);
|
||||||
IInpainter::setRadius(val);
|
InpainterBase::setRadius(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ void InpaintingPipeline::setFrames(const vector<Mat> &val)
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < inpainters_.size(); ++i)
|
for (size_t i = 0; i < inpainters_.size(); ++i)
|
||||||
inpainters_[i]->setFrames(val);
|
inpainters_[i]->setFrames(val);
|
||||||
IInpainter::setFrames(val);
|
InpainterBase::setFrames(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ void InpaintingPipeline::setMotions(const vector<Mat> &val)
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < inpainters_.size(); ++i)
|
for (size_t i = 0; i < inpainters_.size(); ++i)
|
||||||
inpainters_[i]->setMotions(val);
|
inpainters_[i]->setMotions(val);
|
||||||
IInpainter::setMotions(val);
|
InpainterBase::setMotions(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ void InpaintingPipeline::setStabilizedFrames(const vector<Mat> &val)
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < inpainters_.size(); ++i)
|
for (size_t i = 0; i < inpainters_.size(); ++i)
|
||||||
inpainters_[i]->setStabilizedFrames(val);
|
inpainters_[i]->setStabilizedFrames(val);
|
||||||
IInpainter::setStabilizedFrames(val);
|
InpainterBase::setStabilizedFrames(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,7 +89,15 @@ void InpaintingPipeline::setStabilizationMotions(const vector<Mat> &val)
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < inpainters_.size(); ++i)
|
for (size_t i = 0; i < inpainters_.size(); ++i)
|
||||||
inpainters_[i]->setStabilizationMotions(val);
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,26 +51,34 @@ namespace cv
|
|||||||
namespace videostab
|
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;
|
float sum = 0;
|
||||||
weight_.resize(2*radius_ + 1);
|
weight_.resize(2*radius_ + 1);
|
||||||
for (int i = -radius_; i <= radius_; ++i)
|
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)
|
for (int i = -radius_; i <= radius_; ++i)
|
||||||
weight_[radius_ + i] /= sum;
|
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());
|
Mat res = Mat::zeros(cur.size(), cur.type());
|
||||||
float sum = 0.f;
|
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);
|
res += weight_[radius_ + i - index] * getMotion(index, i, motions, size);
|
||||||
sum += weight_[radius_ + i - idx];
|
sum += weight_[radius_ + i - index];
|
||||||
}
|
}
|
||||||
return res / sum;
|
return res / sum;
|
||||||
}
|
}
|
||||||
|
@ -62,9 +62,19 @@ inline float intensity(const cv::Point3_<uchar> &bgr)
|
|||||||
return 0.3f*bgr.x + 0.59f*bgr.y + 0.11f*bgr.z;
|
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)
|
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)
|
template <typename T> inline const T& at(int index, const std::vector<T> &items)
|
||||||
|
@ -50,130 +50,23 @@ namespace cv
|
|||||||
namespace videostab
|
namespace videostab
|
||||||
{
|
{
|
||||||
|
|
||||||
Stabilizer::Stabilizer()
|
StabilizerBase::StabilizerBase()
|
||||||
{
|
{
|
||||||
|
setLog(new NullLog());
|
||||||
setFrameSource(new NullFrameSource());
|
setFrameSource(new NullFrameSource());
|
||||||
setMotionEstimator(new PyrLkRobustMotionEstimator());
|
setMotionEstimator(new PyrLkRobustMotionEstimator());
|
||||||
setMotionFilter(new GaussianMotionFilter(15, sqrt(15.f)));
|
|
||||||
setDeblurer(new NullDeblurer());
|
setDeblurer(new NullDeblurer());
|
||||||
setInpainter(new NullInpainter());
|
setInpainter(new NullInpainter());
|
||||||
setEstimateTrimRatio(true);
|
setRadius(15);
|
||||||
setTrimRatio(0);
|
setTrimRatio(0);
|
||||||
setInclusionConstraint(false);
|
setCorrectionForInclusion(false);
|
||||||
setBorderMode(BORDER_REPLICATE);
|
setBorderMode(BORDER_REPLICATE);
|
||||||
setLog(new NullLog());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Stabilizer::reset()
|
void StabilizerBase::setUp(int cacheSize, const Mat &frame)
|
||||||
{
|
{
|
||||||
radius_ = 0;
|
InpainterBase *inpainter = static_cast<InpainterBase*>(inpainter_);
|
||||||
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)
|
|
||||||
{
|
|
||||||
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_);
|
|
||||||
doInpainting_ = dynamic_cast<NullInpainter*>(inpainter) == 0;
|
doInpainting_ = dynamic_cast<NullInpainter*>(inpainter) == 0;
|
||||||
if (doInpainting_)
|
if (doInpainting_)
|
||||||
{
|
{
|
||||||
@ -182,9 +75,10 @@ void Stabilizer::processFirstFrame(Mat &frame)
|
|||||||
inpainter_->setMotions(motions_);
|
inpainter_->setMotions(motions_);
|
||||||
inpainter_->setStabilizedFrames(stabilizedFrames_);
|
inpainter_->setStabilizedFrames(stabilizedFrames_);
|
||||||
inpainter_->setStabilizationMotions(stabilizationMotions_);
|
inpainter_->setStabilizationMotions(stabilizationMotions_);
|
||||||
|
inpainter_->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
IDeblurer *deblurer = static_cast<IDeblurer*>(deblurer_);
|
DeblurerBase *deblurer = static_cast<DeblurerBase*>(deblurer_);
|
||||||
doDeblurring_ = dynamic_cast<NullDeblurer*>(deblurer) == 0;
|
doDeblurring_ = dynamic_cast<NullDeblurer*>(deblurer) == 0;
|
||||||
if (doDeblurring_)
|
if (doDeblurring_)
|
||||||
{
|
{
|
||||||
@ -196,11 +90,33 @@ void Stabilizer::processFirstFrame(Mat &frame)
|
|||||||
deblurer_->setFrames(frames_);
|
deblurer_->setFrames(frames_);
|
||||||
deblurer_->setMotions(motions_);
|
deblurer_->setMotions(motions_);
|
||||||
deblurer_->setBlurrinessRates(blurrinessRates_);
|
deblurer_->setBlurrinessRates(blurrinessRates_);
|
||||||
|
deblurer_->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_->print("processing frames");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Stabilizer::processNextFrame()
|
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 StabilizerBase::doOneIteration()
|
||||||
{
|
{
|
||||||
Mat frame = frameSource_->nextFrame();
|
Mat frame = frameSource_->nextFrame();
|
||||||
if (!frame.empty())
|
if (!frame.empty())
|
||||||
@ -214,21 +130,16 @@ bool Stabilizer::processNextFrame()
|
|||||||
if (doDeblurring_)
|
if (doDeblurring_)
|
||||||
at(curPos_, blurrinessRates_) = calcBlurriness(frame);
|
at(curPos_, blurrinessRates_) = calcBlurriness(frame);
|
||||||
|
|
||||||
if (!auxPassWasDone_)
|
estimateMotion();
|
||||||
{
|
|
||||||
Mat motionPrevToCur = motionEstimator_->estimate(
|
|
||||||
at(curPos_ - 1, frames_), at(curPos_, frames_));
|
|
||||||
at(curPos_ - 1, motions_) = motionPrevToCur;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curPos_ >= radius_)
|
if (curPos_ >= radius_)
|
||||||
{
|
{
|
||||||
curStabilizedPos_ = curPos_ - radius_;
|
curStabilizedPos_ = curPos_ - radius_;
|
||||||
stabilizeFrame(curStabilizedPos_);
|
stabilizeFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
processFirstFrame(frame);
|
setUp(frame);
|
||||||
|
|
||||||
log_->print(".");
|
log_->print(".");
|
||||||
return true;
|
return true;
|
||||||
@ -239,7 +150,7 @@ bool Stabilizer::processNextFrame()
|
|||||||
curStabilizedPos_++;
|
curStabilizedPos_++;
|
||||||
at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
|
at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
|
||||||
at(curStabilizedPos_ + radius_ - 1, motions_) = at(curPos_ - 1, motions_);
|
at(curStabilizedPos_ + radius_ - 1, motions_) = at(curPos_ - 1, motions_);
|
||||||
stabilizeFrame(curStabilizedPos_);
|
stabilizeFrame();
|
||||||
|
|
||||||
log_->print(".");
|
log_->print(".");
|
||||||
return true;
|
return true;
|
||||||
@ -249,42 +160,215 @@ bool Stabilizer::processNextFrame()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Stabilizer::stabilizeFrame(int idx)
|
void StabilizerBase::stabilizeFrame(const Mat &stabilizationMotion)
|
||||||
{
|
{
|
||||||
Mat stabMotion;
|
Mat stabilizationMotion_;
|
||||||
if (!auxPassWasDone_)
|
if (doCorrectionForInclusion_)
|
||||||
stabMotion = motionFilter_->apply(idx, motions_);
|
stabilizationMotion_ = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
|
||||||
else
|
else
|
||||||
stabMotion = at(idx, stabilizationMotions_);
|
stabilizationMotion_ = stabilizationMotion.clone();
|
||||||
|
|
||||||
if (inclusionConstraint_ && !mustEstimateTrimRatio_)
|
at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion_;
|
||||||
stabMotion = ensureInclusionConstraint(stabMotion, frameSize_, trimRatio_);
|
|
||||||
|
|
||||||
at(idx, stabilizationMotions_) = stabMotion;
|
|
||||||
|
|
||||||
if (doDeblurring_)
|
if (doDeblurring_)
|
||||||
{
|
{
|
||||||
at(idx, frames_).copyTo(preProcessedFrame_);
|
at(curStabilizedPos_, frames_).copyTo(preProcessedFrame_);
|
||||||
deblurer_->deblur(idx, preProcessedFrame_);
|
deblurer_->deblur(curStabilizedPos_, preProcessedFrame_);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
preProcessedFrame_ = at(idx, frames_);
|
preProcessedFrame_ = at(curStabilizedPos_, frames_);
|
||||||
|
|
||||||
// apply stabilization transformation
|
// apply stabilization transformation
|
||||||
warpAffine(
|
warpAffine(
|
||||||
preProcessedFrame_, at(idx, stabilizedFrames_), stabMotion(Rect(0,0,3,2)),
|
preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
|
||||||
frameSize_, INTER_LINEAR, borderMode_);
|
stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_LINEAR, borderMode_);
|
||||||
|
|
||||||
if (doInpainting_)
|
if (doInpainting_)
|
||||||
{
|
{
|
||||||
warpAffine(
|
warpAffine(
|
||||||
frameMask_, at(idx, stabilizedMasks_), stabMotion(Rect(0,0,3,2)), frameSize_,
|
frameMask_, at(curStabilizedPos_, stabilizedMasks_),
|
||||||
INTER_NEAREST);
|
stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_NEAREST);
|
||||||
erode(at(idx, stabilizedMasks_), at(idx, stabilizedMasks_), Mat());
|
|
||||||
at(idx, stabilizedMasks_).copyTo(inpaintingMask_);
|
erode(at(curStabilizedPos_, stabilizedMasks_), at(curStabilizedPos_, stabilizedMasks_),
|
||||||
inpainter_->inpaint(idx, at(idx, stabilizedFrames_), inpaintingMask_);
|
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 videostab
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
@ -12,7 +12,7 @@ using namespace std;
|
|||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace cv::videostab;
|
using namespace cv::videostab;
|
||||||
|
|
||||||
Ptr<Stabilizer> stabilizer;
|
Ptr<IFrameSource> stabilizedFrames;
|
||||||
double outputFps;
|
double outputFps;
|
||||||
string outputPath;
|
string outputPath;
|
||||||
bool quietMode;
|
bool quietMode;
|
||||||
@ -25,7 +25,7 @@ void run()
|
|||||||
VideoWriter writer;
|
VideoWriter writer;
|
||||||
Mat stabilizedFrame;
|
Mat stabilizedFrame;
|
||||||
|
|
||||||
while (!(stabilizedFrame = stabilizer->nextFrame()).empty())
|
while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty())
|
||||||
{
|
{
|
||||||
if (!outputPath.empty())
|
if (!outputPath.empty())
|
||||||
{
|
{
|
||||||
@ -87,7 +87,7 @@ void printHelp()
|
|||||||
" Do color inpainting. The defailt is no.\n"
|
" Do color inpainting. The defailt is no.\n"
|
||||||
" --color-inpaint-radius=<float_number>\n"
|
" --color-inpaint-radius=<float_number>\n"
|
||||||
" Set color inpainting radius (for ns and telea options only).\n\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"
|
" Set output file path explicitely. The default is stabilized.avi.\n"
|
||||||
" --fps=<int_number>\n"
|
" --fps=<int_number>\n"
|
||||||
" Set output video FPS explicitely. By default the source FPS is used.\n"
|
" Set output video FPS explicitely. By default the source FPS is used.\n"
|
||||||
@ -134,9 +134,35 @@ int main(int argc, const char **argv)
|
|||||||
{
|
{
|
||||||
printHelp();
|
printHelp();
|
||||||
return 0;
|
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");
|
string inputPath = cmd.get<string>("1");
|
||||||
if (inputPath.empty())
|
if (inputPath.empty())
|
||||||
@ -169,16 +195,8 @@ int main(int argc, const char **argv)
|
|||||||
|
|
||||||
stabilizer->setMotionEstimator(motionEstimator);
|
stabilizer->setMotionEstimator(motionEstimator);
|
||||||
|
|
||||||
int smoothRadius = -1;
|
|
||||||
float smoothStdev = -1;
|
|
||||||
if (!cmd.get<string>("radius").empty())
|
if (!cmd.get<string>("radius").empty())
|
||||||
smoothRadius = cmd.get<int>("radius");
|
stabilizer->setRadius(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))));
|
|
||||||
|
|
||||||
if (cmd.get<string>("deblur") == "yes")
|
if (cmd.get<string>("deblur") == "yes")
|
||||||
{
|
{
|
||||||
@ -188,14 +206,11 @@ int main(int argc, const char **argv)
|
|||||||
stabilizer->setDeblurer(deblurer);
|
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())
|
if (!cmd.get<string>("trim-ratio").empty())
|
||||||
stabilizer->setTrimRatio(cmd.get<float>("trim-ratio"));
|
stabilizer->setTrimRatio(cmd.get<float>("trim-ratio"));
|
||||||
|
|
||||||
if (!cmd.get<string>("incl-constr").empty())
|
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")
|
if (cmd.get<string>("border-mode") == "reflect")
|
||||||
stabilizer->setBorderMode(BORDER_REFLECT);
|
stabilizer->setBorderMode(BORDER_REFLECT);
|
||||||
@ -250,22 +265,23 @@ int main(int argc, const char **argv)
|
|||||||
|
|
||||||
stabilizer->setLog(new LogToStdout());
|
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())
|
if (!cmd.get<string>("fps").empty())
|
||||||
outputFps = cmd.get<double>("fps");
|
outputFps = cmd.get<double>("fps");
|
||||||
|
|
||||||
quietMode = cmd.get<bool>("quiet");
|
quietMode = cmd.get<bool>("quiet");
|
||||||
|
|
||||||
// run video processing
|
stabilizedFrames = dynamic_cast<IFrameSource*>(stabilizer);
|
||||||
|
|
||||||
run();
|
run();
|
||||||
}
|
}
|
||||||
catch (const exception &e)
|
catch (const exception &e)
|
||||||
{
|
{
|
||||||
cout << "error: " << e.what() << endl;
|
cout << "error: " << e.what() << endl;
|
||||||
stabilizer.release();
|
stabilizedFrames.release();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stabilizer.release();
|
stabilizedFrames.release();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user