From 45fd8a6a63bd6984edf521d5583bc37f1cb43f9a Mon Sep 17 00:00:00 2001 From: Alexey Spizhevoy Date: Thu, 22 Mar 2012 09:30:28 +0000 Subject: [PATCH] Added load and save motion args into videostab sample --- .../include/opencv2/videostab/stabilizer.hpp | 3 + modules/videostab/src/stabilizer.cpp | 10 +++ samples/cpp/videostab.cpp | 90 ++++++++++++++++++++-- 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/modules/videostab/include/opencv2/videostab/stabilizer.hpp b/modules/videostab/include/opencv2/videostab/stabilizer.hpp index 261dd8b..eaa58f1 100644 --- a/modules/videostab/include/opencv2/videostab/stabilizer.hpp +++ b/modules/videostab/include/opencv2/videostab/stabilizer.hpp @@ -163,6 +163,9 @@ public: virtual void reset() { resetImpl(); } virtual Mat nextFrame(); + // available after pre-pass, before it's empty + std::vector motions() const; + private: void resetImpl(); void runPrePassIfNecessary(); diff --git a/modules/videostab/src/stabilizer.cpp b/modules/videostab/src/stabilizer.cpp index 5b17147..9dab8c0 100644 --- a/modules/videostab/src/stabilizer.cpp +++ b/modules/videostab/src/stabilizer.cpp @@ -278,6 +278,16 @@ Mat TwoPassStabilizer::nextFrame() } +vector TwoPassStabilizer::motions() const +{ + if (frameCount_ == 0) + return vector(); + vector res(frameCount_ - 1); + copy(motions_.begin(), motions_.begin() + frameCount_ - 1, res.begin()); + return res; +} + + void TwoPassStabilizer::resetImpl() { isPrePassDone_ = false; diff --git a/samples/cpp/videostab.cpp b/samples/cpp/videostab.cpp index b5f62c0..0c84701 100644 --- a/samples/cpp/videostab.cpp +++ b/samples/cpp/videostab.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include "opencv2/core/core.hpp" @@ -12,14 +13,54 @@ using namespace std; using namespace cv; using namespace cv::videostab; + Ptr stabilizedFrames; +string saveMotionsPath; double outputFps; string outputPath; bool quietMode; void run(); +void saveMotionsIfNecessary(); void printHelp(); +class GlobalMotionReader : public IGlobalMotionEstimator +{ +public: + GlobalMotionReader(string path) + { + ifstream f(path.c_str()); + if (!f.is_open()) + throw runtime_error("can't open motions file: " + path); + int size; f >> size; + motions_.resize(size); + for (int i = 0; i < size; ++i) + { + Mat_ M(3, 3); + for (int l = 0; l < 3; ++l) + for (int s = 0; s < 3; ++s) + f >> M(l,s); + motions_[i] = M; + } + pos_ = 0; + } + + virtual Mat estimate(const Mat &/*frame0*/, const Mat &/*frame1*/) + { + if (pos_ >= motions_.size()) + { + stringstream text; + text << "can't load motion between frames " << pos_ << " and " << pos_+1; + throw runtime_error(text.str()); + } + return motions_[pos_++]; + } + +private: + vector motions_; + size_t pos_; +}; + void run() { VideoWriter writer; @@ -27,6 +68,8 @@ void run() while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty()) { + if (!saveMotionsPath.empty()) + saveMotionsIfNecessary(); if (!outputPath.empty()) { if (!writer.isOpened()) @@ -46,6 +89,33 @@ void run() } +void saveMotionsIfNecessary() +{ + static bool areMotionsSaved = false; + if (!areMotionsSaved) + { + IFrameSource *frameSource = static_cast(stabilizedFrames); + TwoPassStabilizer *twoPassStabilizer = dynamic_cast(frameSource); + if (twoPassStabilizer) + { + ofstream f(saveMotionsPath.c_str()); + const vector &motions = twoPassStabilizer->motions(); + f << motions.size() << endl; + for (size_t i = 0; i < motions.size(); ++i) + { + Mat_ M = motions[i]; + for (int l = 0, k = 0; l < 3; ++l) + for (int s = 0; s < 3; ++s, ++k) + f << M(l,s) << " "; + f << endl; + } + } + areMotionsSaved = true; + cout << "motions are saved"; + } +} + + void printHelp() { cout << "OpenCV video stabilizer.\n" @@ -58,6 +128,10 @@ 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" " -r, --radius=\n" " Set smoothing radius. The default is 15.\n" " --stdev=\n" @@ -108,6 +182,8 @@ int main(int argc, const char **argv) "{ m | model | | }" "{ | min-inlier-ratio | | }" "{ | outlier-ratio | | }" + "{ | save-motions | | }" + "{ | load-motions | | }" "{ r | radius | | }" "{ | stdev | | }" "{ | deblur | | }" @@ -145,7 +221,12 @@ int main(int argc, const char **argv) motionFilter->setStdev(cmd.get("stdev")); } - bool isTwoPass = cmd.get("est-trim") == "yes"; + if (!cmd.get("save-motions").empty()) + saveMotionsPath = cmd.get("save-motions"); + + bool isTwoPass = + cmd.get("est-trim") == "yes" || + !cmd.get("save-motions").empty(); if (isTwoPass) { @@ -181,19 +262,18 @@ int main(int argc, const char **argv) else if (cmd.get("model") == "affine") motionEstimator->setMotionModel(AFFINE); else if (!cmd.get("model").empty()) - throw runtime_error("unknow motion mode: " + cmd.get("model")); - + throw runtime_error("unknow motion mode: " + cmd.get("model")); if (!cmd.get("outlier-ratio").empty()) { RansacParams ransacParams = motionEstimator->ransacParams(); ransacParams.eps = cmd.get("outlier-ratio"); motionEstimator->setRansacParams(ransacParams); } - 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"))); if (!cmd.get("radius").empty()) stabilizer->setRadius(cmd.get("radius")); -- 2.7.4