Added support of homography estimation into videostab module
This commit is contained in:
parent
ecb1f0e288
commit
efa0717d01
@ -58,7 +58,9 @@ enum MotionModel
|
|||||||
TRANSLATION = 0,
|
TRANSLATION = 0,
|
||||||
TRANSLATION_AND_SCALE = 1,
|
TRANSLATION_AND_SCALE = 1,
|
||||||
LINEAR_SIMILARITY = 2,
|
LINEAR_SIMILARITY = 2,
|
||||||
AFFINE = 3
|
AFFINE = 3,
|
||||||
|
HOMOGRAPHY = 4,
|
||||||
|
UNKNOWN = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
CV_EXPORTS Mat estimateGlobalMotionLeastSquares(
|
CV_EXPORTS Mat estimateGlobalMotionLeastSquares(
|
||||||
@ -76,10 +78,11 @@ struct CV_EXPORTS RansacParams
|
|||||||
RansacParams(int size, float thresh, float eps, float prob)
|
RansacParams(int size, float thresh, float eps, float prob)
|
||||||
: size(size), thresh(thresh), eps(eps), prob(prob) {}
|
: size(size), thresh(thresh), eps(eps), prob(prob) {}
|
||||||
|
|
||||||
static RansacParams translationMotionStd() { return RansacParams(2, 0.5f, 0.5f, 0.99f); }
|
static RansacParams translation2dMotionStd() { return RansacParams(2, 0.5f, 0.5f, 0.99f); }
|
||||||
static RansacParams translationAndScale2dMotionStd() { return RansacParams(3, 0.5f, 0.5f, 0.99f); }
|
static RansacParams translationAndScale2dMotionStd() { return RansacParams(3, 0.5f, 0.5f, 0.99f); }
|
||||||
static RansacParams linearSimilarityMotionStd() { return RansacParams(4, 0.5f, 0.5f, 0.99f); }
|
static RansacParams linearSimilarity2dMotionStd() { return RansacParams(4, 0.5f, 0.5f, 0.99f); }
|
||||||
static RansacParams affine2dMotionStd() { return RansacParams(6, 0.5f, 0.5f, 0.99f); }
|
static RansacParams affine2dMotionStd() { return RansacParams(6, 0.5f, 0.5f, 0.99f); }
|
||||||
|
static RansacParams homography2dMotionStd() { return RansacParams(8, 0.5f, 0.5f, 0.99f); }
|
||||||
};
|
};
|
||||||
|
|
||||||
CV_EXPORTS Mat estimateGlobalMotionRobust(
|
CV_EXPORTS Mat estimateGlobalMotionRobust(
|
||||||
@ -87,14 +90,22 @@ CV_EXPORTS Mat estimateGlobalMotionRobust(
|
|||||||
int model = AFFINE, const RansacParams ¶ms = RansacParams::affine2dMotionStd(),
|
int model = AFFINE, const RansacParams ¶ms = RansacParams::affine2dMotionStd(),
|
||||||
float *rmse = 0, int *ninliers = 0);
|
float *rmse = 0, int *ninliers = 0);
|
||||||
|
|
||||||
class CV_EXPORTS IGlobalMotionEstimator
|
class CV_EXPORTS GlobalMotionEstimatorBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IGlobalMotionEstimator() {}
|
GlobalMotionEstimatorBase() : motionModel_(UNKNOWN) {}
|
||||||
|
virtual ~GlobalMotionEstimatorBase() {}
|
||||||
|
|
||||||
|
virtual void setMotionModel(MotionModel val) { motionModel_ = val; }
|
||||||
|
virtual MotionModel motionModel() const { return motionModel_; }
|
||||||
|
|
||||||
virtual Mat estimate(const Mat &frame0, const Mat &frame1) = 0;
|
virtual Mat estimate(const Mat &frame0, const Mat &frame1) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MotionModel motionModel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CV_EXPORTS PyrLkRobustMotionEstimator : public IGlobalMotionEstimator
|
class CV_EXPORTS PyrLkRobustMotionEstimator : public GlobalMotionEstimatorBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PyrLkRobustMotionEstimator();
|
PyrLkRobustMotionEstimator();
|
||||||
@ -105,9 +116,6 @@ public:
|
|||||||
void setOptFlowEstimator(Ptr<ISparseOptFlowEstimator> val) { optFlowEstimator_ = val; }
|
void setOptFlowEstimator(Ptr<ISparseOptFlowEstimator> val) { optFlowEstimator_ = val; }
|
||||||
Ptr<ISparseOptFlowEstimator> optFlowEstimator() const { return optFlowEstimator_; }
|
Ptr<ISparseOptFlowEstimator> optFlowEstimator() const { return optFlowEstimator_; }
|
||||||
|
|
||||||
void setMotionModel(MotionModel val) { motionModel_ = val; }
|
|
||||||
MotionModel motionModel() const { return motionModel_; }
|
|
||||||
|
|
||||||
void setRansacParams(const RansacParams &val) { ransacParams_ = val; }
|
void setRansacParams(const RansacParams &val) { ransacParams_ = val; }
|
||||||
RansacParams ransacParams() const { return ransacParams_; }
|
RansacParams ransacParams() const { return ransacParams_; }
|
||||||
|
|
||||||
@ -122,7 +130,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
Ptr<FeatureDetector> detector_;
|
Ptr<FeatureDetector> detector_;
|
||||||
Ptr<ISparseOptFlowEstimator> optFlowEstimator_;
|
Ptr<ISparseOptFlowEstimator> optFlowEstimator_;
|
||||||
MotionModel motionModel_;
|
|
||||||
RansacParams ransacParams_;
|
RansacParams ransacParams_;
|
||||||
std::vector<uchar> status_;
|
std::vector<uchar> status_;
|
||||||
std::vector<KeyPoint> keypointsPrev_;
|
std::vector<KeyPoint> keypointsPrev_;
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "opencv2/core/core.hpp"
|
#include "opencv2/core/core.hpp"
|
||||||
#include "opencv2/videostab/optical_flow.hpp"
|
#include "opencv2/videostab/optical_flow.hpp"
|
||||||
#include "opencv2/videostab/fast_marching.hpp"
|
#include "opencv2/videostab/fast_marching.hpp"
|
||||||
|
#include "opencv2/videostab/global_motion.hpp"
|
||||||
#include "opencv2/photo/photo.hpp"
|
#include "opencv2/photo/photo.hpp"
|
||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
@ -66,6 +67,9 @@ public:
|
|||||||
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 setMotionModel(MotionModel val) { motionModel_ = val; }
|
||||||
|
virtual MotionModel motionModel() const { return motionModel_; }
|
||||||
|
|
||||||
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,6 +86,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
int radius_;
|
int radius_;
|
||||||
|
MotionModel motionModel_;
|
||||||
const std::vector<Mat> *frames_;
|
const std::vector<Mat> *frames_;
|
||||||
const std::vector<Mat> *motions_;
|
const std::vector<Mat> *motions_;
|
||||||
const std::vector<Mat> *stabilizedFrames_;
|
const std::vector<Mat> *stabilizedFrames_;
|
||||||
@ -101,6 +106,7 @@ public:
|
|||||||
bool empty() const { return inpainters_.empty(); }
|
bool empty() const { return inpainters_.empty(); }
|
||||||
|
|
||||||
virtual void setRadius(int val);
|
virtual void setRadius(int val);
|
||||||
|
virtual void setMotionModel(MotionModel val);
|
||||||
virtual void setFrames(const std::vector<Mat> &val);
|
virtual void setFrames(const std::vector<Mat> &val);
|
||||||
virtual void setMotions(const std::vector<Mat> &val);
|
virtual void setMotions(const std::vector<Mat> &val);
|
||||||
virtual void setStabilizedFrames(const std::vector<Mat> &val);
|
virtual void setStabilizedFrames(const std::vector<Mat> &val);
|
||||||
|
@ -72,8 +72,8 @@ public:
|
|||||||
void setFrameSource(Ptr<IFrameSource> val) { frameSource_ = val; }
|
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<GlobalMotionEstimatorBase> val) { motionEstimator_ = val; }
|
||||||
Ptr<IGlobalMotionEstimator> motionEstimator() const { return motionEstimator_; }
|
Ptr<GlobalMotionEstimatorBase> motionEstimator() const { return motionEstimator_; }
|
||||||
|
|
||||||
void setDeblurer(Ptr<DeblurerBase> val) { deblurer_ = val; }
|
void setDeblurer(Ptr<DeblurerBase> val) { deblurer_ = val; }
|
||||||
Ptr<DeblurerBase> deblurrer() const { return deblurer_; }
|
Ptr<DeblurerBase> deblurrer() const { return deblurer_; }
|
||||||
@ -104,7 +104,7 @@ protected:
|
|||||||
|
|
||||||
Ptr<ILog> log_;
|
Ptr<ILog> log_;
|
||||||
Ptr<IFrameSource> frameSource_;
|
Ptr<IFrameSource> frameSource_;
|
||||||
Ptr<IGlobalMotionEstimator> motionEstimator_;
|
Ptr<GlobalMotionEstimatorBase> motionEstimator_;
|
||||||
Ptr<DeblurerBase> deblurer_;
|
Ptr<DeblurerBase> deblurer_;
|
||||||
Ptr<InpainterBase> inpainter_;
|
Ptr<InpainterBase> inpainter_;
|
||||||
int radius_;
|
int radius_;
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
//M*/
|
//M*/
|
||||||
|
|
||||||
#include "precomp.hpp"
|
#include "precomp.hpp"
|
||||||
#include "opencv2/highgui/highgui.hpp"
|
|
||||||
#include "opencv2/videostab/global_motion.hpp"
|
#include "opencv2/videostab/global_motion.hpp"
|
||||||
#include "opencv2/videostab/ring_buffer.hpp"
|
#include "opencv2/videostab/ring_buffer.hpp"
|
||||||
|
|
||||||
@ -324,8 +323,38 @@ Mat PyrLkRobustMotionEstimator::estimate(const Mat &frame0, const Mat &frame1)
|
|||||||
|
|
||||||
float rmse;
|
float rmse;
|
||||||
int ninliers;
|
int ninliers;
|
||||||
Mat M = estimateGlobalMotionRobust(
|
Mat_<float> M;
|
||||||
pointsPrevGood_, pointsGood_, motionModel_, ransacParams_, &rmse, &ninliers);
|
|
||||||
|
if (motionModel_ != HOMOGRAPHY)
|
||||||
|
M = estimateGlobalMotionRobust(
|
||||||
|
pointsPrevGood_, pointsGood_, motionModel_, ransacParams_, &rmse, &ninliers);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vector<uchar> mask;
|
||||||
|
M = findHomography(pointsPrevGood_, pointsGood_, CV_RANSAC, ransacParams_.thresh, mask);
|
||||||
|
|
||||||
|
ninliers = 0;
|
||||||
|
rmse = 0;
|
||||||
|
|
||||||
|
Point2d p0, p1;
|
||||||
|
float x, y, z;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pointsGood_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (mask[i])
|
||||||
|
{
|
||||||
|
p0 = pointsPrevGood_[i]; p1 = pointsGood_[i];
|
||||||
|
x = M(0,0)*p0.x + M(0,1)*p0.y + M(0,2);
|
||||||
|
y = M(1,0)*p0.x + M(1,1)*p0.y + M(1,2);
|
||||||
|
z = M(2,0)*p0.x + M(2,1)*p0.y + M(2,2);
|
||||||
|
x /= z; y /= z;
|
||||||
|
rmse += sqr(x - p1.x) + sqr(y - p1.y);
|
||||||
|
ninliers++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rmse = sqrt(rmse / static_cast<float>(ninliers));
|
||||||
|
}
|
||||||
|
|
||||||
if (rmse > maxRmse_ || static_cast<float>(ninliers) / pointsGood_.size() < minInlierRatio_)
|
if (rmse > maxRmse_ || static_cast<float>(ninliers) / pointsGood_.size() < minInlierRatio_)
|
||||||
M = Mat::eye(3, 3, CV_32F);
|
M = Mat::eye(3, 3, CV_32F);
|
||||||
|
@ -70,6 +70,14 @@ void InpaintingPipeline::setFrames(const vector<Mat> &val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InpaintingPipeline::setMotionModel(MotionModel val)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < inpainters_.size(); ++i)
|
||||||
|
inpainters_[i]->setMotionModel(val);
|
||||||
|
InpainterBase::setMotionModel(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InpaintingPipeline::setMotions(const vector<Mat> &val)
|
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)
|
||||||
@ -361,17 +369,34 @@ void MotionInpainter::inpaint(int idx, Mat &frame, Mat &mask)
|
|||||||
|
|
||||||
Mat motion1to0 = motions[radius_ + neighbor - idx].inv();
|
Mat motion1to0 = motions[radius_ + neighbor - idx].inv();
|
||||||
|
|
||||||
|
// warp frame
|
||||||
|
|
||||||
frame1_ = at(neighbor, *frames_);
|
frame1_ = at(neighbor, *frames_);
|
||||||
warpAffine(
|
|
||||||
frame1_, transformedFrame1_, motion1to0(Rect(0,0,3,2)), frame1_.size(),
|
if (motionModel_ != HOMOGRAPHY)
|
||||||
INTER_LINEAR, borderMode_);
|
warpAffine(
|
||||||
|
frame1_, transformedFrame1_, motion1to0(Rect(0,0,3,2)), frame1_.size(),
|
||||||
|
INTER_LINEAR, borderMode_);
|
||||||
|
else
|
||||||
|
warpPerspective(
|
||||||
|
frame1_, transformedFrame1_, motion1to0, frame1_.size(), INTER_LINEAR,
|
||||||
|
borderMode_);
|
||||||
|
|
||||||
cvtColor(transformedFrame1_, transformedGrayFrame1_, CV_BGR2GRAY);
|
cvtColor(transformedFrame1_, transformedGrayFrame1_, CV_BGR2GRAY);
|
||||||
|
|
||||||
warpAffine(
|
// warp mask
|
||||||
mask1_, transformedMask1_, motion1to0(Rect(0,0,3,2)), mask1_.size(),
|
|
||||||
INTER_NEAREST);
|
if (motionModel_ != HOMOGRAPHY)
|
||||||
|
warpAffine(
|
||||||
|
mask1_, transformedMask1_, motion1to0(Rect(0,0,3,2)), mask1_.size(),
|
||||||
|
INTER_NEAREST);
|
||||||
|
else
|
||||||
|
warpPerspective(mask1_, transformedMask1_, motion1to0, mask1_.size(), INTER_NEAREST);
|
||||||
|
|
||||||
erode(transformedMask1_, transformedMask1_, Mat());
|
erode(transformedMask1_, transformedMask1_, Mat());
|
||||||
|
|
||||||
|
// update flow
|
||||||
|
|
||||||
optFlowEstimator_->run(grayFrame_, transformedGrayFrame1_, flowX_, flowY_, flowErrors_);
|
optFlowEstimator_->run(grayFrame_, transformedGrayFrame1_, flowX_, flowY_, flowErrors_);
|
||||||
|
|
||||||
calcFlowMask(
|
calcFlowMask(
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "opencv2/imgproc/imgproc.hpp"
|
#include "opencv2/imgproc/imgproc.hpp"
|
||||||
#include "opencv2/video/video.hpp"
|
#include "opencv2/video/video.hpp"
|
||||||
#include "opencv2/features2d/features2d.hpp"
|
#include "opencv2/features2d/features2d.hpp"
|
||||||
|
#include "opencv2/calib3d/calib3d.hpp"
|
||||||
|
|
||||||
// some aux. functions
|
// some aux. functions
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ void StabilizerBase::setUp(int cacheSize, const Mat &frame)
|
|||||||
doInpainting_ = dynamic_cast<NullInpainter*>(inpainter) == 0;
|
doInpainting_ = dynamic_cast<NullInpainter*>(inpainter) == 0;
|
||||||
if (doInpainting_)
|
if (doInpainting_)
|
||||||
{
|
{
|
||||||
|
inpainter_->setMotionModel(motionEstimator_->motionModel());
|
||||||
inpainter_->setFrames(frames_);
|
inpainter_->setFrames(frames_);
|
||||||
inpainter_->setMotions(motions_);
|
inpainter_->setMotions(motions_);
|
||||||
inpainter_->setStabilizedFrames(stabilizedFrames_);
|
inpainter_->setStabilizedFrames(stabilizedFrames_);
|
||||||
@ -176,15 +177,26 @@ void StabilizerBase::stabilizeFrame(const Mat &stabilizationMotion)
|
|||||||
preProcessedFrame_ = at(curStabilizedPos_, frames_);
|
preProcessedFrame_ = at(curStabilizedPos_, frames_);
|
||||||
|
|
||||||
// apply stabilization transformation
|
// apply stabilization transformation
|
||||||
warpAffine(
|
|
||||||
preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
|
if (motionEstimator_->motionModel() != HOMOGRAPHY)
|
||||||
stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_LINEAR, borderMode_);
|
warpAffine(
|
||||||
|
preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
|
||||||
|
stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_LINEAR, borderMode_);
|
||||||
|
else
|
||||||
|
warpPerspective(
|
||||||
|
preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
|
||||||
|
stabilizationMotion_, frameSize_, INTER_LINEAR, borderMode_);
|
||||||
|
|
||||||
if (doInpainting_)
|
if (doInpainting_)
|
||||||
{
|
{
|
||||||
warpAffine(
|
if (motionEstimator_->motionModel() != HOMOGRAPHY)
|
||||||
frameMask_, at(curStabilizedPos_, stabilizedMasks_),
|
warpAffine(
|
||||||
stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_NEAREST);
|
frameMask_, at(curStabilizedPos_, stabilizedMasks_),
|
||||||
|
stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_NEAREST);
|
||||||
|
else
|
||||||
|
warpPerspective(
|
||||||
|
frameMask_, at(curStabilizedPos_, stabilizedMasks_),
|
||||||
|
stabilizationMotion_, frameSize_, INTER_NEAREST);
|
||||||
|
|
||||||
erode(at(curStabilizedPos_, stabilizedMasks_), at(curStabilizedPos_, stabilizedMasks_),
|
erode(at(curStabilizedPos_, stabilizedMasks_), at(curStabilizedPos_, stabilizedMasks_),
|
||||||
Mat());
|
Mat());
|
||||||
|
@ -29,7 +29,7 @@ void run();
|
|||||||
void saveMotionsIfNecessary();
|
void saveMotionsIfNecessary();
|
||||||
void printHelp();
|
void printHelp();
|
||||||
|
|
||||||
class GlobalMotionReader : public IGlobalMotionEstimator
|
class GlobalMotionReader : public GlobalMotionEstimatorBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GlobalMotionReader(string path)
|
GlobalMotionReader(string path)
|
||||||
@ -256,11 +256,11 @@ int main(int argc, const char **argv)
|
|||||||
{
|
{
|
||||||
RansacParams ransac;
|
RansacParams ransac;
|
||||||
PyrLkRobustMotionEstimator *est = new PyrLkRobustMotionEstimator();
|
PyrLkRobustMotionEstimator *est = new PyrLkRobustMotionEstimator();
|
||||||
Ptr<IGlobalMotionEstimator> est_(est);
|
Ptr<GlobalMotionEstimatorBase> est_(est);
|
||||||
if (arg("model") == "transl")
|
if (arg("model") == "transl")
|
||||||
{
|
{
|
||||||
est->setMotionModel(TRANSLATION);
|
est->setMotionModel(TRANSLATION);
|
||||||
ransac = RansacParams::translationMotionStd();
|
ransac = RansacParams::translation2dMotionStd();
|
||||||
}
|
}
|
||||||
else if (arg("model") == "transl_and_scale")
|
else if (arg("model") == "transl_and_scale")
|
||||||
{
|
{
|
||||||
@ -270,7 +270,7 @@ int main(int argc, const char **argv)
|
|||||||
else if (arg("model") == "linear_sim")
|
else if (arg("model") == "linear_sim")
|
||||||
{
|
{
|
||||||
est->setMotionModel(LINEAR_SIMILARITY);
|
est->setMotionModel(LINEAR_SIMILARITY);
|
||||||
ransac = RansacParams::linearSimilarityMotionStd();
|
ransac = RansacParams::linearSimilarity2dMotionStd();
|
||||||
}
|
}
|
||||||
else if (arg("model") == "affine")
|
else if (arg("model") == "affine")
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user