videostab.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. #include <string>
  2. #include <iostream>
  3. #include <fstream>
  4. #include <sstream>
  5. #include <stdexcept>
  6. #include "opencv2/core.hpp"
  7. #include <opencv2/core/utility.hpp>
  8. #include "opencv2/video.hpp"
  9. #include "opencv2/imgproc.hpp"
  10. #include "opencv2/videoio.hpp"
  11. #include "opencv2/highgui.hpp"
  12. #include "opencv2/videostab.hpp"
  13. #include "opencv2/opencv_modules.hpp"
  14. #define arg(name) cmd.get<string>(name)
  15. #define argb(name) cmd.get<bool>(name)
  16. #define argi(name) cmd.get<int>(name)
  17. #define argf(name) cmd.get<float>(name)
  18. #define argd(name) cmd.get<double>(name)
  19. using namespace std;
  20. using namespace cv;
  21. using namespace cv::videostab;
  22. Ptr<IFrameSource> stabilizedFrames;
  23. string saveMotionsPath;
  24. double outputFps;
  25. string outputPath;
  26. bool quietMode;
  27. void run();
  28. void saveMotionsIfNecessary();
  29. void printHelp();
  30. MotionModel motionModel(const string &str);
  31. void run()
  32. {
  33. VideoWriter writer;
  34. Mat stabilizedFrame;
  35. int nframes = 0;
  36. // for each stabilized frame
  37. while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty())
  38. {
  39. nframes++;
  40. // init writer (once) and save stabilized frame
  41. if (!outputPath.empty())
  42. {
  43. if (!writer.isOpened())
  44. writer.open(outputPath, VideoWriter::fourcc('X','V','I','D'),
  45. outputFps, stabilizedFrame.size());
  46. writer << stabilizedFrame;
  47. }
  48. // show stabilized frame
  49. if (!quietMode)
  50. {
  51. imshow("stabilizedFrame", stabilizedFrame);
  52. char key = static_cast<char>(waitKey(3));
  53. if (key == 27) { cout << endl; break; }
  54. }
  55. }
  56. cout << "processed frames: " << nframes << endl
  57. << "finished\n";
  58. }
  59. void printHelp()
  60. {
  61. cout << "OpenCV video stabilizer.\n"
  62. "Usage: videostab <file_path> [arguments]\n\n"
  63. "Arguments:\n"
  64. " -m=, --model=(transl|transl_and_scale|rigid|similarity|affine|homography)\n"
  65. " Set motion model. The default is affine.\n"
  66. " -lp=, --lin-prog-motion-est=(yes|no)\n"
  67. " Turn on/off LP based motion estimation. The default is no.\n"
  68. " --subset=(<int_number>|auto)\n"
  69. " Number of random samples per one motion hypothesis. The default is auto.\n"
  70. " --thresh=(<float_number>|auto)\n"
  71. " Maximum error to classify match as inlier. The default is auto.\n"
  72. " --outlier-ratio=<float_number>\n"
  73. " Motion estimation outlier ratio hypothesis. The default is 0.5.\n"
  74. " --min-inlier-ratio=<float_number>\n"
  75. " Minimum inlier ratio to decide if estimated motion is OK. The default is 0.1.\n"
  76. " --nkps=<int_number>\n"
  77. " Number of keypoints to find in each frame. The default is 1000.\n"
  78. " --local-outlier-rejection=(yes|no)\n"
  79. " Perform local outlier rejection. The default is no.\n\n"
  80. " --feature-masks=(file_path|no)\n"
  81. " Load masks from file. The default is no.\n\n"
  82. " -sm=, --save-motions=(<file_path>|no)\n"
  83. " Save estimated motions into file. The default is no.\n"
  84. " -lm=, --load-motions=(<file_path>|no)\n"
  85. " Load motions from file. The default is no.\n\n"
  86. " -r=, --radius=<int_number>\n"
  87. " Set sliding window radius. The default is 15.\n"
  88. " --stdev=(<float_number>|auto)\n"
  89. " Set smoothing weights standard deviation. The default is auto\n"
  90. " (i.e. sqrt(radius)).\n"
  91. " -lps=, --lin-prog-stab=(yes|no)\n"
  92. " Turn on/off linear programming based stabilization method.\n"
  93. " --lps-trim-ratio=(<float_number>|auto)\n"
  94. " Trimming ratio used in linear programming based method.\n"
  95. " --lps-w1=(<float_number>|1)\n"
  96. " 1st derivative weight. The default is 1.\n"
  97. " --lps-w2=(<float_number>|10)\n"
  98. " 2nd derivative weight. The default is 10.\n"
  99. " --lps-w3=(<float_number>|100)\n"
  100. " 3rd derivative weight. The default is 100.\n"
  101. " --lps-w4=(<float_number>|100)\n"
  102. " Non-translation motion components weight. The default is 100.\n\n"
  103. " --deblur=(yes|no)\n"
  104. " Do deblurring.\n"
  105. " --deblur-sens=<float_number>\n"
  106. " Set deblurring sensitivity (from 0 to +inf). The default is 0.1.\n\n"
  107. " -t=, --trim-ratio=<float_number>\n"
  108. " Set trimming ratio (from 0 to 0.5). The default is 0.1.\n"
  109. " -et=, --est-trim=(yes|no)\n"
  110. " Estimate trim ratio automatically. The default is yes.\n"
  111. " -ic=, --incl-constr=(yes|no)\n"
  112. " Ensure the inclusion constraint is always satisfied. The default is no.\n\n"
  113. " -bm=, --border-mode=(replicate|reflect|const)\n"
  114. " Set border extrapolation mode. The default is replicate.\n\n"
  115. " --mosaic=(yes|no)\n"
  116. " Do consistent mosaicking. The default is no.\n"
  117. " --mosaic-stdev=<float_number>\n"
  118. " Consistent mosaicking stdev threshold. The default is 10.0.\n\n"
  119. " -mi=, --motion-inpaint=(yes|no)\n"
  120. " Do motion inpainting (requires CUDA support). The default is no.\n"
  121. " --mi-dist-thresh=<float_number>\n"
  122. " Estimated flow distance threshold for motion inpainting. The default is 5.0.\n\n"
  123. " -ci=, --color-inpaint=(no|average|ns|telea)\n"
  124. " Do color inpainting. The default is no.\n"
  125. " --ci-radius=<float_number>\n"
  126. " Set color inpainting radius (for ns and telea options only).\n"
  127. " The default is 2.0\n\n"
  128. " -ws=, --wobble-suppress=(yes|no)\n"
  129. " Perform wobble suppression. The default is no.\n"
  130. " --ws-lp=(yes|no)\n"
  131. " Turn on/off LP based motion estimation. The default is no.\n"
  132. " --ws-period=<int_number>\n"
  133. " Set wobble suppression period. The default is 30.\n"
  134. " --ws-model=(transl|transl_and_scale|rigid|similarity|affine|homography)\n"
  135. " Set wobble suppression motion model (must have more DOF than motion \n"
  136. " estimation model). The default is homography.\n"
  137. " --ws-subset=(<int_number>|auto)\n"
  138. " Number of random samples per one motion hypothesis. The default is auto.\n"
  139. " --ws-thresh=(<float_number>|auto)\n"
  140. " Maximum error to classify match as inlier. The default is auto.\n"
  141. " --ws-outlier-ratio=<float_number>\n"
  142. " Motion estimation outlier ratio hypothesis. The default is 0.5.\n"
  143. " --ws-min-inlier-ratio=<float_number>\n"
  144. " Minimum inlier ratio to decide if estimated motion is OK. The default is 0.1.\n"
  145. " --ws-nkps=<int_number>\n"
  146. " Number of keypoints to find in each frame. The default is 1000.\n"
  147. " --ws-local-outlier-rejection=(yes|no)\n"
  148. " Perform local outlier rejection. The default is no.\n\n"
  149. " -sm2=, --save-motions2=(<file_path>|no)\n"
  150. " Save motions estimated for wobble suppression. The default is no.\n"
  151. " -lm2=, --load-motions2=(<file_path>|no)\n"
  152. " Load motions for wobble suppression from file. The default is no.\n\n"
  153. " -gpu=(yes|no)\n"
  154. " Use CUDA optimization whenever possible. The default is no.\n\n"
  155. " -o=, --output=(no|<file_path>)\n"
  156. " Set output file path explicitly. The default is stabilized.avi.\n"
  157. " --fps=(<float_number>|auto)\n"
  158. " Set output video FPS explicitly. By default the source FPS is used (auto).\n"
  159. " -q, --quiet\n"
  160. " Don't show output video frames.\n\n"
  161. " -h, --help\n"
  162. " Print help.\n\n"
  163. "Note: some argument configurations lead to two passes, some to single pass.\n\n";
  164. }
  165. // motion estimator builders are for concise creation of motion estimators
  166. class IMotionEstimatorBuilder
  167. {
  168. public:
  169. virtual ~IMotionEstimatorBuilder() {}
  170. virtual Ptr<ImageMotionEstimatorBase> build() = 0;
  171. protected:
  172. IMotionEstimatorBuilder(CommandLineParser &command) : cmd(command) {}
  173. CommandLineParser cmd;
  174. };
  175. class MotionEstimatorRansacL2Builder : public IMotionEstimatorBuilder
  176. {
  177. public:
  178. MotionEstimatorRansacL2Builder(CommandLineParser &command, bool use_gpu, const string &_prefix = "")
  179. : IMotionEstimatorBuilder(command), gpu(use_gpu), prefix(_prefix) {}
  180. virtual Ptr<ImageMotionEstimatorBase> build() CV_OVERRIDE
  181. {
  182. Ptr<MotionEstimatorRansacL2> est = makePtr<MotionEstimatorRansacL2>(motionModel(arg(prefix + "model")));
  183. RansacParams ransac = est->ransacParams();
  184. if (arg(prefix + "subset") != "auto")
  185. ransac.size = argi(prefix + "subset");
  186. if (arg(prefix + "thresh") != "auto")
  187. ransac.thresh = argf(prefix + "thresh");
  188. ransac.eps = argf(prefix + "outlier-ratio");
  189. est->setRansacParams(ransac);
  190. est->setMinInlierRatio(argf(prefix + "min-inlier-ratio"));
  191. Ptr<IOutlierRejector> outlierRejector = makePtr<NullOutlierRejector>();
  192. if (arg(prefix + "local-outlier-rejection") == "yes")
  193. {
  194. Ptr<TranslationBasedLocalOutlierRejector> tblor = makePtr<TranslationBasedLocalOutlierRejector>();
  195. RansacParams ransacParams = tblor->ransacParams();
  196. if (arg(prefix + "thresh") != "auto")
  197. ransacParams.thresh = argf(prefix + "thresh");
  198. tblor->setRansacParams(ransacParams);
  199. outlierRejector = tblor;
  200. }
  201. #if defined(HAVE_OPENCV_CUDAIMGPROC) && defined(HAVE_OPENCV_CUDAOPTFLOW)
  202. if (gpu)
  203. {
  204. Ptr<KeypointBasedMotionEstimatorGpu> kbest = makePtr<KeypointBasedMotionEstimatorGpu>(est);
  205. kbest->setOutlierRejector(outlierRejector);
  206. return kbest;
  207. }
  208. #else
  209. CV_Assert(gpu == false && "CUDA modules are not available");
  210. #endif
  211. Ptr<KeypointBasedMotionEstimator> kbest = makePtr<KeypointBasedMotionEstimator>(est);
  212. kbest->setDetector(GFTTDetector::create(argi(prefix + "nkps")));
  213. kbest->setOutlierRejector(outlierRejector);
  214. return kbest;
  215. }
  216. private:
  217. bool gpu;
  218. string prefix;
  219. };
  220. class MotionEstimatorL1Builder : public IMotionEstimatorBuilder
  221. {
  222. public:
  223. MotionEstimatorL1Builder(CommandLineParser &command, bool use_gpu, const string &_prefix = "")
  224. : IMotionEstimatorBuilder(command), gpu(use_gpu), prefix(_prefix) {}
  225. virtual Ptr<ImageMotionEstimatorBase> build() CV_OVERRIDE
  226. {
  227. Ptr<MotionEstimatorL1> est = makePtr<MotionEstimatorL1>(motionModel(arg(prefix + "model")));
  228. Ptr<IOutlierRejector> outlierRejector = makePtr<NullOutlierRejector>();
  229. if (arg(prefix + "local-outlier-rejection") == "yes")
  230. {
  231. Ptr<TranslationBasedLocalOutlierRejector> tblor = makePtr<TranslationBasedLocalOutlierRejector>();
  232. RansacParams ransacParams = tblor->ransacParams();
  233. if (arg(prefix + "thresh") != "auto")
  234. ransacParams.thresh = argf(prefix + "thresh");
  235. tblor->setRansacParams(ransacParams);
  236. outlierRejector = tblor;
  237. }
  238. #if defined(HAVE_OPENCV_CUDAIMGPROC) && defined(HAVE_OPENCV_CUDAOPTFLOW)
  239. if (gpu)
  240. {
  241. Ptr<KeypointBasedMotionEstimatorGpu> kbest = makePtr<KeypointBasedMotionEstimatorGpu>(est);
  242. kbest->setOutlierRejector(outlierRejector);
  243. return kbest;
  244. }
  245. #else
  246. CV_Assert(gpu == false && "CUDA modules are not available");
  247. #endif
  248. Ptr<KeypointBasedMotionEstimator> kbest = makePtr<KeypointBasedMotionEstimator>(est);
  249. kbest->setDetector(GFTTDetector::create(argi(prefix + "nkps")));
  250. kbest->setOutlierRejector(outlierRejector);
  251. return kbest;
  252. }
  253. private:
  254. bool gpu;
  255. string prefix;
  256. };
  257. int main(int argc, const char **argv)
  258. {
  259. try
  260. {
  261. const char *keys =
  262. "{ @1 | | }"
  263. "{ m model | affine | }"
  264. "{ lp lin-prog-motion-est | no | }"
  265. "{ subset | auto | }"
  266. "{ thresh | auto | }"
  267. "{ outlier-ratio | 0.5 | }"
  268. "{ min-inlier-ratio | 0.1 | }"
  269. "{ nkps | 1000 | }"
  270. "{ extra-kps | 0 | }"
  271. "{ local-outlier-rejection | no | }"
  272. "{ feature-masks | no | }"
  273. "{ sm save-motions | no | }"
  274. "{ lm load-motions | no | }"
  275. "{ r radius | 15 | }"
  276. "{ stdev | auto | }"
  277. "{ lps lin-prog-stab | no | }"
  278. "{ lps-trim-ratio | auto | }"
  279. "{ lps-w1 | 1 | }"
  280. "{ lps-w2 | 10 | }"
  281. "{ lps-w3 | 100 | }"
  282. "{ lps-w4 | 100 | }"
  283. "{ deblur | no | }"
  284. "{ deblur-sens | 0.1 | }"
  285. "{ et est-trim | yes | }"
  286. "{ t trim-ratio | 0.1 | }"
  287. "{ ic incl-constr | no | }"
  288. "{ bm border-mode | replicate | }"
  289. "{ mosaic | no | }"
  290. "{ ms mosaic-stdev | 10.0 | }"
  291. "{ mi motion-inpaint | no | }"
  292. "{ mi-dist-thresh | 5.0 | }"
  293. "{ ci color-inpaint | no | }"
  294. "{ ci-radius | 2 | }"
  295. "{ ws wobble-suppress | no | }"
  296. "{ ws-period | 30 | }"
  297. "{ ws-model | homography | }"
  298. "{ ws-subset | auto | }"
  299. "{ ws-thresh | auto | }"
  300. "{ ws-outlier-ratio | 0.5 | }"
  301. "{ ws-min-inlier-ratio | 0.1 | }"
  302. "{ ws-nkps | 1000 | }"
  303. "{ ws-extra-kps | 0 | }"
  304. "{ ws-local-outlier-rejection | no | }"
  305. "{ ws-lp | no | }"
  306. "{ sm2 save-motions2 | no | }"
  307. "{ lm2 load-motions2 | no | }"
  308. "{ gpu | no | }"
  309. "{ o output | stabilized.avi | }"
  310. "{ fps | auto | }"
  311. "{ q quiet | | }"
  312. "{ h help | | }";
  313. CommandLineParser cmd(argc, argv, keys);
  314. // parse command arguments
  315. if (argb("help"))
  316. {
  317. printHelp();
  318. return 0;
  319. }
  320. if (arg("gpu") == "yes")
  321. {
  322. cout << "initializing GPU..."; cout.flush();
  323. Mat hostTmp = Mat::zeros(1, 1, CV_32F);
  324. cuda::GpuMat deviceTmp;
  325. deviceTmp.upload(hostTmp);
  326. cout << endl;
  327. }
  328. StabilizerBase *stabilizer = 0;
  329. // check if source video is specified
  330. string inputPath = arg(0);
  331. if (inputPath.empty())
  332. throw runtime_error("specify video file path");
  333. // get source video parameters
  334. Ptr<VideoFileSource> source = makePtr<VideoFileSource>(inputPath);
  335. cout << "frame count (rough): " << source->count() << endl;
  336. if (arg("fps") == "auto")
  337. outputFps = source->fps();
  338. else
  339. outputFps = argd("fps");
  340. // prepare motion estimation builders
  341. Ptr<IMotionEstimatorBuilder> motionEstBuilder;
  342. if (arg("lin-prog-motion-est") == "yes")
  343. motionEstBuilder.reset(new MotionEstimatorL1Builder(cmd, arg("gpu") == "yes"));
  344. else
  345. motionEstBuilder.reset(new MotionEstimatorRansacL2Builder(cmd, arg("gpu") == "yes"));
  346. Ptr<IMotionEstimatorBuilder> wsMotionEstBuilder;
  347. if (arg("ws-lp") == "yes")
  348. wsMotionEstBuilder.reset(new MotionEstimatorL1Builder(cmd, arg("gpu") == "yes", "ws-"));
  349. else
  350. wsMotionEstBuilder.reset(new MotionEstimatorRansacL2Builder(cmd, arg("gpu") == "yes", "ws-"));
  351. // determine whether we must use one pass or two pass stabilizer
  352. bool isTwoPass =
  353. arg("est-trim") == "yes" || arg("wobble-suppress") == "yes" || arg("lin-prog-stab") == "yes";
  354. if (isTwoPass)
  355. {
  356. // we must use two pass stabilizer
  357. TwoPassStabilizer *twoPassStabilizer = new TwoPassStabilizer();
  358. stabilizer = twoPassStabilizer;
  359. twoPassStabilizer->setEstimateTrimRatio(arg("est-trim") == "yes");
  360. // determine stabilization technique
  361. if (arg("lin-prog-stab") == "yes")
  362. {
  363. Ptr<LpMotionStabilizer> stab = makePtr<LpMotionStabilizer>();
  364. stab->setFrameSize(Size(source->width(), source->height()));
  365. stab->setTrimRatio(arg("lps-trim-ratio") == "auto" ? argf("trim-ratio") : argf("lps-trim-ratio"));
  366. stab->setWeight1(argf("lps-w1"));
  367. stab->setWeight2(argf("lps-w2"));
  368. stab->setWeight3(argf("lps-w3"));
  369. stab->setWeight4(argf("lps-w4"));
  370. twoPassStabilizer->setMotionStabilizer(stab);
  371. }
  372. else if (arg("stdev") == "auto")
  373. twoPassStabilizer->setMotionStabilizer(makePtr<GaussianMotionFilter>(argi("radius")));
  374. else
  375. twoPassStabilizer->setMotionStabilizer(makePtr<GaussianMotionFilter>(argi("radius"), argf("stdev")));
  376. // init wobble suppressor if necessary
  377. if (arg("wobble-suppress") == "yes")
  378. {
  379. Ptr<MoreAccurateMotionWobbleSuppressorBase> ws = makePtr<MoreAccurateMotionWobbleSuppressor>();
  380. if (arg("gpu") == "yes")
  381. #ifdef HAVE_OPENCV_CUDAWARPING
  382. ws = makePtr<MoreAccurateMotionWobbleSuppressorGpu>();
  383. #else
  384. throw runtime_error("OpenCV is built without CUDA support");
  385. #endif
  386. ws->setMotionEstimator(wsMotionEstBuilder->build());
  387. ws->setPeriod(argi("ws-period"));
  388. twoPassStabilizer->setWobbleSuppressor(ws);
  389. MotionModel model = ws->motionEstimator()->motionModel();
  390. if (arg("load-motions2") != "no")
  391. {
  392. ws->setMotionEstimator(makePtr<FromFileMotionReader>(arg("load-motions2")));
  393. ws->motionEstimator()->setMotionModel(model);
  394. }
  395. if (arg("save-motions2") != "no")
  396. {
  397. ws->setMotionEstimator(makePtr<ToFileMotionWriter>(arg("save-motions2"), ws->motionEstimator()));
  398. ws->motionEstimator()->setMotionModel(model);
  399. }
  400. }
  401. }
  402. else
  403. {
  404. // we must use one pass stabilizer
  405. OnePassStabilizer *onePassStabilizer = new OnePassStabilizer();
  406. stabilizer = onePassStabilizer;
  407. if (arg("stdev") == "auto")
  408. onePassStabilizer->setMotionFilter(makePtr<GaussianMotionFilter>(argi("radius")));
  409. else
  410. onePassStabilizer->setMotionFilter(makePtr<GaussianMotionFilter>(argi("radius"), argf("stdev")));
  411. }
  412. stabilizer->setFrameSource(source);
  413. stabilizer->setMotionEstimator(motionEstBuilder->build());
  414. if (arg("feature-masks") != "no")
  415. {
  416. Ptr<MaskFrameSource> maskSource = makePtr<MaskFrameSource>(
  417. makePtr<VideoFileSource>(arg("feature-masks")));
  418. std::function<void(Mat&)> maskCallback = [](Mat & inputFrame)
  419. {
  420. cv::cvtColor(inputFrame, inputFrame, cv::COLOR_BGR2GRAY);
  421. threshold(inputFrame, inputFrame, 127, 255, THRESH_BINARY);
  422. };
  423. maskSource->setMaskCallback(maskCallback);
  424. stabilizer->setMaskSource(maskSource);
  425. }
  426. // cast stabilizer to simple frame source interface to read stabilized frames
  427. stabilizedFrames.reset(dynamic_cast<IFrameSource*>(stabilizer));
  428. MotionModel model = stabilizer->motionEstimator()->motionModel();
  429. if (arg("load-motions") != "no")
  430. {
  431. stabilizer->setMotionEstimator(makePtr<FromFileMotionReader>(arg("load-motions")));
  432. stabilizer->motionEstimator()->setMotionModel(model);
  433. }
  434. if (arg("save-motions") != "no")
  435. {
  436. stabilizer->setMotionEstimator(makePtr<ToFileMotionWriter>(arg("save-motions"), stabilizer->motionEstimator()));
  437. stabilizer->motionEstimator()->setMotionModel(model);
  438. }
  439. stabilizer->setRadius(argi("radius"));
  440. // init deblurer
  441. if (arg("deblur") == "yes")
  442. {
  443. Ptr<WeightingDeblurer> deblurer = makePtr<WeightingDeblurer>();
  444. deblurer->setRadius(argi("radius"));
  445. deblurer->setSensitivity(argf("deblur-sens"));
  446. stabilizer->setDeblurer(deblurer);
  447. }
  448. // set up trimming parameters
  449. stabilizer->setTrimRatio(argf("trim-ratio"));
  450. stabilizer->setCorrectionForInclusion(arg("incl-constr") == "yes");
  451. if (arg("border-mode") == "reflect")
  452. stabilizer->setBorderMode(BORDER_REFLECT);
  453. else if (arg("border-mode") == "replicate")
  454. stabilizer->setBorderMode(BORDER_REPLICATE);
  455. else if (arg("border-mode") == "const")
  456. stabilizer->setBorderMode(BORDER_CONSTANT);
  457. else
  458. throw runtime_error("unknown border extrapolation mode: "
  459. + cmd.get<string>("border-mode"));
  460. // init inpainter
  461. InpaintingPipeline *inpainters = new InpaintingPipeline();
  462. Ptr<InpainterBase> inpainters_(inpainters);
  463. if (arg("mosaic") == "yes")
  464. {
  465. Ptr<ConsistentMosaicInpainter> inp = makePtr<ConsistentMosaicInpainter>();
  466. inp->setStdevThresh(argf("mosaic-stdev"));
  467. inpainters->pushBack(inp);
  468. }
  469. if (arg("motion-inpaint") == "yes")
  470. {
  471. Ptr<MotionInpainter> inp = makePtr<MotionInpainter>();
  472. inp->setDistThreshold(argf("mi-dist-thresh"));
  473. inpainters->pushBack(inp);
  474. }
  475. if (arg("color-inpaint") == "average")
  476. inpainters->pushBack(makePtr<ColorAverageInpainter>());
  477. else if (arg("color-inpaint") == "ns")
  478. inpainters->pushBack(makePtr<ColorInpainter>(int(INPAINT_NS), argd("ci-radius")));
  479. else if (arg("color-inpaint") == "telea")
  480. inpainters->pushBack(makePtr<ColorInpainter>(int(INPAINT_TELEA), argd("ci-radius")));
  481. else if (arg("color-inpaint") != "no")
  482. throw runtime_error("unknown color inpainting method: " + arg("color-inpaint"));
  483. if (!inpainters->empty())
  484. {
  485. inpainters->setRadius(argi("radius"));
  486. stabilizer->setInpainter(inpainters_);
  487. }
  488. if (arg("output") != "no")
  489. outputPath = arg("output");
  490. quietMode = argb("quiet");
  491. run();
  492. }
  493. catch (const exception &e)
  494. {
  495. cout << "error: " << e.what() << endl;
  496. stabilizedFrames.release();
  497. return -1;
  498. }
  499. stabilizedFrames.release();
  500. return 0;
  501. }
  502. MotionModel motionModel(const string &str)
  503. {
  504. if (str == "transl")
  505. return MM_TRANSLATION;
  506. if (str == "transl_and_scale")
  507. return MM_TRANSLATION_AND_SCALE;
  508. if (str == "rigid")
  509. return MM_RIGID;
  510. if (str == "similarity")
  511. return MM_SIMILARITY;
  512. if (str == "affine")
  513. return MM_AFFINE;
  514. if (str == "homography")
  515. return MM_HOMOGRAPHY;
  516. throw runtime_error("unknown motion model: " + str);
  517. }