68b62192dbfedfb49ae25834aa6482a4d4f28a4e
[profile/ivi/opencv.git] / samples / cpp / videostab.cpp
1 #include <string>
2 #include <iostream>
3 #include <sstream>
4 #include <stdexcept>
5 #include "opencv2/core/core.hpp"
6 #include "opencv2/video/video.hpp"
7 #include "opencv2/imgproc/imgproc.hpp"
8 #include "opencv2/highgui/highgui.hpp"
9 #include "opencv2/videostab/videostab.hpp"
10
11 using namespace std;
12 using namespace cv;
13 using namespace cv::videostab;
14
15 Ptr<Stabilizer> stabilizer;
16 double outputFps;
17 string outputPath;
18 bool quietMode;
19
20 void run();
21 void printHelp();
22
23 void run()
24 {
25     VideoWriter writer;
26     Mat stabilizedFrame;
27
28     while (!(stabilizedFrame = stabilizer->nextFrame()).empty())
29     {
30         if (!outputPath.empty())
31         {
32             if (!writer.isOpened())
33                 writer.open(outputPath, CV_FOURCC('X','V','I','D'), outputFps, stabilizedFrame.size());
34             writer << stabilizedFrame;
35         }
36         if (!quietMode)
37         {
38             imshow("stabilizedFrame", stabilizedFrame);
39             char key = static_cast<char>(waitKey(3));
40             if (key == 27)
41                 break;
42         }
43     }
44
45     cout << "\nfinished\n";
46 }
47
48
49 void printHelp()
50 {
51     cout << "OpenCV video stabilizer.\n"
52             "Usage: videostab <file_path> [arguments]\n\n"
53             "Arguments:\n"
54             "  -m, --model=(transl|transl_and_scale|affine)\n"
55             "      Set motion model. The default is affine.\n"
56             "  --outlier-ratio=<float_number>\n"
57             "      Outliers ratio in motion estimation. The default is 0.5.\n"
58             "  --min-inlier-ratio=<float_number>\n"
59             "      Minimum inlier ratio to decide if estimated motion is OK. The default is 0.1,\n"
60             "      but you may want to increase it.\n"
61             "  -r, --radius=<int_number>\n"
62             "      Set smoothing radius. The default is 15.\n"
63             "  --stdev=<float_number>\n"
64             "      Set smoothing weights standard deviation. The default is sqrt(radius).\n"
65             "  --deblur=(yes|no)\n"
66             "      Do deblurring.\n"
67             "  --deblur-sens=<float_number>\n"
68             "      Set deblurring sensitivity (from 0 to +inf). The default is 0.1.\n"
69             "  -t, --trim-ratio=<float_number>\n"
70             "      Set trimming ratio (from 0 to 0.5). The default is 0.\n"
71             "  --est-trim=(yes|no)\n"
72             "      Estimate trim ratio automatically. The default is yes (that leads to two passes,\n"
73             "      you can turn it off if you want to use one pass only).\n"
74             "  --incl-constr=(yes|no)\n"
75             "      Ensure the inclusion constraint is always satisfied. The default is no.\n"
76             "  --border-mode=(replicate|reflect|const)\n"
77             "      Set border extrapolation mode. The default is replicate.\n"
78             "  --mosaic=(yes|no)\n"
79             "      Do consistent mosaicing. The default is no.\n"
80             "  --mosaic-stdev=<float_number>\n"
81             "      Consistent mosaicing stdev threshold. The default is 10.\n"
82             "  --motion-inpaint=(yes|no)\n"
83             "      Do motion inpainting (requires GPU support). The default is no.\n"
84             "  --color-inpaint=(no|average|ns|telea)\n"
85             "      Do color inpainting. The defailt is no.\n"
86             "  --color-inpaint-radius=<float_number>\n"
87             "      Set color inpainting radius (for ns and telea options only).\n"
88             "  -o, --output=<file_path>\n"
89             "      Set output file path explicitely. The default is stabilized.avi.\n"
90             "  --fps=<int_number>\n"
91             "      Set output video FPS explicitely. By default the source FPS is used.\n"
92             "  -q, --quiet\n"
93             "      Don't show output video frames.\n"
94             "  -h, --help\n"
95             "      Print help.\n"
96             "\n";
97 }
98
99
100 int main(int argc, const char **argv)
101 {
102     try
103     {
104         const char *keys =
105                 "{ 1 | | | | }"
106                 "{ m | model | | }"
107                 "{ | min-inlier-ratio | | }"
108                 "{ | outlier-ratio | | }"
109                 "{ r | radius | | }"
110                 "{ | stdev | | }"
111                 "{ | deblur | | }"
112                 "{ | deblur-sens | | }"
113                 "{ | est-trim | | }"
114                 "{ t | trim-ratio | | }"
115                 "{ | incl-constr | | }"
116                 "{ | border-mode | | }"
117                 "{ | mosaic | | }"
118                 "{ | mosaic-stdev | | }"
119                 "{ | motion-inpaint | | }"
120                 "{ | color-inpaint | no | }"
121                 "{ | color-inpaint-radius | | }"
122                 "{ o | output | stabilized.avi | }"
123                 "{ | fps | | }"
124                 "{ q | quiet | false | }"
125                 "{ h | help | false | }";
126         CommandLineParser cmd(argc, argv, keys);
127
128         // parse command arguments
129
130         if (cmd.get<bool>("help"))
131         {
132             printHelp();
133             return 0;
134         }
135
136         stabilizer = new Stabilizer();
137
138         string inputPath = cmd.get<string>("1");
139         if (inputPath.empty())
140             throw runtime_error("specify video file path");
141
142         VideoFileSource *frameSource = new VideoFileSource(inputPath);
143         outputFps = frameSource->fps();
144         stabilizer->setFrameSource(frameSource);
145         cout << "frame count: " << frameSource->frameCount() << endl;
146
147         PyrLkRobustMotionEstimator *motionEstimator = new PyrLkRobustMotionEstimator();
148         if (cmd.get<string>("model") == "transl")           
149             motionEstimator->setMotionModel(TRANSLATION);
150         else if (cmd.get<string>("model") == "transl_and_scale")
151             motionEstimator->setMotionModel(TRANSLATION_AND_SCALE);
152         else if (cmd.get<string>("model") == "affine")
153             motionEstimator->setMotionModel(AFFINE);
154         else if (!cmd.get<string>("model").empty())
155             throw runtime_error("unknow motion mode: " + cmd.get<string>("model"));        
156
157         if (!cmd.get<string>("outlier-ratio").empty())
158         {
159             RansacParams ransacParams = motionEstimator->ransacParams();
160             ransacParams.eps = cmd.get<float>("outlier-ratio");
161             motionEstimator->setRansacParams(ransacParams);
162         }
163
164         if (!cmd.get<string>("min-inlier-ratio").empty())
165             motionEstimator->setMinInlierRatio(cmd.get<float>("min-inlier-ratio"));
166
167         stabilizer->setMotionEstimator(motionEstimator);
168
169         int smoothRadius = -1;
170         float smoothStdev = -1;
171         if (!cmd.get<string>("radius").empty())
172             smoothRadius = cmd.get<int>("radius");
173         if (!cmd.get<string>("stdev").empty())
174             smoothStdev = cmd.get<float>("stdev");
175         if (smoothRadius > 0 && smoothStdev > 0)
176             stabilizer->setMotionFilter(new GaussianMotionFilter(smoothRadius, smoothStdev));
177         else if (smoothRadius > 0 && smoothStdev < 0)
178             stabilizer->setMotionFilter(new GaussianMotionFilter(smoothRadius, sqrt(static_cast<float>(smoothRadius))));
179
180         if (cmd.get<string>("deblur") == "yes")
181         {
182             WeightingDeblurer *deblurer = new WeightingDeblurer();
183             if (!cmd.get<string>("deblur-sens").empty())
184                 deblurer->setSensitivity(cmd.get<float>("deblur-sens"));
185             stabilizer->setDeblurer(deblurer);
186         }
187
188         if (!cmd.get<string>("est-trim").empty())
189             stabilizer->setEstimateTrimRatio(cmd.get<string>("est-trim") == "yes");
190
191         if (!cmd.get<string>("trim-ratio").empty())
192             stabilizer->setTrimRatio(cmd.get<float>("trim-ratio"));
193
194         if (!cmd.get<string>("incl-constr").empty())
195             stabilizer->setInclusionConstraint(cmd.get<string>("incl-constr") == "yes");
196
197         if (cmd.get<string>("border-mode") == "reflect")
198             stabilizer->setBorderMode(BORDER_REFLECT);
199         else if (cmd.get<string>("border-mode") == "replicate")
200             stabilizer->setBorderMode(BORDER_REPLICATE);
201         else if (cmd.get<string>("border-mode") == "const")
202             stabilizer->setBorderMode(BORDER_CONSTANT);
203         else if (!cmd.get<string>("border-mode").empty())
204             throw runtime_error("unknown border extrapolation mode: " + cmd.get<string>("border-mode"));
205
206         InpaintingPipeline *inpainters = new InpaintingPipeline();
207         if (cmd.get<string>("mosaic") == "yes")
208         {
209             ConsistentMosaicInpainter *inpainter = new ConsistentMosaicInpainter();
210             if (!cmd.get<string>("mosaic-stdev").empty())
211                 inpainter->setStdevThresh(cmd.get<float>("mosaic-stdev"));
212             inpainters->pushBack(inpainter);
213         }
214         if (cmd.get<string>("motion-inpaint") == "yes")
215             inpainters->pushBack(new MotionInpainter());
216         if (!cmd.get<string>("color-inpaint").empty())
217         {
218             if (cmd.get<string>("color-inpaint") == "average")
219                 inpainters->pushBack(new ColorAverageInpainter());
220             else if (!cmd.get<string>("color-inpaint-radius").empty())
221             {
222                 float radius = cmd.get<float>("color-inpaint-radius");
223                 if (cmd.get<string>("color-inpaint") == "ns")
224                     inpainters->pushBack(new ColorInpainter(INPAINT_NS, radius));
225                 else if (cmd.get<string>("color-inpaint") == "telea")
226                     inpainters->pushBack(new ColorInpainter(INPAINT_TELEA, radius));
227                 else if (cmd.get<string>("color-inpaint") != "no")
228                     throw runtime_error("unknown color inpainting method: " + cmd.get<string>("color-inpaint"));
229             }
230             else
231             {
232                 if (cmd.get<string>("color-inpaint") == "ns")
233                     inpainters->pushBack(new ColorInpainter(INPAINT_NS));
234                 else if (cmd.get<string>("color-inpaint") == "telea")
235                     inpainters->pushBack(new ColorInpainter(INPAINT_TELEA));
236                 else if (cmd.get<string>("color-inpaint") != "no")
237                     throw runtime_error("unknown color inpainting method: " + cmd.get<string>("color-inpaint"));
238             }
239         }
240         if (!inpainters->empty())
241             stabilizer->setInpainter(inpainters);
242
243         stabilizer->setLog(new LogToStdout());
244
245         outputPath = cmd.get<string>("output");
246
247         if (!cmd.get<string>("fps").empty())
248             outputFps = cmd.get<double>("fps");
249
250         quietMode = cmd.get<bool>("quiet");
251
252         // run video processing
253         run();
254     }
255     catch (const exception &e)
256     {
257         cout << e.what() << endl;
258         stabilizer.release();
259         return -1;
260     }
261     stabilizer.release();
262     return 0;
263 }