Added load and save motion args into videostab sample
authorAlexey Spizhevoy <no@email>
Thu, 22 Mar 2012 09:30:28 +0000 (09:30 +0000)
committerAlexey Spizhevoy <no@email>
Thu, 22 Mar 2012 09:30:28 +0000 (09:30 +0000)
modules/videostab/include/opencv2/videostab/stabilizer.hpp
modules/videostab/src/stabilizer.cpp
samples/cpp/videostab.cpp

index 261dd8b..eaa58f1 100644 (file)
@@ -163,6 +163,9 @@ public:
     virtual void reset() { resetImpl(); }
     virtual Mat nextFrame();
 
+    // available after pre-pass, before it's empty
+    std::vector<Mat> motions() const;
+
 private:
     void resetImpl();
     void runPrePassIfNecessary();
index 5b17147..9dab8c0 100644 (file)
@@ -278,6 +278,16 @@ Mat TwoPassStabilizer::nextFrame()
 }
 
 
+vector<Mat> TwoPassStabilizer::motions() const
+{
+    if (frameCount_ == 0)
+        return vector<Mat>();
+    vector<Mat> res(frameCount_ - 1);
+    copy(motions_.begin(), motions_.begin() + frameCount_ - 1, res.begin());
+    return res;
+}
+
+
 void TwoPassStabilizer::resetImpl()
 {
     isPrePassDone_ = false;
index b5f62c0..0c84701 100644 (file)
@@ -1,5 +1,6 @@
 #include <string>
 #include <iostream>
+#include <fstream>
 #include <sstream>
 #include <stdexcept>
 #include "opencv2/core/core.hpp"
@@ -12,14 +13,54 @@ using namespace std;
 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;
@@ -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<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"
@@ -58,6 +128,10 @@ void printHelp()
             "  --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"
@@ -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<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)
         {
@@ -181,19 +262,18 @@ int main(int argc, const char **argv)
         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"));