From: Alexey Spizhevoy Date: Tue, 20 Mar 2012 12:24:51 +0000 (+0000) Subject: Added more inpainting methods. Fixed some errors. X-Git-Tag: accepted/2.0/20130307.220821~1079 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dcb5464b3c5a4a090515bd78bcc41a1e8af61a94;p=profile%2Fivi%2Fopencv.git Added more inpainting methods. Fixed some errors. --- diff --git a/modules/videostab/CMakeLists.txt b/modules/videostab/CMakeLists.txt index 56dbae2..ed7f8c4 100644 --- a/modules/videostab/CMakeLists.txt +++ b/modules/videostab/CMakeLists.txt @@ -1,3 +1,3 @@ set(the_description "Video stabilization") -ocv_define_module(videostab opencv_imgproc opencv_features2d opencv_video opencv_highgui OPTIONAL opencv_gpu) +ocv_define_module(videostab opencv_imgproc opencv_features2d opencv_video opencv_highgui opencv_photo OPTIONAL opencv_gpu) diff --git a/modules/videostab/include/opencv2/videostab/frame_source.hpp b/modules/videostab/include/opencv2/videostab/frame_source.hpp index ff83a68..24facb5 100644 --- a/modules/videostab/include/opencv2/videostab/frame_source.hpp +++ b/modules/videostab/include/opencv2/videostab/frame_source.hpp @@ -72,6 +72,7 @@ class CV_EXPORTS VideoFileSource : public IFrameSource { public: VideoFileSource(const std::string &path, bool volatileFrame = false); + virtual void reset(); virtual Mat nextFrame(); diff --git a/modules/videostab/include/opencv2/videostab/inpainting.hpp b/modules/videostab/include/opencv2/videostab/inpainting.hpp index fd65eef..1d83978 100644 --- a/modules/videostab/include/opencv2/videostab/inpainting.hpp +++ b/modules/videostab/include/opencv2/videostab/inpainting.hpp @@ -47,6 +47,7 @@ #include "opencv2/core/core.hpp" #include "opencv2/videostab/optical_flow.hpp" #include "opencv2/videostab/fast_marching.hpp" +#include "opencv2/photo/photo.hpp" namespace cv { @@ -163,6 +164,20 @@ private: FastMarchingMethod fmm_; }; +class CV_EXPORTS ColorInpainter : public IInpainter +{ +public: + ColorInpainter(int method = INPAINT_TELEA, double radius = 2.) + : method_(method), radius_(radius) {} + + virtual void inpaint(int idx, Mat &frame, Mat &mask); + +private: + int method_; + double radius_; + Mat invMask_; +}; + CV_EXPORTS void calcFlowMask( const Mat &flowX, const Mat &flowY, const Mat &errors, float maxError, const Mat &mask0, const Mat &mask1, Mat &flowMask); diff --git a/modules/videostab/src/inpainting.cpp b/modules/videostab/src/inpainting.cpp index db12cb3..c7452dd 100644 --- a/modules/videostab/src/inpainting.cpp +++ b/modules/videostab/src/inpainting.cpp @@ -110,7 +110,7 @@ struct Pixel3 ConsistentMosaicInpainter::ConsistentMosaicInpainter() { - setStdevThresh(10); + setStdevThresh(20); } @@ -190,24 +190,17 @@ class MotionInpaintBody public: void operator ()(int x, int y) { - float uEst = 0.f, vEst = 0.f; - float wSum = 0.f; + float uEst = 0.f, vEst = 0.f, wSum = 0.f; for (int dy = -rad; dy <= rad; ++dy) { for (int dx = -rad; dx <= rad; ++dx) { int qx0 = x + dx; - int qy0 = y + dy; + int qy0 = y + dy; - if (qy0 > 0 && qy0+1 < mask0.rows && qx0 > 0 && qx0+1 < mask0.cols && mask0(qy0,qx0) && - mask0(qy0-1,qx0) && mask0(qy0+1,qx0) && mask0(qy0,qx0-1) && mask0(qy0,qx0+1)) + if (qy0 >= 0 && qy0 < mask0.rows && qx0 >= 0 && qx0 < mask0.cols && mask0(qy0,qx0)) { - float dudx = 0.5f * (flowX(qy0,qx0+1) - flowX(qy0,qx0-1)); - float dvdx = 0.5f * (flowY(qy0,qx0+1) - flowY(qy0,qx0-1)); - float dudy = 0.5f * (flowX(qy0+1,qx0) - flowX(qy0-1,qx0)); - float dvdy = 0.5f * (flowY(qy0+1,qx0) - flowY(qy0-1,qx0)); - int qx1 = cvRound(qx0 + flowX(qy0,qx0)); int qy1 = cvRound(qy0 + flowY(qy0,qx0)); int px1 = qx1 - dx; @@ -216,14 +209,54 @@ public: if (qx1 >= 0 && qx1 < mask1.cols && qy1 >= 0 && qy1 < mask1.rows && mask1(qy1,qx1) && px1 >= 0 && px1 < mask1.cols && py1 >= 0 && py1 < mask1.rows && mask1(py1,px1)) { + float dudx = 0.f, dvdx = 0.f, dudy = 0.f, dvdy = 0.f; + + if (qx0 > 0 && mask0(qy0,qx0-1)) + { + if (qx0+1 < mask0.cols && mask0(qy0,qx0+1)) + { + dudx = (flowX(qy0,qx0+1) - flowX(qy0,qx0-1)) * 0.5f; + dvdx = (flowY(qy0,qx0+1) - flowY(qy0,qx0-1)) * 0.5f; + } + else + { + dudx = flowX(qy0,qx0) - flowX(qy0,qx0-1); + dvdx = flowY(qy0,qx0) - flowY(qy0,qx0-1); + } + } + else if (qx0+1 < mask0.cols && mask0(qy0,qx0+1)) + { + dudx = flowX(qy0,qx0+1) - flowX(qy0,qx0); + dvdx = flowY(qy0,qx0+1) - flowY(qy0,qx0); + } + + if (qy0 > 0 && mask0(qy0-1,qx0)) + { + if (qy0+1 < mask0.rows && mask0(qy0+1,qx0)) + { + dudy = (flowX(qy0+1,qx0) - flowX(qy0-1,qx0)) * 0.5f; + dvdy = (flowY(qy0+1,qx0) - flowY(qy0-1,qx0)) * 0.5f; + } + else + { + dudy = flowX(qy0,qx0) - flowX(qy0-1,qx0); + dvdy = flowY(qy0,qx0) - flowY(qy0-1,qx0); + } + } + else if (qy0+1 < mask0.rows && mask0(qy0+1,qx0)) + { + dudy = flowX(qy0+1,qx0) - flowX(qy0,qx0); + dvdy = flowY(qy0+1,qx0) - flowY(qy0,qx0); + } + Point3_ cp = frame1(py1,px1), cq = frame1(qy1,qx1); float distColor = sqr(cp.x-cq.x) + sqr(cp.y-cq.y) + sqr(cp.z-cq.z); float w = 1.f / (sqrt(distColor * (dx*dx + dy*dy)) + eps); + uEst += w * (flowX(qy0,qx0) - dudx*dx - dudy*dy); vEst += w * (flowY(qy0,qx0) - dvdx*dx - dvdy*dy); wSum += w; } - //else return; } } } @@ -317,7 +350,7 @@ void MotionInpainter::inpaint(int idx, Mat &frame, Mat &mask) fmm_.run(flowMask_, body); completeFrameAccordingToFlow( - flowMask_, flowX_, flowY_, transformedFrame1_, transformedMask1_, frame, mask); + flowMask_, flowX_, flowY_, transformedFrame1_, transformedMask1_, frame, mask); } } @@ -364,6 +397,13 @@ void ColorAverageInpainter::inpaint(int /*idx*/, Mat &frame, Mat &mask) } +void ColorInpainter::inpaint(int /*idx*/, Mat &frame, Mat &mask) +{ + bitwise_not(mask, invMask_); + cv::inpaint(frame, invMask_, frame, radius_, method_); +} + + void calcFlowMask( const Mat &flowX, const Mat &flowY, const Mat &errors, float maxError, const Mat &mask0, const Mat &mask1, Mat &flowMask) diff --git a/samples/cpp/videostab.cpp b/samples/cpp/videostab.cpp index 6616624..68b6219 100644 --- a/samples/cpp/videostab.cpp +++ b/samples/cpp/videostab.cpp @@ -73,7 +73,7 @@ void printHelp() " you can turn it off if you want to use one pass only).\n" " --incl-constr=(yes|no)\n" " Ensure the inclusion constraint is always satisfied. The default is no.\n" - " --border-mode=(replicate|const)\n" + " --border-mode=(replicate|reflect|const)\n" " Set border extrapolation mode. The default is replicate.\n" " --mosaic=(yes|no)\n" " Do consistent mosaicing. The default is no.\n" @@ -81,8 +81,10 @@ void printHelp() " Consistent mosaicing stdev threshold. The default is 10.\n" " --motion-inpaint=(yes|no)\n" " Do motion inpainting (requires GPU support). The default is no.\n" - " --color-inpaint=(yes|no)\n" + " --color-inpaint=(no|average|ns|telea)\n" " Do color inpainting. The defailt is no.\n" + " --color-inpaint-radius=\n" + " Set color inpainting radius (for ns and telea options only).\n" " -o, --output=\n" " Set output file path explicitely. The default is stabilized.avi.\n" " --fps=\n" @@ -115,7 +117,8 @@ int main(int argc, const char **argv) "{ | mosaic | | }" "{ | mosaic-stdev | | }" "{ | motion-inpaint | | }" - "{ | color-inpaint | | }" + "{ | color-inpaint | no | }" + "{ | color-inpaint-radius | | }" "{ o | output | stabilized.avi | }" "{ | fps | | }" "{ q | quiet | false | }" @@ -172,7 +175,7 @@ int main(int argc, const char **argv) if (smoothRadius > 0 && smoothStdev > 0) stabilizer->setMotionFilter(new GaussianMotionFilter(smoothRadius, smoothStdev)); else if (smoothRadius > 0 && smoothStdev < 0) - stabilizer->setMotionFilter(new GaussianMotionFilter(smoothRadius, sqrt(smoothRadius))); + stabilizer->setMotionFilter(new GaussianMotionFilter(smoothRadius, sqrt(static_cast(smoothRadius)))); if (cmd.get("deblur") == "yes") { @@ -191,7 +194,9 @@ int main(int argc, const char **argv) if (!cmd.get("incl-constr").empty()) stabilizer->setInclusionConstraint(cmd.get("incl-constr") == "yes"); - if (cmd.get("border-mode") == "replicate") + if (cmd.get("border-mode") == "reflect") + stabilizer->setBorderMode(BORDER_REFLECT); + else if (cmd.get("border-mode") == "replicate") stabilizer->setBorderMode(BORDER_REPLICATE); else if (cmd.get("border-mode") == "const") stabilizer->setBorderMode(BORDER_CONSTANT); @@ -208,8 +213,30 @@ int main(int argc, const char **argv) } if (cmd.get("motion-inpaint") == "yes") inpainters->pushBack(new MotionInpainter()); - if (cmd.get("color-inpaint") == "yes") - inpainters->pushBack(new ColorAverageInpainter()); + if (!cmd.get("color-inpaint").empty()) + { + if (cmd.get("color-inpaint") == "average") + inpainters->pushBack(new ColorAverageInpainter()); + else if (!cmd.get("color-inpaint-radius").empty()) + { + float radius = cmd.get("color-inpaint-radius"); + if (cmd.get("color-inpaint") == "ns") + inpainters->pushBack(new ColorInpainter(INPAINT_NS, radius)); + else if (cmd.get("color-inpaint") == "telea") + inpainters->pushBack(new ColorInpainter(INPAINT_TELEA, radius)); + else if (cmd.get("color-inpaint") != "no") + throw runtime_error("unknown color inpainting method: " + cmd.get("color-inpaint")); + } + else + { + if (cmd.get("color-inpaint") == "ns") + inpainters->pushBack(new ColorInpainter(INPAINT_NS)); + else if (cmd.get("color-inpaint") == "telea") + inpainters->pushBack(new ColorInpainter(INPAINT_TELEA)); + else if (cmd.get("color-inpaint") != "no") + throw runtime_error("unknown color inpainting method: " + cmd.get("color-inpaint")); + } + } if (!inpainters->empty()) stabilizer->setInpainter(inpainters);