1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
43 #include "precomp.hpp"
45 #include "opencv2/videostab/inpainting.hpp"
46 #include "opencv2/videostab/global_motion.hpp"
47 #include "opencv2/videostab/fast_marching.hpp"
56 void InpaintingPipeline::setRadius(int val)
58 for (size_t i = 0; i < inpainters_.size(); ++i)
59 inpainters_[i]->setRadius(val);
60 IInpainter::setRadius(val);
64 void InpaintingPipeline::setFrames(const vector<Mat> &val)
66 for (size_t i = 0; i < inpainters_.size(); ++i)
67 inpainters_[i]->setFrames(val);
68 IInpainter::setFrames(val);
72 void InpaintingPipeline::setMotions(const vector<Mat> &val)
74 for (size_t i = 0; i < inpainters_.size(); ++i)
75 inpainters_[i]->setMotions(val);
76 IInpainter::setMotions(val);
80 void InpaintingPipeline::setStabilizedFrames(const vector<Mat> &val)
82 for (size_t i = 0; i < inpainters_.size(); ++i)
83 inpainters_[i]->setStabilizedFrames(val);
84 IInpainter::setStabilizedFrames(val);
88 void InpaintingPipeline::setStabilizationMotions(const vector<Mat> &val)
90 for (size_t i = 0; i < inpainters_.size(); ++i)
91 inpainters_[i]->setStabilizationMotions(val);
92 IInpainter::setStabilizationMotions(val);
96 void InpaintingPipeline::inpaint(int idx, Mat &frame, Mat &mask)
98 for (size_t i = 0; i < inpainters_.size(); ++i)
99 inpainters_[i]->inpaint(idx, frame, mask);
106 Point3_<uchar> color;
107 bool operator <(const Pixel3 &other) const { return intens < other.intens; }
111 ConsistentMosaicInpainter::ConsistentMosaicInpainter()
117 void ConsistentMosaicInpainter::inpaint(int idx, Mat &frame, Mat &mask)
119 CV_Assert(frame.type() == CV_8UC3);
120 CV_Assert(mask.size() == frame.size() && mask.type() == CV_8U);
122 Mat invS = at(idx, *stabilizationMotions_).inv();
123 vector<Mat_<float> > motions(2*radius_ + 1);
124 for (int i = -radius_; i <= radius_; ++i)
125 motions[radius_ + i] = getMotion(idx, idx + i, *motions_) * invS;
129 vector<Pixel3> pixels(2*radius_ + 1);
131 Mat_<Point3_<uchar> > frame_(frame);
132 Mat_<uchar> mask_(mask);
134 for (int y = 0; y < mask.rows; ++y)
136 for (int x = 0; x < mask.cols; ++x)
144 for (int i = -radius_; i <= radius_; ++i)
146 const Mat_<Point3_<uchar> > &framei = at(idx + i, *frames_);
147 const Mat_<float> &Mi = motions[radius_ + i];
148 int xi = cvRound(Mi(0,0)*x + Mi(0,1)*y + Mi(0,2));
149 int yi = cvRound(Mi(1,0)*x + Mi(1,1)*y + Mi(1,2));
150 if (xi >= 0 && xi < framei.cols && yi >= 0 && yi < framei.rows)
152 pixels[n].color = framei(yi, xi);
153 mean += pixels[n].intens = intensity(pixels[n].color);
161 for (int i = 0; i < n; ++i)
162 var += sqr(pixels[i].intens - mean);
163 var /= std::max(n - 1, 1);
165 if (var < stdevThresh_ * stdevThresh_)
167 sort(pixels.begin(), pixels.begin() + n);
169 int c1 = pixels[nh].color.x;
170 int c2 = pixels[nh].color.y;
171 int c3 = pixels[nh].color.z;
174 c1 = (c1 + pixels[nh].color.x) / 2;
175 c2 = (c2 + pixels[nh].color.y) / 2;
176 c3 = (c3 + pixels[nh].color.z) / 2;
178 frame_(y, x) = Point3_<uchar>(
179 static_cast<uchar>(c1),
180 static_cast<uchar>(c2),
181 static_cast<uchar>(c3));
191 class MotionInpaintBody
194 void operator ()(int x, int y)
196 float uEst = 0.f, vEst = 0.f, wSum = 0.f;
198 for (int dy = -rad; dy <= rad; ++dy)
200 for (int dx = -rad; dx <= rad; ++dx)
205 if (qy0 >= 0 && qy0 < mask0.rows && qx0 >= 0 && qx0 < mask0.cols && mask0(qy0,qx0))
207 int qx1 = cvRound(qx0 + flowX(qy0,qx0));
208 int qy1 = cvRound(qy0 + flowY(qy0,qx0));
212 if (qx1 >= 0 && qx1 < mask1.cols && qy1 >= 0 && qy1 < mask1.rows && mask1(qy1,qx1) &&
213 px1 >= 0 && px1 < mask1.cols && py1 >= 0 && py1 < mask1.rows && mask1(py1,px1))
215 float dudx = 0.f, dvdx = 0.f, dudy = 0.f, dvdy = 0.f;
217 if (qx0 > 0 && mask0(qy0,qx0-1))
219 if (qx0+1 < mask0.cols && mask0(qy0,qx0+1))
221 dudx = (flowX(qy0,qx0+1) - flowX(qy0,qx0-1)) * 0.5f;
222 dvdx = (flowY(qy0,qx0+1) - flowY(qy0,qx0-1)) * 0.5f;
226 dudx = flowX(qy0,qx0) - flowX(qy0,qx0-1);
227 dvdx = flowY(qy0,qx0) - flowY(qy0,qx0-1);
230 else if (qx0+1 < mask0.cols && mask0(qy0,qx0+1))
232 dudx = flowX(qy0,qx0+1) - flowX(qy0,qx0);
233 dvdx = flowY(qy0,qx0+1) - flowY(qy0,qx0);
236 if (qy0 > 0 && mask0(qy0-1,qx0))
238 if (qy0+1 < mask0.rows && mask0(qy0+1,qx0))
240 dudy = (flowX(qy0+1,qx0) - flowX(qy0-1,qx0)) * 0.5f;
241 dvdy = (flowY(qy0+1,qx0) - flowY(qy0-1,qx0)) * 0.5f;
245 dudy = flowX(qy0,qx0) - flowX(qy0-1,qx0);
246 dvdy = flowY(qy0,qx0) - flowY(qy0-1,qx0);
249 else if (qy0+1 < mask0.rows && mask0(qy0+1,qx0))
251 dudy = flowX(qy0+1,qx0) - flowX(qy0,qx0);
252 dvdy = flowY(qy0+1,qx0) - flowY(qy0,qx0);
255 Point3_<uchar> cp = frame1(py1,px1), cq = frame1(qy1,qx1);
256 float distColor = sqr(cp.x-cq.x) + sqr(cp.y-cq.y) + sqr(cp.z-cq.z);
257 float w = 1.f / (sqrt(distColor * (dx*dx + dy*dy)) + eps);
259 uEst += w * (flowX(qy0,qx0) - dudx*dx - dudy*dy);
260 vEst += w * (flowY(qy0,qx0) - dvdx*dx - dvdy*dy);
269 flowX(y,x) = uEst / wSum;
270 flowY(y,x) = vEst / wSum;
275 Mat_<Point3_<uchar> > frame1;
276 Mat_<uchar> mask0, mask1;
277 Mat_<float> flowX, flowY;
283 MotionInpainter::MotionInpainter()
286 setOptFlowEstimator(new DensePyrLkOptFlowEstimatorGpu());
288 CV_Error(CV_StsNotImplemented, "Current implementation of MotionInpainter requires GPU");
290 setFlowErrorThreshold(1e-4f);
291 setBorderMode(BORDER_REPLICATE);
295 void MotionInpainter::inpaint(int idx, Mat &frame, Mat &mask)
297 priority_queue<pair<float,int> > neighbors;
298 vector<Mat> motions(2*radius_ + 1);
300 for (int i = -radius_; i <= radius_; ++i)
302 Mat motion0to1 = getMotion(idx, idx + i, *motions_) * at(idx, *stabilizationMotions_).inv();
303 motions[radius_ + i] = motion0to1;
307 float err = alignementError(motion0to1, frame, mask, at(idx + i, *frames_));
308 neighbors.push(make_pair(-err, idx + i));
312 if (mask1_.size() != mask.size())
314 mask1_.create(mask.size());
318 cvtColor(frame, grayFrame_, CV_BGR2GRAY);
320 MotionInpaintBody body;
324 while (!neighbors.empty())
326 int neighbor = neighbors.top().second;
329 Mat motion1to0 = motions[radius_ + neighbor - idx].inv();
331 frame1_ = at(neighbor, *frames_);
333 frame1_, transformedFrame1_, motion1to0(Rect(0,0,3,2)), frame1_.size(),
334 INTER_LINEAR, borderMode_);
335 cvtColor(transformedFrame1_, transformedGrayFrame1_, CV_BGR2GRAY);
338 mask1_, transformedMask1_, motion1to0(Rect(0,0,3,2)), mask1_.size(),
340 erode(transformedMask1_, transformedMask1_, Mat());
342 optFlowEstimator_->run(grayFrame_, transformedGrayFrame1_, flowX_, flowY_, flowErrors_);
345 flowX_, flowY_, flowErrors_, flowErrorThreshold_, mask, transformedMask1_,
350 body.mask0 = flowMask_;
351 body.mask1 = transformedMask1_;
352 body.frame1 = transformedFrame1_;
353 fmm_.run(flowMask_, body);
355 completeFrameAccordingToFlow(
356 flowMask_, flowX_, flowY_, transformedFrame1_, transformedMask1_, frame, mask);
361 class ColorAverageInpaintBody
364 void operator ()(int x, int y)
366 float c1 = 0, c2 = 0, c3 = 0;
369 static const int lut[8][2] = {{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,1}, {1,-1}, {1,0}, {1,1}};
371 for (int i = 0; i < 8; ++i)
373 int qx = x + lut[i][0];
374 int qy = y + lut[i][1];
375 if (qy >= 0 && qy < mask.rows && qx >= 0 && qx < mask.cols && mask(qy,qx))
377 c1 += frame.at<uchar>(qy,3*qx);
378 c2 += frame.at<uchar>(qy,3*qx+1);
379 c3 += frame.at<uchar>(qy,3*qx+2);
384 float wSumInv = 1.f / wSum;
385 frame(y,x) = Point3_<uchar>(
386 static_cast<uchar>(c1*wSumInv),
387 static_cast<uchar>(c2*wSumInv),
388 static_cast<uchar>(c3*wSumInv));
392 cv::Mat_<uchar> mask;
393 cv::Mat_<cv::Point3_<uchar> > frame;
397 void ColorAverageInpainter::inpaint(int /*idx*/, Mat &frame, Mat &mask)
399 ColorAverageInpaintBody body;
402 fmm_.run(mask, body);
406 void ColorInpainter::inpaint(int /*idx*/, Mat &frame, Mat &mask)
408 bitwise_not(mask, invMask_);
409 cv::inpaint(frame, invMask_, frame, radius_, method_);
414 const Mat &flowX, const Mat &flowY, const Mat &errors, float maxError,
415 const Mat &mask0, const Mat &mask1, Mat &flowMask)
417 CV_Assert(flowX.type() == CV_32F && flowX.size() == mask0.size());
418 CV_Assert(flowY.type() == CV_32F && flowY.size() == mask0.size());
419 CV_Assert(errors.type() == CV_32F && errors.size() == mask0.size());
420 CV_Assert(mask0.type() == CV_8U);
421 CV_Assert(mask1.type() == CV_8U && mask1.size() == mask0.size());
423 Mat_<float> flowX_(flowX), flowY_(flowY), errors_(errors);
424 Mat_<uchar> mask0_(mask0), mask1_(mask1);
426 flowMask.create(mask0.size(), CV_8U);
428 Mat_<uchar> flowMask_(flowMask);
430 for (int y0 = 0; y0 < flowMask_.rows; ++y0)
432 for (int x0 = 0; x0 < flowMask_.cols; ++x0)
434 if (mask0_(y0,x0) && errors_(y0,x0) < maxError)
436 int x1 = cvRound(x0 + flowX_(y0,x0));
437 int y1 = cvRound(y0 + flowY_(y0,x0));
439 if (x1 >= 0 && x1 < mask1_.cols && y1 >= 0 && y1 < mask1_.rows && mask1_(y1,x1))
440 flowMask_(y0,x0) = 255;
447 void completeFrameAccordingToFlow(
448 const Mat &flowMask, const Mat &flowX, const Mat &flowY, const Mat &frame1, const Mat &mask1,
449 Mat &frame0, Mat &mask0)
451 CV_Assert(flowMask.type() == CV_8U);
452 CV_Assert(flowX.type() == CV_32F && flowX.size() == flowMask.size());
453 CV_Assert(flowY.type() == CV_32F && flowY.size() == flowMask.size());
454 CV_Assert(frame1.type() == CV_8UC3 && frame1.size() == flowMask.size());
455 CV_Assert(mask1.type() == CV_8U && mask1.size() == flowMask.size());
456 CV_Assert(frame0.type() == CV_8UC3 && frame0.size() == flowMask.size());
457 CV_Assert(mask0.type() == CV_8U && mask0.size() == flowMask.size());
459 Mat_<uchar> flowMask_(flowMask), mask1_(mask1), mask0_(mask0);
460 Mat_<float> flowX_(flowX), flowY_(flowY);
462 for (int y0 = 0; y0 < frame0.rows; ++y0)
464 for (int x0 = 0; x0 < frame0.cols; ++x0)
466 if (!mask0_(y0,x0) && flowMask_(y0,x0))
468 int x1 = cvRound(x0 + flowX_(y0,x0));
469 int y1 = cvRound(y0 + flowY_(y0,x0));
471 if (x1 >= 0 && x1 < frame1.cols && y1 >= 0 && y1 < frame1.rows && mask1_(y1,x1))
473 frame0.at<Point3_<uchar> >(y0,x0) = frame1.at<Point3_<uchar> >(y1,x1);
481 } // namespace videostab