#include <string>
#include <iostream>
+#include <fstream>
#include <sstream>
#include <stdexcept>
#include "opencv2/core/core.hpp"
using namespace cv;
using namespace cv::videostab;
+
Ptr<IFrameSource> 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_<float> 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<Mat> motions_;
+ size_t pos_;
+};
+
void run()
{
VideoWriter writer;
while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty())
{
+ if (!saveMotionsPath.empty())
+ saveMotionsIfNecessary();
if (!outputPath.empty())
{
if (!writer.isOpened())
}
+void saveMotionsIfNecessary()
+{
+ static bool areMotionsSaved = false;
+ if (!areMotionsSaved)
+ {
+ IFrameSource *frameSource = static_cast<IFrameSource*>(stabilizedFrames);
+ TwoPassStabilizer *twoPassStabilizer = dynamic_cast<TwoPassStabilizer*>(frameSource);
+ if (twoPassStabilizer)
+ {
+ ofstream f(saveMotionsPath.c_str());
+ const vector<Mat> &motions = twoPassStabilizer->motions();
+ f << motions.size() << endl;
+ for (size_t i = 0; i < motions.size(); ++i)
+ {
+ Mat_<float> 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"
" --min-inlier-ratio=<float_number>\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=<file_path>\n"
+ " Save estimated motions into file.\n"
+ " --load-motions=<file_path>\n"
+ " Load motions from file.\n\n"
" -r, --radius=<int_number>\n"
" Set smoothing radius. The default is 15.\n"
" --stdev=<float_number>\n"
"{ m | model | | }"
"{ | min-inlier-ratio | | }"
"{ | outlier-ratio | | }"
+ "{ | save-motions | | }"
+ "{ | load-motions | | }"
"{ r | radius | | }"
"{ | stdev | | }"
"{ | deblur | | }"
motionFilter->setStdev(cmd.get<float>("stdev"));
}
- bool isTwoPass = cmd.get<string>("est-trim") == "yes";
+ if (!cmd.get<string>("save-motions").empty())
+ saveMotionsPath = cmd.get<string>("save-motions");
+
+ bool isTwoPass =
+ cmd.get<string>("est-trim") == "yes" ||
+ !cmd.get<string>("save-motions").empty();
if (isTwoPass)
{
else if (cmd.get<string>("model") == "affine")
motionEstimator->setMotionModel(AFFINE);
else if (!cmd.get<string>("model").empty())
- throw runtime_error("unknow motion mode: " + cmd.get<string>("model"));
-
+ throw runtime_error("unknow motion mode: " + cmd.get<string>("model"));
if (!cmd.get<string>("outlier-ratio").empty())
{
RansacParams ransacParams = motionEstimator->ransacParams();
ransacParams.eps = cmd.get<float>("outlier-ratio");
motionEstimator->setRansacParams(ransacParams);
}
-
if (!cmd.get<string>("min-inlier-ratio").empty())
motionEstimator->setMinInlierRatio(cmd.get<float>("min-inlier-ratio"));
-
stabilizer->setMotionEstimator(motionEstimator);
+ if (!cmd.get<string>("load-motions").empty())
+ stabilizer->setMotionEstimator(new GlobalMotionReader(cmd.get<string>("load-motions")));
if (!cmd.get<string>("radius").empty())
stabilizer->setRadius(cmd.get<int>("radius"));