Merge pull request #2424 from GArik:master

videostab: Fix out of range data usage

* videostab: Add simple UTs for video stabilizers

Reproduces issue #5178

* videostab: Fix out of range data usage

Fixes issue #5178

* videostab: Use cv::Range for ranges instead of std::pair
pull/2441/head
Igor Murzov 5 years ago committed by GitHub
parent bdfd1e75d4
commit a0d9138a5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      modules/videostab/include/opencv2/videostab/deblurring.hpp
  2. 12
      modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp
  3. 4
      modules/videostab/samples/videostab.cpp
  4. 6
      modules/videostab/src/deblurring.cpp
  5. 14
      modules/videostab/src/motion_stabilizing.cpp
  6. 16
      modules/videostab/src/stabilizer.cpp
  7. 82
      modules/videostab/test/test_stabilizer.cpp

@ -66,7 +66,7 @@ public:
virtual void setRadius(int val) { radius_ = val; }
virtual int radius() const { return radius_; }
virtual void deblur(int idx, Mat &frame) = 0;
virtual void deblur(int idx, Mat &frame, const Range &range) = 0;
// data from stabilizer
@ -90,7 +90,7 @@ protected:
class CV_EXPORTS NullDeblurer : public DeblurerBase
{
public:
virtual void deblur(int /*idx*/, Mat &/*frame*/) CV_OVERRIDE {}
virtual void deblur(int /*idx*/, Mat &/*frame*/, const Range &/*range*/) CV_OVERRIDE {}
};
class CV_EXPORTS WeightingDeblurer : public DeblurerBase
@ -101,7 +101,7 @@ public:
void setSensitivity(float val) { sensitivity_ = val; }
float sensitivity() const { return sensitivity_; }
virtual void deblur(int idx, Mat &frame) CV_OVERRIDE;
virtual void deblur(int idx, Mat &frame, const Range &range) CV_OVERRIDE;
private:
float sensitivity_;

@ -63,7 +63,7 @@ public:
//! assumes that [0, size-1) is in or equals to [range.first, range.second)
virtual void stabilize(
int size, const std::vector<Mat> &motions, std::pair<int,int> range,
int size, const std::vector<Mat> &motions, const Range &range,
Mat *stabilizationMotions) = 0;
};
@ -74,7 +74,7 @@ public:
bool empty() const { return stabilizers_.empty(); }
virtual void stabilize(
int size, const std::vector<Mat> &motions, std::pair<int,int> range,
int size, const std::vector<Mat> &motions, const Range &range,
Mat *stabilizationMotions) CV_OVERRIDE;
private:
@ -87,10 +87,10 @@ public:
virtual ~MotionFilterBase() {}
virtual Mat stabilize(
int idx, const std::vector<Mat> &motions, std::pair<int,int> range) = 0;
int idx, const std::vector<Mat> &motions, const Range &range) = 0;
virtual void stabilize(
int size, const std::vector<Mat> &motions, std::pair<int,int> range,
int size, const std::vector<Mat> &motions, const Range &range,
Mat *stabilizationMotions) CV_OVERRIDE;
};
@ -104,7 +104,7 @@ public:
float stdev() const { return stdev_; }
virtual Mat stabilize(
int idx, const std::vector<Mat> &motions, std::pair<int,int> range) CV_OVERRIDE;
int idx, const std::vector<Mat> &motions, const Range &range) CV_OVERRIDE;
private:
int radius_;
@ -141,7 +141,7 @@ public:
float weight4() const { return w4_; }
virtual void stabilize(
int size, const std::vector<Mat> &motions, std::pair<int,int> range,
int size, const std::vector<Mat> &motions, const Range &range,
Mat *stabilizationMotions) CV_OVERRIDE;
private:

@ -125,9 +125,9 @@ void printHelp()
" -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"
" Do consistent mosaicking. The default is no.\n"
" --mosaic-stdev=<float_number>\n"
" Consistent mosaicing stdev threshold. The default is 10.0.\n\n"
" Consistent mosaicking 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=<float_number>\n"

@ -70,7 +70,7 @@ WeightingDeblurer::WeightingDeblurer()
}
void WeightingDeblurer::deblur(int idx, Mat &frame)
void WeightingDeblurer::deblur(int idx, Mat &frame, const Range &range)
{
CV_INSTRUMENT_REGION();
@ -93,7 +93,9 @@ void WeightingDeblurer::deblur(int idx, Mat &frame)
}
}
for (int k = idx - radius_; k <= idx + radius_; ++k)
int iMin = std::max(idx - radius_, range.start);
int iMax = std::min(idx + radius_, range.end);
for (int k = iMin; k <= iMax; ++k)
{
const Mat &neighbor = at(k, *frames_);
float bRatio = at(idx, *blurrinessRates_) / at(k, *blurrinessRates_);

@ -52,7 +52,7 @@ namespace videostab
{
void MotionStabilizationPipeline::stabilize(
int size, const std::vector<Mat> &motions, std::pair<int,int> range, Mat *stabilizationMotions)
int size, const std::vector<Mat> &motions, const Range &range, Mat *stabilizationMotions)
{
std::vector<Mat> updatedMotions(motions.size());
for (size_t i = 0; i < motions.size(); ++i)
@ -81,7 +81,7 @@ void MotionStabilizationPipeline::stabilize(
void MotionFilterBase::stabilize(
int size, const std::vector<Mat> &motions, std::pair<int,int> range, Mat *stabilizationMotions)
int size, const std::vector<Mat> &motions, const Range &range, Mat *stabilizationMotions)
{
for (int i = 0; i < size; ++i)
stabilizationMotions[i] = stabilize(i, motions, range);
@ -102,13 +102,13 @@ void GaussianMotionFilter::setParams(int _radius, float _stdev)
}
Mat GaussianMotionFilter::stabilize(int idx, const std::vector<Mat> &motions, std::pair<int,int> range)
Mat GaussianMotionFilter::stabilize(int idx, const std::vector<Mat> &motions, const Range &range)
{
const Mat &cur = at(idx, motions);
Mat res = Mat::zeros(cur.size(), cur.type());
float sum = 0.f;
int iMin = std::max(idx - radius_, range.first);
int iMax = std::min(idx + radius_, range.second);
int iMin = std::max(idx - radius_, range.start);
int iMax = std::min(idx + radius_, range.end);
for (int i = iMin; i <= iMax; ++i)
{
res += weight_[radius_ + i - idx] * getMotion(idx, i, motions);
@ -132,7 +132,7 @@ LpMotionStabilizer::LpMotionStabilizer(MotionModel model)
#ifndef HAVE_CLP
void LpMotionStabilizer::stabilize(int, const std::vector<Mat>&, std::pair<int,int>, Mat*)
void LpMotionStabilizer::stabilize(int, const std::vector<Mat>&, const Range &, Mat*)
{
CV_Error(Error::StsError, "The library is built without Clp support");
}
@ -140,7 +140,7 @@ void LpMotionStabilizer::stabilize(int, const std::vector<Mat>&, std::pair<int,i
#else
void LpMotionStabilizer::stabilize(
int size, const std::vector<Mat> &motions, std::pair<int,int> /*range*/, Mat *stabilizationMotions)
int size, const std::vector<Mat> &motions, const Range &/*range*/, Mat *stabilizationMotions)
{
CV_Assert(model_ <= MM_AFFINE);

@ -63,11 +63,11 @@ StabilizerBase::StabilizerBase()
setTrimRatio(0);
setCorrectionForInclusion(false);
setBorderMode(BORDER_REPLICATE);
curPos_ = 0;
curPos_ = -1;
curStabilizedPos_ = -1;
doDeblurring_ = false;
doInpainting_ = false;
processingStartTime_ = 0;
curStabilizedPos_ = 0;
}
@ -143,12 +143,10 @@ bool StabilizerBase::doOneIteration()
log_->print(".");
return true;
}
if (curStabilizedPos_ < curPos_)
else if (curStabilizedPos_ < curPos_)
{
curStabilizedPos_++;
at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F);
at(curPos_, motions_) = Mat::eye(3, 3, CV_32F);
stabilizeFrame();
log_->print(".");
@ -201,7 +199,7 @@ void StabilizerBase::stabilizeFrame()
if (doDeblurring_)
{
at(curStabilizedPos_, frames_).copyTo(preProcessedFrame_);
deblurer_->deblur(curStabilizedPos_, preProcessedFrame_);
deblurer_->deblur(curStabilizedPos_, preProcessedFrame_, Range(0, curPos_));
}
else
preProcessedFrame_ = at(curStabilizedPos_, frames_);
@ -301,7 +299,7 @@ Mat OnePassStabilizer::estimateMotion()
Mat OnePassStabilizer::estimateStabilizationMotion()
{
return motionFilter_->stabilize(curStabilizedPos_, motions_, std::make_pair(0, curPos_));
return motionFilter_->stabilize(curStabilizedPos_, motions_, Range(0, curPos_));
}
@ -438,7 +436,7 @@ void TwoPassStabilizer::runPrePassIfNecessary()
stabilizationMotions_.resize(frameCount_);
motionStabilizer_->stabilize(
frameCount_, motions_, std::make_pair(0, frameCount_ - 1), &stabilizationMotions_[0]);
frameCount_, motions_, Range(0, frameCount_ - 1), &stabilizationMotions_[0]);
elapsedTime = clock() - startTime;
log_->print("motion stabilization time: %.3f sec\n",

@ -0,0 +1,82 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <opencv2/ts/cuda_test.hpp> // EXPECT_MAT_NEAR
namespace opencv_test { namespace {
using namespace ::cv::videostab;
class OneFrameTestSource : public IFrameSource
{
public:
OneFrameTestSource(const Mat &frame)
{
frameNumber_ = 0;
frame_ = frame;
}
virtual void reset() CV_OVERRIDE
{
frameNumber_ = 0;
}
virtual Mat nextFrame() CV_OVERRIDE
{
return (frameNumber_++ == 0) ? frame_ : Mat();
}
private:
int frameNumber_;
Mat frame_;
};
TEST(OnePassStabilizer, oneFrame)
{
Mat frame(2, 3, CV_8UC3);
randu(frame, Scalar::all(0), Scalar::all(255));
OnePassStabilizer stabilizer;
stabilizer.setRadius(10);
stabilizer.setFrameSource(makePtr<OneFrameTestSource>(frame));
Mat stabilizedFrame = stabilizer.nextFrame();
EXPECT_MAT_NEAR(frame, stabilizedFrame, 0);
EXPECT_TRUE(stabilizer.nextFrame().empty());
}
TEST(OnePassStabilizer, oneFrame_deblur)
{
Mat frame(2, 3, CV_8UC3);
randu(frame, Scalar::all(0), Scalar::all(255));
OnePassStabilizer stabilizer;
stabilizer.setRadius(1);
stabilizer.setFrameSource(makePtr<OneFrameTestSource>(frame));
Ptr<WeightingDeblurer> deblurer = makePtr<WeightingDeblurer>();
deblurer->setRadius(10);
stabilizer.setDeblurer(deblurer);
Mat stabilizedFrame = stabilizer.nextFrame();
EXPECT_MAT_NEAR(frame, stabilizedFrame, 0);
EXPECT_TRUE(stabilizer.nextFrame().empty());
}
TEST(TwoPassStabilizer, oneFrame)
{
Mat frame(2, 3, CV_8UC3);
randu(frame, Scalar::all(0), Scalar::all(255));
TwoPassStabilizer stabilizer;
stabilizer.setRadius(10);
stabilizer.setFrameSource(makePtr<OneFrameTestSource>(frame));
Mat stabilizedFrame = stabilizer.nextFrame();
EXPECT_MAT_NEAR(frame, stabilizedFrame, 0);
EXPECT_TRUE(stabilizer.nextFrame().empty());
}
}} // namespace
Loading…
Cancel
Save