From 31498ebbeab973d59203d9e206c089a7bd849d3f Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 7 Nov 2018 15:49:35 +0300 Subject: [PATCH] videostab: move sample to opencv_contrib --- samples/cpp/CMakeLists.txt | 1 - samples/cpp/videostab.cpp | 566 ------------------------------------- 2 files changed, 567 deletions(-) delete mode 100644 samples/cpp/videostab.cpp diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 131681e61c..1a177d346c 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -14,7 +14,6 @@ set(OPENCV_CPP_SAMPLES_REQUIRED_DEPS opencv_features2d opencv_calib3d opencv_stitching - opencv_videostab ${OPENCV_MODULES_PUBLIC} ${OpenCV_LIB_COMPONENTS}) ocv_check_dependencies(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS}) diff --git a/samples/cpp/videostab.cpp b/samples/cpp/videostab.cpp deleted file mode 100644 index 15d68dc2dd..0000000000 --- a/samples/cpp/videostab.cpp +++ /dev/null @@ -1,566 +0,0 @@ -#include -#include -#include -#include -#include -#include "opencv2/core.hpp" -#include -#include "opencv2/video.hpp" -#include "opencv2/imgproc.hpp" -#include "opencv2/videoio.hpp" -#include "opencv2/highgui.hpp" -#include "opencv2/videostab.hpp" -#include "opencv2/opencv_modules.hpp" - -#define arg(name) cmd.get(name) -#define argb(name) cmd.get(name) -#define argi(name) cmd.get(name) -#define argf(name) cmd.get(name) -#define argd(name) cmd.get(name) - -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(); -MotionModel motionModel(const string &str); - - -void run() -{ - VideoWriter writer; - Mat stabilizedFrame; - int nframes = 0; - - // for each stabilized frame - while (!(stabilizedFrame = stabilizedFrames->nextFrame()).empty()) - { - nframes++; - - // init writer (once) and save stabilized frame - if (!outputPath.empty()) - { - if (!writer.isOpened()) - writer.open(outputPath, VideoWriter::fourcc('X','V','I','D'), - outputFps, stabilizedFrame.size()); - writer << stabilizedFrame; - } - - // show stabilized frame - if (!quietMode) - { - imshow("stabilizedFrame", stabilizedFrame); - char key = static_cast(waitKey(3)); - if (key == 27) { cout << endl; break; } - } - } - - cout << "processed frames: " << nframes << endl - << "finished\n"; -} - - -void printHelp() -{ - cout << "OpenCV video stabilizer.\n" - "Usage: videostab [arguments]\n\n" - "Arguments:\n" - " -m=, --model=(transl|transl_and_scale|rigid|similarity|affine|homography)\n" - " Set motion model. The default is affine.\n" - " -lp=, --lin-prog-motion-est=(yes|no)\n" - " Turn on/off LP based motion estimation. The default is no.\n" - " --subset=(|auto)\n" - " Number of random samples per one motion hypothesis. The default is auto.\n" - " --thresh=(|auto)\n" - " Maximum error to classify match as inlier. The default is auto.\n" - " --outlier-ratio=\n" - " Motion estimation outlier ratio hypothesis. The default is 0.5.\n" - " --min-inlier-ratio=\n" - " Minimum inlier ratio to decide if estimated motion is OK. The default is 0.1.\n" - " --nkps=\n" - " Number of keypoints to find in each frame. The default is 1000.\n" - " --local-outlier-rejection=(yes|no)\n" - " Perform local outlier rejection. The default is no.\n\n" - " -sm=, --save-motions=(|no)\n" - " Save estimated motions into file. The default is no.\n" - " -lm=, --load-motions=(|no)\n" - " Load motions from file. The default is no.\n\n" - " -r=, --radius=\n" - " Set sliding window radius. The default is 15.\n" - " --stdev=(|auto)\n" - " Set smoothing weights standard deviation. The default is auto\n" - " (i.e. sqrt(radius)).\n" - " -lps=, --lin-prog-stab=(yes|no)\n" - " Turn on/off linear programming based stabilization method.\n" - " --lps-trim-ratio=(|auto)\n" - " Trimming ratio used in linear programming based method.\n" - " --lps-w1=(|1)\n" - " 1st derivative weight. The default is 1.\n" - " --lps-w2=(|10)\n" - " 2nd derivative weight. The default is 10.\n" - " --lps-w3=(|100)\n" - " 3rd derivative weight. The default is 100.\n" - " --lps-w4=(|100)\n" - " Non-translation motion components weight. The default is 100.\n\n" - " --deblur=(yes|no)\n" - " Do deblurring.\n" - " --deblur-sens=\n" - " Set deblurring sensitivity (from 0 to +inf). The default is 0.1.\n\n" - " -t=, --trim-ratio=\n" - " Set trimming ratio (from 0 to 0.5). The default is 0.1.\n" - " -et=, --est-trim=(yes|no)\n" - " Estimate trim ratio automatically. The default is yes.\n" - " -ic=, --incl-constr=(yes|no)\n" - " Ensure the inclusion constraint is always satisfied. The default is no.\n\n" - " -bm=, --border-mode=(replicate|reflect|const)\n" - " Set border extrapolation mode. The default is replicate.\n\n" - " --mosaic=(yes|no)\n" - " Do consistent mosaicing. The default is no.\n" - " --mosaic-stdev=\n" - " Consistent mosaicing stdev threshold. The default is 10.0.\n\n" - " -mi=, --motion-inpaint=(yes|no)\n" - " Do motion inpainting (requires CUDA support). The default is no.\n" - " --mi-dist-thresh=\n" - " Estimated flow distance threshold for motion inpainting. The default is 5.0.\n\n" - " -ci=, --color-inpaint=(no|average|ns|telea)\n" - " Do color inpainting. The default is no.\n" - " --ci-radius=\n" - " Set color inpainting radius (for ns and telea options only).\n" - " The default is 2.0\n\n" - " -ws=, --wobble-suppress=(yes|no)\n" - " Perform wobble suppression. The default is no.\n" - " --ws-lp=(yes|no)\n" - " Turn on/off LP based motion estimation. The default is no.\n" - " --ws-period=\n" - " Set wobble suppression period. The default is 30.\n" - " --ws-model=(transl|transl_and_scale|rigid|similarity|affine|homography)\n" - " Set wobble suppression motion model (must have more DOF than motion \n" - " estimation model). The default is homography.\n" - " --ws-subset=(|auto)\n" - " Number of random samples per one motion hypothesis. The default is auto.\n" - " --ws-thresh=(|auto)\n" - " Maximum error to classify match as inlier. The default is auto.\n" - " --ws-outlier-ratio=\n" - " Motion estimation outlier ratio hypothesis. The default is 0.5.\n" - " --ws-min-inlier-ratio=\n" - " Minimum inlier ratio to decide if estimated motion is OK. The default is 0.1.\n" - " --ws-nkps=\n" - " Number of keypoints to find in each frame. The default is 1000.\n" - " --ws-local-outlier-rejection=(yes|no)\n" - " Perform local outlier rejection. The default is no.\n\n" - " -sm2=, --save-motions2=(|no)\n" - " Save motions estimated for wobble suppression. The default is no.\n" - " -lm2=, --load-motions2=(|no)\n" - " Load motions for wobble suppression from file. The default is no.\n\n" - " -gpu=(yes|no)\n" - " Use CUDA optimization whenever possible. The default is no.\n\n" - " -o=, --output=(no|)\n" - " Set output file path explicitly. The default is stabilized.avi.\n" - " --fps=(|auto)\n" - " Set output video FPS explicitly. By default the source FPS is used (auto).\n" - " -q, --quiet\n" - " Don't show output video frames.\n\n" - " -h, --help\n" - " Print help.\n\n" - "Note: some argument configurations lead to two passes, some to single pass.\n\n"; -} - -// motion estimator builders are for concise creation of motion estimators - -class IMotionEstimatorBuilder -{ -public: - virtual ~IMotionEstimatorBuilder() {} - virtual Ptr build() = 0; -protected: - IMotionEstimatorBuilder(CommandLineParser &command) : cmd(command) {} - CommandLineParser cmd; -}; - - -class MotionEstimatorRansacL2Builder : public IMotionEstimatorBuilder -{ -public: - MotionEstimatorRansacL2Builder(CommandLineParser &command, bool use_gpu, const string &_prefix = "") - : IMotionEstimatorBuilder(command), gpu(use_gpu), prefix(_prefix) {} - - virtual Ptr build() CV_OVERRIDE - { - Ptr est = makePtr(motionModel(arg(prefix + "model"))); - - RansacParams ransac = est->ransacParams(); - if (arg(prefix + "subset") != "auto") - ransac.size = argi(prefix + "subset"); - if (arg(prefix + "thresh") != "auto") - ransac.thresh = argf(prefix + "thresh"); - ransac.eps = argf(prefix + "outlier-ratio"); - est->setRansacParams(ransac); - - est->setMinInlierRatio(argf(prefix + "min-inlier-ratio")); - - Ptr outlierRejector = makePtr(); - if (arg(prefix + "local-outlier-rejection") == "yes") - { - Ptr tblor = makePtr(); - RansacParams ransacParams = tblor->ransacParams(); - if (arg(prefix + "thresh") != "auto") - ransacParams.thresh = argf(prefix + "thresh"); - tblor->setRansacParams(ransacParams); - outlierRejector = tblor; - } - -#if defined(HAVE_OPENCV_CUDAIMGPROC) && defined(HAVE_OPENCV_CUDAOPTFLOW) - if (gpu) - { - Ptr kbest = makePtr(est); - kbest->setOutlierRejector(outlierRejector); - return kbest; - } -#else - CV_Assert(gpu == false && "CUDA modules are not available"); -#endif - - Ptr kbest = makePtr(est); - kbest->setDetector(GFTTDetector::create(argi(prefix + "nkps"))); - kbest->setOutlierRejector(outlierRejector); - return kbest; - } -private: - bool gpu; - string prefix; -}; - - -class MotionEstimatorL1Builder : public IMotionEstimatorBuilder -{ -public: - MotionEstimatorL1Builder(CommandLineParser &command, bool use_gpu, const string &_prefix = "") - : IMotionEstimatorBuilder(command), gpu(use_gpu), prefix(_prefix) {} - - virtual Ptr build() CV_OVERRIDE - { - Ptr est = makePtr(motionModel(arg(prefix + "model"))); - - Ptr outlierRejector = makePtr(); - if (arg(prefix + "local-outlier-rejection") == "yes") - { - Ptr tblor = makePtr(); - RansacParams ransacParams = tblor->ransacParams(); - if (arg(prefix + "thresh") != "auto") - ransacParams.thresh = argf(prefix + "thresh"); - tblor->setRansacParams(ransacParams); - outlierRejector = tblor; - } - -#if defined(HAVE_OPENCV_CUDAIMGPROC) && defined(HAVE_OPENCV_CUDAOPTFLOW) - if (gpu) - { - Ptr kbest = makePtr(est); - kbest->setOutlierRejector(outlierRejector); - return kbest; - } -#else - CV_Assert(gpu == false && "CUDA modules are not available"); -#endif - - Ptr kbest = makePtr(est); - kbest->setDetector(GFTTDetector::create(argi(prefix + "nkps"))); - kbest->setOutlierRejector(outlierRejector); - return kbest; - } -private: - bool gpu; - string prefix; -}; - - -int main(int argc, const char **argv) -{ - try - { - const char *keys = - "{ @1 | | }" - "{ m model | affine | }" - "{ lp lin-prog-motion-est | no | }" - "{ subset | auto | }" - "{ thresh | auto | }" - "{ outlier-ratio | 0.5 | }" - "{ min-inlier-ratio | 0.1 | }" - "{ nkps | 1000 | }" - "{ extra-kps | 0 | }" - "{ local-outlier-rejection | no | }" - "{ sm save-motions | no | }" - "{ lm load-motions | no | }" - "{ r radius | 15 | }" - "{ stdev | auto | }" - "{ lps lin-prog-stab | no | }" - "{ lps-trim-ratio | auto | }" - "{ lps-w1 | 1 | }" - "{ lps-w2 | 10 | }" - "{ lps-w3 | 100 | }" - "{ lps-w4 | 100 | }" - "{ deblur | no | }" - "{ deblur-sens | 0.1 | }" - "{ et est-trim | yes | }" - "{ t trim-ratio | 0.1 | }" - "{ ic incl-constr | no | }" - "{ bm border-mode | replicate | }" - "{ mosaic | no | }" - "{ ms mosaic-stdev | 10.0 | }" - "{ mi motion-inpaint | no | }" - "{ mi-dist-thresh | 5.0 | }" - "{ ci color-inpaint | no | }" - "{ ci-radius | 2 | }" - "{ ws wobble-suppress | no | }" - "{ ws-period | 30 | }" - "{ ws-model | homography | }" - "{ ws-subset | auto | }" - "{ ws-thresh | auto | }" - "{ ws-outlier-ratio | 0.5 | }" - "{ ws-min-inlier-ratio | 0.1 | }" - "{ ws-nkps | 1000 | }" - "{ ws-extra-kps | 0 | }" - "{ ws-local-outlier-rejection | no | }" - "{ ws-lp | no | }" - "{ sm2 save-motions2 | no | }" - "{ lm2 load-motions2 | no | }" - "{ gpu | no | }" - "{ o output | stabilized.avi | }" - "{ fps | auto | }" - "{ q quiet | | }" - "{ h help | | }"; - CommandLineParser cmd(argc, argv, keys); - - // parse command arguments - - if (argb("help")) - { - printHelp(); - return 0; - } - - if (arg("gpu") == "yes") - { - cout << "initializing GPU..."; cout.flush(); - Mat hostTmp = Mat::zeros(1, 1, CV_32F); - cuda::GpuMat deviceTmp; - deviceTmp.upload(hostTmp); - cout << endl; - } - - StabilizerBase *stabilizer = 0; - - // check if source video is specified - - string inputPath = arg(0); - if (inputPath.empty()) - throw runtime_error("specify video file path"); - - // get source video parameters - - Ptr source = makePtr(inputPath); - cout << "frame count (rough): " << source->count() << endl; - if (arg("fps") == "auto") - outputFps = source->fps(); - else - outputFps = argd("fps"); - - // prepare motion estimation builders - - Ptr motionEstBuilder; - if (arg("lin-prog-motion-est") == "yes") - motionEstBuilder.reset(new MotionEstimatorL1Builder(cmd, arg("gpu") == "yes")); - else - motionEstBuilder.reset(new MotionEstimatorRansacL2Builder(cmd, arg("gpu") == "yes")); - - Ptr wsMotionEstBuilder; - if (arg("ws-lp") == "yes") - wsMotionEstBuilder.reset(new MotionEstimatorL1Builder(cmd, arg("gpu") == "yes", "ws-")); - else - wsMotionEstBuilder.reset(new MotionEstimatorRansacL2Builder(cmd, arg("gpu") == "yes", "ws-")); - - // determine whether we must use one pass or two pass stabilizer - bool isTwoPass = - arg("est-trim") == "yes" || arg("wobble-suppress") == "yes" || arg("lin-prog-stab") == "yes"; - - if (isTwoPass) - { - // we must use two pass stabilizer - - TwoPassStabilizer *twoPassStabilizer = new TwoPassStabilizer(); - stabilizer = twoPassStabilizer; - twoPassStabilizer->setEstimateTrimRatio(arg("est-trim") == "yes"); - - // determine stabilization technique - - if (arg("lin-prog-stab") == "yes") - { - Ptr stab = makePtr(); - stab->setFrameSize(Size(source->width(), source->height())); - stab->setTrimRatio(arg("lps-trim-ratio") == "auto" ? argf("trim-ratio") : argf("lps-trim-ratio")); - stab->setWeight1(argf("lps-w1")); - stab->setWeight2(argf("lps-w2")); - stab->setWeight3(argf("lps-w3")); - stab->setWeight4(argf("lps-w4")); - twoPassStabilizer->setMotionStabilizer(stab); - } - else if (arg("stdev") == "auto") - twoPassStabilizer->setMotionStabilizer(makePtr(argi("radius"))); - else - twoPassStabilizer->setMotionStabilizer(makePtr(argi("radius"), argf("stdev"))); - - // init wobble suppressor if necessary - - if (arg("wobble-suppress") == "yes") - { - Ptr ws = makePtr(); - if (arg("gpu") == "yes") -#ifdef HAVE_OPENCV_CUDAWARPING - ws = makePtr(); -#else - throw runtime_error("OpenCV is built without CUDA support"); -#endif - - ws->setMotionEstimator(wsMotionEstBuilder->build()); - ws->setPeriod(argi("ws-period")); - twoPassStabilizer->setWobbleSuppressor(ws); - - MotionModel model = ws->motionEstimator()->motionModel(); - if (arg("load-motions2") != "no") - { - ws->setMotionEstimator(makePtr(arg("load-motions2"))); - ws->motionEstimator()->setMotionModel(model); - } - if (arg("save-motions2") != "no") - { - ws->setMotionEstimator(makePtr(arg("save-motions2"), ws->motionEstimator())); - ws->motionEstimator()->setMotionModel(model); - } - } - } - else - { - // we must use one pass stabilizer - - OnePassStabilizer *onePassStabilizer = new OnePassStabilizer(); - stabilizer = onePassStabilizer; - if (arg("stdev") == "auto") - onePassStabilizer->setMotionFilter(makePtr(argi("radius"))); - else - onePassStabilizer->setMotionFilter(makePtr(argi("radius"), argf("stdev"))); - } - - stabilizer->setFrameSource(source); - stabilizer->setMotionEstimator(motionEstBuilder->build()); - - // cast stabilizer to simple frame source interface to read stabilized frames - stabilizedFrames.reset(dynamic_cast(stabilizer)); - - MotionModel model = stabilizer->motionEstimator()->motionModel(); - if (arg("load-motions") != "no") - { - stabilizer->setMotionEstimator(makePtr(arg("load-motions"))); - stabilizer->motionEstimator()->setMotionModel(model); - } - if (arg("save-motions") != "no") - { - stabilizer->setMotionEstimator(makePtr(arg("save-motions"), stabilizer->motionEstimator())); - stabilizer->motionEstimator()->setMotionModel(model); - } - - stabilizer->setRadius(argi("radius")); - - // init deblurer - if (arg("deblur") == "yes") - { - Ptr deblurer = makePtr(); - deblurer->setRadius(argi("radius")); - deblurer->setSensitivity(argf("deblur-sens")); - stabilizer->setDeblurer(deblurer); - } - - // set up trimming parameters - stabilizer->setTrimRatio(argf("trim-ratio")); - stabilizer->setCorrectionForInclusion(arg("incl-constr") == "yes"); - - if (arg("border-mode") == "reflect") - stabilizer->setBorderMode(BORDER_REFLECT); - else if (arg("border-mode") == "replicate") - stabilizer->setBorderMode(BORDER_REPLICATE); - else if (arg("border-mode") == "const") - stabilizer->setBorderMode(BORDER_CONSTANT); - else - throw runtime_error("unknown border extrapolation mode: " - + cmd.get("border-mode")); - - // init inpainter - InpaintingPipeline *inpainters = new InpaintingPipeline(); - Ptr inpainters_(inpainters); - if (arg("mosaic") == "yes") - { - Ptr inp = makePtr(); - inp->setStdevThresh(argf("mosaic-stdev")); - inpainters->pushBack(inp); - } - if (arg("motion-inpaint") == "yes") - { - Ptr inp = makePtr(); - inp->setDistThreshold(argf("mi-dist-thresh")); - inpainters->pushBack(inp); - } - if (arg("color-inpaint") == "average") - inpainters->pushBack(makePtr()); - else if (arg("color-inpaint") == "ns") - inpainters->pushBack(makePtr(int(INPAINT_NS), argd("ci-radius"))); - else if (arg("color-inpaint") == "telea") - inpainters->pushBack(makePtr(int(INPAINT_TELEA), argd("ci-radius"))); - else if (arg("color-inpaint") != "no") - throw runtime_error("unknown color inpainting method: " + arg("color-inpaint")); - if (!inpainters->empty()) - { - inpainters->setRadius(argi("radius")); - stabilizer->setInpainter(inpainters_); - } - - if (arg("output") != "no") - outputPath = arg("output"); - - quietMode = argb("quiet"); - - run(); - } - catch (const exception &e) - { - cout << "error: " << e.what() << endl; - stabilizedFrames.release(); - return -1; - } - stabilizedFrames.release(); - return 0; -} - - -MotionModel motionModel(const string &str) -{ - if (str == "transl") - return MM_TRANSLATION; - if (str == "transl_and_scale") - return MM_TRANSLATION_AND_SCALE; - if (str == "rigid") - return MM_RIGID; - if (str == "similarity") - return MM_SIMILARITY; - if (str == "affine") - return MM_AFFINE; - if (str == "homography") - return MM_HOMOGRAPHY; - throw runtime_error("unknown motion model: " + str); -}