From 3e23bb6df694e963875ba150e57e97bfd358ffe7 Mon Sep 17 00:00:00 2001 From: Alexey Spizhevoy Date: Mon, 2 Apr 2012 09:25:27 +0000 Subject: [PATCH] Refactored videostab module and sample --- .../include/opencv2/videostab/deblurring.hpp | 2 - .../include/opencv2/videostab/global_motion.hpp | 1 + .../include/opencv2/videostab/inpainting.hpp | 4 - .../opencv2/videostab/motion_stabilizing.hpp | 6 + .../include/opencv2/videostab/stabilizer.hpp | 2 +- modules/videostab/src/inpainting.cpp | 8 - modules/videostab/src/stabilizer.cpp | 40 ++-- samples/cpp/videostab.cpp | 261 ++++++++++----------- 8 files changed, 150 insertions(+), 174 deletions(-) diff --git a/modules/videostab/include/opencv2/videostab/deblurring.hpp b/modules/videostab/include/opencv2/videostab/deblurring.hpp index a61f9ce..6cbc47f 100644 --- a/modules/videostab/include/opencv2/videostab/deblurring.hpp +++ b/modules/videostab/include/opencv2/videostab/deblurring.hpp @@ -72,8 +72,6 @@ public: virtual void setBlurrinessRates(const std::vector &val) { blurrinessRates_ = &val; } virtual const std::vector& blurrinessRates() const { return *blurrinessRates_; } - virtual void update() {} - virtual void deblur(int idx, Mat &frame) = 0; protected: diff --git a/modules/videostab/include/opencv2/videostab/global_motion.hpp b/modules/videostab/include/opencv2/videostab/global_motion.hpp index 85a37fe..2acaad2 100644 --- a/modules/videostab/include/opencv2/videostab/global_motion.hpp +++ b/modules/videostab/include/opencv2/videostab/global_motion.hpp @@ -72,6 +72,7 @@ struct CV_EXPORTS RansacParams float eps; // max outliers ratio float prob; // probability of success + RansacParams() : size(0), thresh(0), eps(0), prob(0) {} RansacParams(int size, float thresh, float eps, float prob) : size(size), thresh(thresh), eps(eps), prob(prob) {} diff --git a/modules/videostab/include/opencv2/videostab/inpainting.hpp b/modules/videostab/include/opencv2/videostab/inpainting.hpp index 7d32142..9c18dcf 100644 --- a/modules/videostab/include/opencv2/videostab/inpainting.hpp +++ b/modules/videostab/include/opencv2/videostab/inpainting.hpp @@ -78,8 +78,6 @@ public: virtual void setStabilizationMotions(const std::vector &val) { stabilizationMotions_ = &val; } virtual const std::vector& stabilizationMotions() const { return *stabilizationMotions_; } - virtual void update() {} - virtual void inpaint(int idx, Mat &frame, Mat &mask) = 0; protected: @@ -108,8 +106,6 @@ public: virtual void setStabilizedFrames(const std::vector &val); virtual void setStabilizationMotions(const std::vector &val); - virtual void update(); - virtual void inpaint(int idx, Mat &frame, Mat &mask); private: diff --git a/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp b/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp index f811aa5..c942de1 100644 --- a/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp +++ b/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp @@ -79,6 +79,12 @@ class CV_EXPORTS GaussianMotionFilter : public MotionFilterBase { public: GaussianMotionFilter() : stdev_(-1.f) {} + GaussianMotionFilter(int radius, float stdev = -1.f) + { + setRadius(radius); + setStdev(stdev); + update(); + } void setStdev(float val) { stdev_ = val; } float stdev() const { return stdev_; } diff --git a/modules/videostab/include/opencv2/videostab/stabilizer.hpp b/modules/videostab/include/opencv2/videostab/stabilizer.hpp index eaa58f1..c206498 100644 --- a/modules/videostab/include/opencv2/videostab/stabilizer.hpp +++ b/modules/videostab/include/opencv2/videostab/stabilizer.hpp @@ -160,7 +160,7 @@ public: void setEstimateTrimRatio(bool val) { mustEstTrimRatio_ = val; } bool mustEstimateTrimaRatio() const { return mustEstTrimRatio_; } - virtual void reset() { resetImpl(); } + virtual void reset(); virtual Mat nextFrame(); // available after pre-pass, before it's empty diff --git a/modules/videostab/src/inpainting.cpp b/modules/videostab/src/inpainting.cpp index 805458d..a2e3c2c 100644 --- a/modules/videostab/src/inpainting.cpp +++ b/modules/videostab/src/inpainting.cpp @@ -93,14 +93,6 @@ void InpaintingPipeline::setStabilizationMotions(const vector &val) } -void InpaintingPipeline::update() -{ - for (size_t i = 0; i < inpainters_.size(); ++i) - inpainters_[i]->update(); - InpainterBase::update(); -} - - void InpaintingPipeline::inpaint(int idx, Mat &frame, Mat &mask) { for (size_t i = 0; i < inpainters_.size(); ++i) diff --git a/modules/videostab/src/stabilizer.cpp b/modules/videostab/src/stabilizer.cpp index 93868c2..0e6a855 100644 --- a/modules/videostab/src/stabilizer.cpp +++ b/modules/videostab/src/stabilizer.cpp @@ -70,12 +70,10 @@ void StabilizerBase::setUp(int cacheSize, const Mat &frame) doInpainting_ = dynamic_cast(inpainter) == 0; if (doInpainting_) { - inpainter_->setRadius(radius_); inpainter_->setFrames(frames_); inpainter_->setMotions(motions_); inpainter_->setStabilizedFrames(stabilizedFrames_); inpainter_->setStabilizationMotions(stabilizationMotions_); - inpainter_->update(); } DeblurerBase *deblurer = static_cast(deblurer_); @@ -86,11 +84,9 @@ void StabilizerBase::setUp(int cacheSize, const Mat &frame) float blurriness = calcBlurriness(frame); for (int i = -radius_; i <= 0; ++i) at(i, blurrinessRates_) = blurriness; - deblurer_->setRadius(radius_); deblurer_->setFrames(frames_); deblurer_->setMotions(motions_); deblurer_->setBlurrinessRates(blurrinessRates_); - deblurer_->update(); } log_->print("processing frames"); @@ -242,7 +238,6 @@ void OnePassStabilizer::setUp(Mat &firstFrame) at(0, frames_) = firstFrame; - motionFilter_->setRadius(radius_); motionFilter_->update(); StabilizerBase::setUp(cacheSize, firstFrame); @@ -267,7 +262,22 @@ TwoPassStabilizer::TwoPassStabilizer() { setMotionStabilizer(new GaussianMotionFilter()); setEstimateTrimRatio(false); - resetImpl(); + reset(); +} + + +void TwoPassStabilizer::reset() +{ + isPrePassDone_ = false; + frameCount_ = 0; + curPos_ = -1; + curStabilizedPos_ = -1; + frames_.clear(); + motions_.clear(); + stabilizedFrames_.clear(); + stabilizationMotions_.clear(); + doDeblurring_ = false; + doInpainting_ = false; } @@ -288,21 +298,6 @@ vector TwoPassStabilizer::motions() const } -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_) @@ -335,10 +330,7 @@ void TwoPassStabilizer::runPrePassIfNecessary() IMotionStabilizer *motionStabilizer = static_cast(motionStabilizer_); MotionFilterBase *motionFilterBase = dynamic_cast(motionStabilizer); if (motionFilterBase) - { - motionFilterBase->setRadius(radius_); motionFilterBase->update(); - } stabilizationMotions_.resize(frameCount_); motionStabilizer_->stabilize(&motions_[0], frameCount_, &stabilizationMotions_[0]); diff --git a/samples/cpp/videostab.cpp b/samples/cpp/videostab.cpp index 4e530e2..0b966df 100644 --- a/samples/cpp/videostab.cpp +++ b/samples/cpp/videostab.cpp @@ -9,11 +9,16 @@ #include "opencv2/highgui/highgui.hpp" #include "opencv2/videostab/videostab.hpp" +#define arg(name) cmd.get(name) +#define argb(name) cmd.get(name) +#define argi(name) cmd.get(name) +#define argf(name) cmd.get(name) +#define argd(name) cmd.get(name) + using namespace std; using namespace cv; using namespace cv::videostab; - Ptr stabilizedFrames; string saveMotionsPath; double outputFps; @@ -61,6 +66,7 @@ private: size_t pos_; }; + void run() { VideoWriter writer; @@ -128,14 +134,15 @@ void printHelp() " --min-inlier-ratio=\n" " Minimum inlier ratio to decide if estimated motion is OK. The default is 0.1,\n" " but you may want to increase it.\n\n" - " --save-motions=\n" - " Save estimated motions into file.\n" - " --load-motions=\n" - " Load motions from file.\n\n" + " --save-motions=(|no)\n" + " Save estimated motions into file. The default is no.\n" + " --load-motions=(|no)\n" + " Load motions from file. The default is no.\n\n" " -r, --radius=\n" - " Set smoothing radius. The default is 15.\n" - " --stdev=\n" - " Set smoothing weights standard deviation. The default is sqrt(radius).\n\n" + " Set sliding window radius. The default is 15.\n" + " --stdev=(|auto)\n" + " Set smoothing weights standard deviation. The default is sqrt(radius),\n" + " i.e. auto.\n\n" " --deblur=(yes|no)\n" " Do deblurring.\n" " --deblur-sens=\n" @@ -160,10 +167,11 @@ void printHelp() " --color-inpaint=(no|average|ns|telea)\n" " Do color inpainting. The defailt is no.\n" " --color-inpaint-radius=\n" - " Set color inpainting radius (for ns and telea options only).\n\n" + " Set color inpainting radius (for ns and telea options only).\n" + " The default is 2.0\n\n" " -o, --output=(no|)\n" " Set output file path explicitely. The default is stabilized.avi.\n" - " --fps=\n" + " --fps=(|auto)\n" " Set output video FPS explicitely. By default the source FPS is used.\n" " -q, --quiet\n" " Don't show output video frames.\n\n" @@ -179,182 +187,165 @@ int main(int argc, const char **argv) { const char *keys = "{ 1 | | | | }" - "{ m | model | | }" - "{ | min-inlier-ratio | | }" - "{ | outlier-ratio | | }" - "{ | save-motions | | }" - "{ | load-motions | | }" - "{ r | radius | | }" - "{ | stdev | | }" - "{ | deblur | | }" - "{ | deblur-sens | | }" + "{ m | model | affine| }" + "{ | min-inlier-ratio | 0.1 | }" + "{ | outlier-ratio | 0.5 | }" + "{ | save-motions | no | }" + "{ | load-motions | no | }" + "{ r | radius | 15 | }" + "{ | stdev | auto | }" + "{ | deblur | no | }" + "{ | deblur-sens | 0.1 | }" "{ | est-trim | yes | }" - "{ t | trim-ratio | | }" - "{ | incl-constr | | }" - "{ | border-mode | | }" - "{ | mosaic | | }" - "{ | mosaic-stdev | | }" - "{ | motion-inpaint | | }" - "{ | dist-thresh | | }" + "{ t | trim-ratio | 0.0 | }" + "{ | incl-constr | no | }" + "{ | border-mode | replicate | }" + "{ | mosaic | no | }" + "{ | mosaic-stdev | 10.0 | }" + "{ | motion-inpaint | no | }" + "{ | dist-thresh | 5.0 | }" "{ | color-inpaint | no | }" - "{ | color-inpaint-radius | | }" + "{ | color-inpaint-radius | 2 | }" "{ o | output | stabilized.avi | }" - "{ | fps | | }" + "{ | fps | auto | }" "{ q | quiet | false | }" "{ h | help | false | }"; CommandLineParser cmd(argc, argv, keys); // parse command arguments - if (cmd.get("help")) + if (argb("help")) { printHelp(); return 0; } StabilizerBase *stabilizer; - GaussianMotionFilter *motionFilter = 0; - - if (!cmd.get("stdev").empty()) - { - motionFilter = new GaussianMotionFilter(); - motionFilter->setStdev(cmd.get("stdev")); - } - - if (!cmd.get("save-motions").empty()) - saveMotionsPath = cmd.get("save-motions"); - - bool isTwoPass = - cmd.get("est-trim") == "yes" || - !cmd.get("save-motions").empty(); + bool isTwoPass = arg("est-trim") == "yes" || arg("save-motions") != "no"; if (isTwoPass) { TwoPassStabilizer *twoPassStabilizer = new TwoPassStabilizer(); - if (!cmd.get("est-trim").empty()) - twoPassStabilizer->setEstimateTrimRatio(cmd.get("est-trim") == "yes"); - if (motionFilter) - twoPassStabilizer->setMotionStabilizer(motionFilter); stabilizer = twoPassStabilizer; + twoPassStabilizer->setEstimateTrimRatio(arg("est-trim") == "yes"); + if (arg("stdev") == "auto") + twoPassStabilizer->setMotionStabilizer(new GaussianMotionFilter(argi("radius"))); + else + twoPassStabilizer->setMotionStabilizer(new GaussianMotionFilter(argi("radius"), argf("stdev"))); } else { - OnePassStabilizer *onePassStabilizer= new OnePassStabilizer(); - if (motionFilter) - onePassStabilizer->setMotionFilter(motionFilter); + OnePassStabilizer *onePassStabilizer = new OnePassStabilizer(); stabilizer = onePassStabilizer; + if (arg("stdev") == "auto") + onePassStabilizer->setMotionFilter(new GaussianMotionFilter(argi("radius"))); + else + onePassStabilizer->setMotionFilter(new GaussianMotionFilter(argi("radius"), argf("stdev"))); } + stabilizedFrames = dynamic_cast(stabilizer); + + string inputPath = arg("1"); + if (inputPath.empty()) throw runtime_error("specify video file path"); - string inputPath = cmd.get("1"); - if (inputPath.empty()) - throw runtime_error("specify video file path"); - - VideoFileSource *frameSource = new VideoFileSource(inputPath); - outputFps = frameSource->fps(); - stabilizer->setFrameSource(frameSource); - cout << "frame count: " << frameSource->frameCount() << endl; - - PyrLkRobustMotionEstimator *motionEstimator = new PyrLkRobustMotionEstimator(); - if (cmd.get("model") == "transl") - motionEstimator->setMotionModel(TRANSLATION); - else if (cmd.get("model") == "transl_and_scale") - motionEstimator->setMotionModel(TRANSLATION_AND_SCALE); - else if (cmd.get("model") == "linear_sim") - motionEstimator->setMotionModel(LINEAR_SIMILARITY); - else if (cmd.get("model") == "affine") - motionEstimator->setMotionModel(AFFINE); - else if (!cmd.get("model").empty()) - throw runtime_error("unknow motion mode: " + cmd.get("model")); - if (!cmd.get("outlier-ratio").empty()) + VideoFileSource *source = new VideoFileSource(inputPath); + cout << "frame count: " << source->frameCount() << endl; + if (arg("fps") == "auto") outputFps = source->fps(); else outputFps = argd("fps"); + stabilizer->setFrameSource(source); + + if (arg("load-motions") == "no") { - RansacParams ransacParams = motionEstimator->ransacParams(); - ransacParams.eps = cmd.get("outlier-ratio"); - motionEstimator->setRansacParams(ransacParams); + RansacParams ransac; + PyrLkRobustMotionEstimator *est = new PyrLkRobustMotionEstimator(); + Ptr est_(est); + if (arg("model") == "transl") + { + est->setMotionModel(TRANSLATION); + ransac = RansacParams::translationMotionStd(); + } + else if (arg("model") == "transl_and_scale") + { + est->setMotionModel(TRANSLATION_AND_SCALE); + ransac = RansacParams::translationAndScale2dMotionStd(); + } + else if (arg("model") == "linear_sim") + { + est->setMotionModel(LINEAR_SIMILARITY); + ransac = RansacParams::linearSimilarityMotionStd(); + } + else if (arg("model") == "affine") + { + est->setMotionModel(AFFINE); + ransac = RansacParams::affine2dMotionStd(); + } + else + throw runtime_error("unknown motion model: " + arg("model")); + ransac.eps = argf("outlier-ratio"); + est->setRansacParams(ransac); + est->setMinInlierRatio(argf("min-inlier-ratio")); + stabilizer->setMotionEstimator(est_); } - if (!cmd.get("min-inlier-ratio").empty()) - motionEstimator->setMinInlierRatio(cmd.get("min-inlier-ratio")); - stabilizer->setMotionEstimator(motionEstimator); - if (!cmd.get("load-motions").empty()) - stabilizer->setMotionEstimator(new GlobalMotionReader(cmd.get("load-motions"))); + else + stabilizer->setMotionEstimator(new GlobalMotionReader(arg("load-motions"))); - if (!cmd.get("radius").empty()) - stabilizer->setRadius(cmd.get("radius")); + if (arg("save-motions") != "no") + saveMotionsPath = arg("save-motions"); - if (cmd.get("deblur") == "yes") + stabilizer->setRadius(argi("radius")); + if (arg("deblur") == "yes") { WeightingDeblurer *deblurer = new WeightingDeblurer(); - if (!cmd.get("deblur-sens").empty()) - deblurer->setSensitivity(cmd.get("deblur-sens")); + deblurer->setRadius(argi("radius")); + deblurer->setSensitivity(argf("deblur-sens")); stabilizer->setDeblurer(deblurer); } - if (!cmd.get("trim-ratio").empty()) - stabilizer->setTrimRatio(cmd.get("trim-ratio")); + stabilizer->setTrimRatio(argf("trim-ratio")); + stabilizer->setCorrectionForInclusion(arg("incl-constr") == "yes"); - if (!cmd.get("incl-constr").empty()) - stabilizer->setCorrectionForInclusion(cmd.get("incl-constr") == "yes"); - - if (cmd.get("border-mode") == "reflect") + if (arg("border-mode") == "reflect") stabilizer->setBorderMode(BORDER_REFLECT); - else if (cmd.get("border-mode") == "replicate") + else if (arg("border-mode") == "replicate") stabilizer->setBorderMode(BORDER_REPLICATE); - else if (cmd.get("border-mode") == "const") + else if (arg("border-mode") == "const") stabilizer->setBorderMode(BORDER_CONSTANT); - else if (!cmd.get("border-mode").empty()) - throw runtime_error("unknown border extrapolation mode: " + cmd.get("border-mode")); + else + throw runtime_error("unknown border extrapolation mode: " + + cmd.get("border-mode")); InpaintingPipeline *inpainters = new InpaintingPipeline(); - if (cmd.get("mosaic") == "yes") + Ptr inpainters_(inpainters); + if (arg("mosaic") == "yes") { - ConsistentMosaicInpainter *inpainter = new ConsistentMosaicInpainter(); - if (!cmd.get("mosaic-stdev").empty()) - inpainter->setStdevThresh(cmd.get("mosaic-stdev")); - inpainters->pushBack(inpainter); + ConsistentMosaicInpainter *inp = new ConsistentMosaicInpainter(); + inp->setStdevThresh(argf("mosaic-stdev")); + inpainters->pushBack(inp); } - if (cmd.get("motion-inpaint") == "yes") + if (arg("motion-inpaint") == "yes") { - MotionInpainter *inpainter = new MotionInpainter(); - if (!cmd.get("dist-thresh").empty()) - inpainter->setDistThreshold(cmd.get("dist-thresh")); - inpainters->pushBack(inpainter); + MotionInpainter *inp = new MotionInpainter(); + inp->setDistThreshold(argf("dist-thresh")); + inpainters->pushBack(inp); } - if (!cmd.get("color-inpaint").empty()) + if (arg("color-inpaint") == "average") + inpainters->pushBack(new ColorAverageInpainter()); + else if (arg("color-inpaint") == "ns") + inpainters->pushBack(new ColorInpainter(INPAINT_NS, argd("color-inpaint-radius"))); + else if (arg("color-inpaint") == "telea") + inpainters->pushBack(new ColorInpainter(INPAINT_TELEA, argd("color-inpaint-radius"))); + else if (arg("color-inpaint") != "no") + throw runtime_error("unknown color inpainting method: " + arg("color-inpaint")); + if (!inpainters->empty()) { - if (cmd.get("color-inpaint") == "average") - inpainters->pushBack(new ColorAverageInpainter()); - else if (!cmd.get("color-inpaint-radius").empty()) - { - float radius = cmd.get("color-inpaint-radius"); - if (cmd.get("color-inpaint") == "ns") - inpainters->pushBack(new ColorInpainter(INPAINT_NS, radius)); - else if (cmd.get("color-inpaint") == "telea") - inpainters->pushBack(new ColorInpainter(INPAINT_TELEA, radius)); - else if (cmd.get("color-inpaint") != "no") - throw runtime_error("unknown color inpainting method: " + cmd.get("color-inpaint")); - } - else - { - if (cmd.get("color-inpaint") == "ns") - inpainters->pushBack(new ColorInpainter(INPAINT_NS)); - else if (cmd.get("color-inpaint") == "telea") - inpainters->pushBack(new ColorInpainter(INPAINT_TELEA)); - else if (cmd.get("color-inpaint") != "no") - throw runtime_error("unknown color inpainting method: " + cmd.get("color-inpaint")); - } + inpainters->setRadius(argi("radius")); + stabilizer->setInpainter(inpainters_); } - if (!inpainters->empty()) - stabilizer->setInpainter(inpainters); stabilizer->setLog(new LogToStdout()); - outputPath = cmd.get("output") != "no" ? cmd.get("output") : ""; - - if (!cmd.get("fps").empty()) - outputFps = cmd.get("fps"); + if (arg("output") != "no") + outputPath = arg("output"); - quietMode = cmd.get("quiet"); - - stabilizedFrames = dynamic_cast(stabilizer); + quietMode = argb("quite"); run(); } -- 2.7.4