提交 07e0f7bf 编写于 作者: V Vadim Pisarevsky

refactored video module; use the new-style algorithms now

上级 14a0abbf
......@@ -893,7 +893,7 @@ CV_INIT_ALGORITHM(LBPH, "FaceRecognizer.LBPH",
bool initModule_contrib()
{
Ptr<Algorithm> efaces = createEigenfaces(), ffaces = createFisherfaces(), lbph = createLBPH();
Ptr<Algorithm> efaces = createEigenfaces_hidden(), ffaces = createFisherfaces_hidden(), lbph = createLBPH_hidden();
return efaces->info() != 0 && ffaces->info() != 0 && lbph->info() != 0;
}
......
......@@ -254,14 +254,14 @@ namespace cv
} //namespace cv
#define CV_INIT_ALGORITHM(classname, algname, memberinit) \
static ::cv::Algorithm* create##classname() \
static ::cv::Algorithm* create##classname##_hidden() \
{ \
return new classname; \
} \
\
static ::cv::AlgorithmInfo& classname##_info() \
{ \
static ::cv::AlgorithmInfo classname##_info_var(algname, create##classname); \
static ::cv::AlgorithmInfo classname##_info_var(algname, create##classname##_hidden); \
return classname##_info_var; \
} \
\
......
......@@ -614,10 +614,10 @@ PERF_TEST_P(Video_Cn_LearningRate, Video_MOG,
}
else
{
cv::BackgroundSubtractorMOG mog;
cv::Ptr<cv::BackgroundSubtractor> mog = cv::createBackgroundSubtractorMOG();
cv::Mat foreground;
mog(frame, foreground, learningRate);
mog->apply(frame, foreground, learningRate);
for (int i = 0; i < 10; ++i)
{
......@@ -635,7 +635,7 @@ PERF_TEST_P(Video_Cn_LearningRate, Video_MOG,
}
startTimer(); next();
mog(frame, foreground, learningRate);
mog->apply(frame, foreground, learningRate);
stopTimer();
}
......@@ -709,12 +709,12 @@ PERF_TEST_P(Video_Cn, Video_MOG2,
}
else
{
cv::BackgroundSubtractorMOG2 mog2;
mog2.set("detectShadows", false);
cv::Ptr<cv::BackgroundSubtractor> mog2 = cv::createBackgroundSubtractorMOG2();
mog2->set("detectShadows", false);
cv::Mat foreground;
mog2(frame, foreground);
mog2->apply(frame, foreground);
for (int i = 0; i < 10; ++i)
{
......@@ -732,7 +732,7 @@ PERF_TEST_P(Video_Cn, Video_MOG2,
}
startTimer(); next();
mog2(frame, foreground);
mog2->apply(frame, foreground);
stopTimer();
}
......@@ -789,7 +789,7 @@ PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage,
}
else
{
cv::BackgroundSubtractorMOG2 mog2;
cv::Ptr<cv::BackgroundSubtractor> mog2 = cv::createBackgroundSubtractorMOG2();
cv::Mat foreground;
for (int i = 0; i < 10; ++i)
......@@ -807,12 +807,12 @@ PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage,
cv::swap(temp, frame);
}
mog2(frame, foreground);
mog2->apply(frame, foreground);
}
cv::Mat background;
TEST_CYCLE() mog2.getBackgroundImage(background);
TEST_CYCLE() mog2->getBackgroundImage(background);
CPU_SANITY_CHECK(background);
}
......@@ -958,11 +958,11 @@ PERF_TEST_P(Video_Cn_MaxFeatures, Video_GMG,
cv::Mat foreground;
cv::Mat zeros(frame.size(), CV_8UC1, cv::Scalar::all(0));
cv::BackgroundSubtractorGMG gmg;
gmg.set("maxFeatures", maxFeatures);
gmg.initialize(frame.size(), 0.0, 255.0);
cv::Ptr<cv::BackgroundSubtractor> gmg = cv::createBackgroundSubtractorGMG();
gmg->set("maxFeatures", maxFeatures);
//gmg.initialize(frame.size(), 0.0, 255.0);
gmg(frame, foreground);
gmg->apply(frame, foreground);
for (int i = 0; i < 150; ++i)
{
......@@ -985,7 +985,7 @@ PERF_TEST_P(Video_Cn_MaxFeatures, Video_GMG,
}
startTimer(); next();
gmg(frame, foreground);
gmg->apply(frame, foreground);
stopTimer();
}
......
......@@ -245,8 +245,8 @@ GPU_TEST_P(MOG2, Update)
mog2.bShadowDetection = detectShadow;
cv::gpu::GpuMat foreground = createMat(frame.size(), CV_8UC1, useRoi);
cv::BackgroundSubtractorMOG2 mog2_gold;
mog2_gold.set("detectShadows", detectShadow);
cv::Ptr<cv::BackgroundSubtractorMOG2> mog2_gold = cv::createBackgroundSubtractorMOG2();
mog2_gold.setDetectShadows(detectShadow);
cv::Mat foreground_gold;
for (int i = 0; i < 10; ++i)
......@@ -263,7 +263,7 @@ GPU_TEST_P(MOG2, Update)
mog2(loadMat(frame, useRoi), foreground);
mog2_gold(frame, foreground_gold);
mog2_gold->apply(frame, foreground_gold);
if (detectShadow)
{
......@@ -290,8 +290,8 @@ GPU_TEST_P(MOG2, getBackgroundImage)
mog2.bShadowDetection = detectShadow;
cv::gpu::GpuMat foreground;
cv::BackgroundSubtractorMOG2 mog2_gold;
mog2_gold.set("detectShadows", detectShadow);
cv::Ptr<cv::BackgroundSubtractorMOG2> mog2_gold = cv::createBackgroundSubtractorMOG2();
mog2_gold.setDetectShadows(detectShadow);
cv::Mat foreground_gold;
for (int i = 0; i < 10; ++i)
......@@ -301,14 +301,14 @@ GPU_TEST_P(MOG2, getBackgroundImage)
mog2(loadMat(frame, useRoi), foreground);
mog2_gold(frame, foreground_gold);
mog2_gold->apply(frame, foreground_gold);
}
cv::gpu::GpuMat background = createMat(frame.size(), frame.type(), useRoi);
mog2.getBackgroundImage(background);
cv::Mat background_gold;
mog2_gold.getBackgroundImage(background_gold);
mog2_gold->getBackgroundImage(background_gold);
ASSERT_MAT_NEAR(background_gold, background, 0);
}
......
......@@ -50,7 +50,7 @@ icvReleaseGaussianBGModel( CvGaussBGModel** bg_model )
if( *bg_model )
{
delete (cv::BackgroundSubtractorMOG*)((*bg_model)->mog);
delete (cv::Ptr<cv::BackgroundSubtractor>*)((*bg_model)->mog);
cvReleaseImage( &(*bg_model)->background );
cvReleaseImage( &(*bg_model)->foreground );
memset( *bg_model, 0, sizeof(**bg_model) );
......@@ -65,10 +65,10 @@ icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model, doubl
{
cv::Mat image = cv::cvarrToMat(curr_frame), mask = cv::cvarrToMat(bg_model->foreground);
cv::BackgroundSubtractorMOG* mog = (cv::BackgroundSubtractorMOG*)(bg_model->mog);
cv::Ptr<cv::BackgroundSubtractor>* mog = (cv::Ptr<cv::BackgroundSubtractor>*)(bg_model->mog);
CV_Assert(mog != 0);
(*mog)(image, mask, learningRate);
(*mog)->apply(image, mask, learningRate);
bg_model->countFrames++;
return 0;
......@@ -105,13 +105,11 @@ cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parame
bg_model->params = params;
cv::BackgroundSubtractorMOG* mog =
new cv::BackgroundSubtractorMOG(params.win_size,
params.n_gauss,
params.bg_threshold,
params.variance_init);
bg_model->mog = mog;
cv::Ptr<cv::BackgroundSubtractor> mog = cv::createBackgroundSubtractorMOG(params.win_size, params.n_gauss,
params.bg_threshold);
cv::Ptr<cv::BackgroundSubtractor>* pmog = new cv::Ptr<cv::BackgroundSubtractor>;
*pmog = mog;
bg_model->mog = pmog;
CvSize sz = cvGetSize(first_frame);
bg_model->background = cvCreateImage(sz, IPL_DEPTH_8U, first_frame->nChannels);
......
......@@ -56,7 +56,7 @@ CV_INIT_ALGORITHM(EM, "StatModel.EM",
bool initModule_ml(void)
{
Ptr<Algorithm> em = createEM();
Ptr<Algorithm> em = createEM_hidden();
return em->info() != 0;
}
......
......@@ -67,7 +67,7 @@ CV_INIT_ALGORITHM(SIFT, "Feature2D.SIFT",
bool initModule_nonfree(void)
{
Ptr<Algorithm> sift = createSIFT(), surf = createSURF();
Ptr<Algorithm> sift = createSIFT_hidden(), surf = createSURF_hidden();
return sift->info() != 0 && surf->info() != 0;
}
......
......@@ -125,6 +125,7 @@ typedef Ptr<FeatureDetector> Ptr_FeatureDetector;
typedef Ptr<DescriptorExtractor> Ptr_DescriptorExtractor;
typedef Ptr<Feature2D> Ptr_Feature2D;
typedef Ptr<DescriptorMatcher> Ptr_DescriptorMatcher;
typedef Ptr<BackgroundSubtractor> Ptr_BackgroundSubtractor;
typedef Ptr<cv::softcascade::ChannelFeatureBuilder> Ptr_ChannelFeatureBuilder;
......
......@@ -58,8 +58,8 @@ CV_INIT_ALGORITHM(SCascade, "CascadeDetector.SCascade",
bool initModule_softcascade(void)
{
Ptr<Algorithm> sc = createSCascade();
Ptr<Algorithm> sc1 = createDetector();
Ptr<Algorithm> sc = createSCascade_hidden();
Ptr<Algorithm> sc1 = createDetector_hidden();
return (sc1->info() != 0) && (sc->info() != 0);
}
......
......@@ -12,6 +12,7 @@
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
......@@ -54,17 +55,14 @@ namespace cv
The class is only used to define the common interface for
the whole family of background/foreground segmentation algorithms.
*/
class CV_EXPORTS_W BackgroundSubtractor : public Algorithm
class BackgroundSubtractor : public Algorithm
{
public:
//! the virtual destructor
virtual ~BackgroundSubtractor();
//! the update operator that takes the next video frame and returns the current foreground mask as 8-bit binary image.
CV_WRAP_AS(apply) virtual void operator()(InputArray image, OutputArray fgmask,
double learningRate=0);
virtual void apply(InputArray image, OutputArray fgmask, double learningRate=0) = 0;
//! computes a background image
virtual void getBackgroundImage(OutputArray backgroundImage) const;
virtual void getBackgroundImage(OutputArray backgroundImage) const = 0;
};
......@@ -78,35 +76,26 @@ public:
http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
*/
class CV_EXPORTS_W BackgroundSubtractorMOG : public BackgroundSubtractor
class BackgroundSubtractorMOG : public BackgroundSubtractor
{
public:
//! the default constructor
CV_WRAP BackgroundSubtractorMOG();
//! the full constructor that takes the length of the history, the number of gaussian mixtures, the background ratio parameter and the noise strength
CV_WRAP BackgroundSubtractorMOG(int history, int nmixtures, double backgroundRatio, double noiseSigma=0);
//! the destructor
virtual ~BackgroundSubtractorMOG();
//! the update operator
virtual void operator()(InputArray image, OutputArray fgmask, double learningRate=0);
//! re-initiaization method
virtual void initialize(Size frameSize, int frameType);
virtual AlgorithmInfo* info() const;
protected:
Size frameSize;
int frameType;
Mat bgmodel;
int nframes;
int history;
int nmixtures;
double varThreshold;
double backgroundRatio;
double noiseSigma;
virtual int getHistory() const = 0;
virtual void setHistory(int nframes) = 0;
virtual int getNMixtures() const = 0;
virtual void setNMixtures(int nmix) = 0;
virtual double getBackgroundRatio() const = 0;
virtual void setBackgroundRatio(double backgroundRatio) = 0;
virtual double getNoiseSigma() const = 0;
virtual void setNoiseSigma(double noiseSigma) = 0;
};
CV_EXPORTS Ptr<BackgroundSubtractorMOG>
createBackgroundSubtractorMOG(int history=200, int nmixtures=5,
double backgroundRatio=0.7, double noiseSigma=0);
/*!
The class implements the following algorithm:
......@@ -114,82 +103,51 @@ protected:
Z.Zivkovic
International Conference Pattern Recognition, UK, August, 2004.
http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
*/
class CV_EXPORTS BackgroundSubtractorMOG2 : public BackgroundSubtractor
*/
class BackgroundSubtractorMOG2 : public BackgroundSubtractor
{
public:
//! the default constructor
BackgroundSubtractorMOG2();
//! the full constructor that takes the length of the history, the number of gaussian mixtures, the background ratio parameter and the noise strength
BackgroundSubtractorMOG2(int history, float varThreshold, bool bShadowDetection=true);
//! the destructor
virtual ~BackgroundSubtractorMOG2();
//! the update operator
virtual void operator()(InputArray image, OutputArray fgmask, double learningRate=-1);
//! computes a background image which are the mean of all background gaussians
virtual void getBackgroundImage(OutputArray backgroundImage) const;
//! re-initiaization method
virtual void initialize(Size frameSize, int frameType);
virtual AlgorithmInfo* info() const;
protected:
Size frameSize;
int frameType;
Mat bgmodel;
Mat bgmodelUsedModes;//keep track of number of modes per pixel
int nframes;
int history;
int nmixtures;
//! here it is the maximum allowed number of mixture components.
//! Actual number is determined dynamically per pixel
double varThreshold;
// threshold on the squared Mahalanobis distance to decide if it is well described
// by the background model or not. Related to Cthr from the paper.
// This does not influence the update of the background. A typical value could be 4 sigma
// and that is varThreshold=4*4=16; Corresponds to Tb in the paper.
/////////////////////////
// less important parameters - things you might change but be carefull
////////////////////////
float backgroundRatio;
// corresponds to fTB=1-cf from the paper
// TB - threshold when the component becomes significant enough to be included into
// the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
// For alpha=0.001 it means that the mode should exist for approximately 105 frames before
// it is considered foreground
// float noiseSigma;
float varThresholdGen;
//correspondts to Tg - threshold on the squared Mahalan. dist. to decide
//when a sample is close to the existing components. If it is not close
//to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
//Smaller Tg leads to more generated components and higher Tg might make
//lead to small number of components but they can grow too large
float fVarInit;
float fVarMin;
float fVarMax;
//initial variance for the newly generated components.
//It will will influence the speed of adaptation. A good guess should be made.
//A simple way is to estimate the typical standard deviation from the images.
//I used here 10 as a reasonable value
// min and max can be used to further control the variance
float fCT;//CT - complexity reduction prior
//this is related to the number of samples needed to accept that a component
//actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
//the standard Stauffer&Grimson algorithm (maybe not exact but very similar)
//shadow detection parameters
bool bShadowDetection;//default 1 - do shadow detection
unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result - 127 default value
float fTau;
// Tau - shadow threshold. The shadow is detected if the pixel is darker
//version of the background. Tau is a threshold on how much darker the shadow can be.
//Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
//See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
virtual int getHistory() const = 0;
virtual void setHistory(int nframes) = 0;
virtual int getNMixtures() const = 0;
virtual void setNMixtures(int nmix) = 0;
virtual double getBackgroundRatio() const = 0;
virtual void setBackgroundRatio(double backgroundRatio) = 0;
virtual double getVarThreshold() const = 0;
virtual void setVarThreshold(double varThreshold) = 0;
virtual double getVarThresholdGen() const = 0;
virtual void setVarThresholdGen(double varThresholdGen) = 0;
virtual double getVarInit() const = 0;
virtual void setVarInit(double varInit) = 0;
virtual double getVarMin() const = 0;
virtual void setVarMin(double varMin) = 0;
virtual double getVarMax() const = 0;
virtual void setVarMax(double varMax) = 0;
virtual double getComplexityReductionThreshold() const = 0;
virtual void setComplexityReductionThreshold(double ct) = 0;
virtual bool getDetectShadows() const = 0;
virtual void setDetectShadows(bool detectshadows) = 0;
virtual int getShadowValue() const = 0;
virtual void setShadowValue(int value) = 0;
virtual double getShadowThreshold() const = 0;
virtual void setShadowThreshold(double value) = 0;
};
CV_EXPORTS Ptr<BackgroundSubtractorMOG2>
createBackgroundSubtractorMOG2(int history=500, double varThreshold=16,
bool detectShadows=true);
/**
* Background Subtractor module. Takes a series of images and returns a sequence of mask (8UC1)
* images of the same size, where 255 indicates Foreground and 0 represents Background.
......@@ -197,66 +155,44 @@ protected:
* Variable-Lighting Conditions for a Responsive Audio Art Installation," A. Godbehere,
* A. Matsukawa, K. Goldberg, American Control Conference, Montreal, June 2012.
*/
class CV_EXPORTS BackgroundSubtractorGMG: public cv::BackgroundSubtractor
class BackgroundSubtractorGMG : public BackgroundSubtractor
{
public:
BackgroundSubtractorGMG();
virtual ~BackgroundSubtractorGMG();
virtual AlgorithmInfo* info() const;
/**
* Validate parameters and set up data structures for appropriate image size.
* Must call before running on data.
* @param frameSize input frame size
* @param min minimum value taken on by pixels in image sequence. Usually 0
* @param max maximum value taken on by pixels in image sequence. e.g. 1.0 or 255
*/
void initialize(cv::Size frameSize, double min, double max);
/**
* Performs single-frame background subtraction and builds up a statistical background image
* model.
* @param image Input image
* @param fgmask Output mask image representing foreground and background pixels
*/
virtual void operator()(InputArray image, OutputArray fgmask, double learningRate=-1.0);
/**
* Releases all inner buffers.
*/
void release();
//! Total number of distinct colors to maintain in histogram.
int maxFeatures;
//! Set between 0.0 and 1.0, determines how quickly features are "forgotten" from histograms.
double learningRate;
//! Number of frames of video to use to initialize histograms.
int numInitializationFrames;
//! Number of discrete levels in each channel to be used in histograms.
int quantizationLevels;
//! Prior probability that any given pixel is a background pixel. A sensitivity parameter.
double backgroundPrior;
//! Value above which pixel is determined to be FG.
double decisionThreshold;
//! Smoothing radius, in pixels, for cleaning up FG image.
int smoothingRadius;
//! Perform background model update
bool updateBackgroundModel;
private:
double maxVal_;
double minVal_;
cv::Size frameSize_;
int frameNum_;
cv::Mat_<int> nfeatures_;
cv::Mat_<unsigned int> colors_;
cv::Mat_<float> weights_;
cv::Mat buf_;
virtual int getMaxFeatures() const = 0;
virtual void setMaxFeatures(int maxFeatures) = 0;
virtual double getDefaultLearningRate() const = 0;
virtual void setDefaultLearningRate(double lr) = 0;
virtual int getNumFrames() const = 0;
virtual void setNumFrames(int nframes) = 0;
virtual int getQuantizationLevels() const = 0;
virtual void setQuantizationLevels(int nlevels) = 0;
virtual double getBackgroundPrior() const = 0;
virtual void setBackgroundPrior(double bgprior) = 0;
virtual int getSmoothingRadius() const = 0;
virtual void setSmoothingRadius(int radius) = 0;
virtual double getDecisionThreshold() const = 0;
virtual void setDecisionThreshold(double thresh) = 0;
virtual bool getUpdateBackgroundModel() const = 0;
virtual void setUpdateBackgroundModel(bool update) = 0;
virtual double getMinVal() const = 0;
virtual void setMinVal(double val) = 0;
virtual double getMaxVal() const = 0;
virtual void setMaxVal(double val) = 0;
};
CV_EXPORTS Ptr<BackgroundSubtractorGMG> createBackgroundSubtractorGMG(int initializationFrames=120,
double decisionThreshold=0.8);
}
#endif
......@@ -219,23 +219,6 @@ CVAPI(const CvMat*) cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement
#define cvKalmanUpdateByMeasurement cvKalmanCorrect
/****************************************************************************************\
* Image Alignment (ECC algorithm) *
\****************************************************************************************/
enum
{
MOTION_TRANSLATION,
MOTION_EUCLIDEAN,
MOTION_AFFINE,
MOTION_HOMOGRAPHY
};
/* Estimate the geometric transformation between 2 images (area-based alignment) */
CVAPI(double) cvFindTransformECC (const CvArr* templateImage, const CvArr* inputImage,
CvMat* warpMatrix,
const int motionType,
const CvTermCriteria criteria);
#ifdef __cplusplus
}
......@@ -341,6 +324,14 @@ CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next,
CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst,
bool fullAffine);
enum
{
MOTION_TRANSLATION=0,
MOTION_EUCLIDEAN=1,
MOTION_AFFINE=2,
MOTION_HOMOGRAPHY=3
};
//! estimates the best-fit Translation, Euclidean, Affine or Perspective Transformation
// with respect to Enhanced Correlation Coefficient criterion that maps one image to
// another (area-based alignment)
......
......@@ -7,9 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
......@@ -22,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
......@@ -58,15 +60,6 @@
namespace cv
{
BackgroundSubtractor::~BackgroundSubtractor() {}
void BackgroundSubtractor::operator()(InputArray, OutputArray, double)
{
}
void BackgroundSubtractor::getBackgroundImage(OutputArray) const
{
}
static const int defaultNMixtures = 5;
static const int defaultHistory = 200;
static const double defaultBackgroundRatio = 0.7;
......@@ -74,55 +67,88 @@ static const double defaultVarThreshold = 2.5*2.5;
static const double defaultNoiseSigma = 30*0.5;
static const double defaultInitialWeight = 0.05;
BackgroundSubtractorMOG::BackgroundSubtractorMOG()
class BackgroundSubtractorMOGImpl : public BackgroundSubtractorMOG
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
nmixtures = defaultNMixtures;
history = defaultHistory;
varThreshold = defaultVarThreshold;
backgroundRatio = defaultBackgroundRatio;
noiseSigma = defaultNoiseSigma;
}
public:
//! the default constructor
BackgroundSubtractorMOGImpl()
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
nmixtures = defaultNMixtures;
history = defaultHistory;
varThreshold = defaultVarThreshold;
backgroundRatio = defaultBackgroundRatio;
noiseSigma = defaultNoiseSigma;
}
// the full constructor that takes the length of the history,
// the number of gaussian mixtures, the background ratio parameter and the noise strength
BackgroundSubtractorMOGImpl(int _history, int _nmixtures, double _backgroundRatio, double _noiseSigma=0)
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
nmixtures = std::min(_nmixtures > 0 ? _nmixtures : defaultNMixtures, 8);
history = _history > 0 ? _history : defaultHistory;
varThreshold = defaultVarThreshold;
backgroundRatio = std::min(_backgroundRatio > 0 ? _backgroundRatio : 0.95, 1.);
noiseSigma = _noiseSigma <= 0 ? defaultNoiseSigma : _noiseSigma;
}
BackgroundSubtractorMOG::BackgroundSubtractorMOG(int _history, int _nmixtures,
double _backgroundRatio,
double _noiseSigma)
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
nmixtures = std::min(_nmixtures > 0 ? _nmixtures : defaultNMixtures, 8);
history = _history > 0 ? _history : defaultHistory;
varThreshold = defaultVarThreshold;
backgroundRatio = std::min(_backgroundRatio > 0 ? _backgroundRatio : 0.95, 1.);
noiseSigma = _noiseSigma <= 0 ? defaultNoiseSigma : _noiseSigma;
}
//! the update operator
virtual void apply(InputArray image, OutputArray fgmask, double learningRate=0);
BackgroundSubtractorMOG::~BackgroundSubtractorMOG()
{
}
//! re-initiaization method
virtual void initialize(Size _frameSize, int _frameType)
{
frameSize = _frameSize;
frameType = _frameType;
nframes = 0;
int nchannels = CV_MAT_CN(frameType);
CV_Assert( CV_MAT_DEPTH(frameType) == CV_8U );
// for each gaussian mixture of each pixel bg model we store ...
// the mixture sort key (w/sum_of_variances), the mixture weight (w),
// the mean (nchannels values) and
// the diagonal covariance matrix (another nchannels values)
bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + 2*nchannels), CV_32F );
bgmodel = Scalar::all(0);
}
virtual AlgorithmInfo* info() const { return 0; }
void BackgroundSubtractorMOG::initialize(Size _frameSize, int _frameType)
{
frameSize = _frameSize;
frameType = _frameType;
nframes = 0;
int nchannels = CV_MAT_CN(frameType);
CV_Assert( CV_MAT_DEPTH(frameType) == CV_8U );
// for each gaussian mixture of each pixel bg model we store ...
// the mixture sort key (w/sum_of_variances), the mixture weight (w),
// the mean (nchannels values) and
// the diagonal covariance matrix (another nchannels values)
bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + 2*nchannels), CV_32F );
bgmodel = Scalar::all(0);
}
virtual void getBackgroundImage(OutputArray) const
{
CV_Error( CV_StsNotImplemented, "" );
}
virtual int getHistory() const { return history; }
virtual void setHistory(int _nframes) { history = _nframes; }
virtual int getNMixtures() const { return nmixtures; }
virtual void setNMixtures(int nmix) { nmixtures = nmix; }
virtual double getBackgroundRatio() const { return backgroundRatio; }
virtual void setBackgroundRatio(double _backgroundRatio) { backgroundRatio = _backgroundRatio; }
virtual double getNoiseSigma() const { return noiseSigma; }
virtual void setNoiseSigma(double _noiseSigma) { noiseSigma = _noiseSigma; }
protected:
Size frameSize;
int frameType;
Mat bgmodel;
int nframes;
int history;
int nmixtures;
double varThreshold;
double backgroundRatio;
double noiseSigma;
};
template<typename VT> struct MixData
......@@ -391,7 +417,7 @@ static void process8uC3( const Mat& image, Mat& fgmask, double learningRate,
}
}
void BackgroundSubtractorMOG::operator()(InputArray _image, OutputArray _fgmask, double learningRate)
void BackgroundSubtractorMOGImpl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
{
Mat image = _image.getMat();
bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;
......@@ -415,6 +441,12 @@ void BackgroundSubtractorMOG::operator()(InputArray _image, OutputArray _fgmask,
CV_Error( CV_StsUnsupportedFormat, "Only 1- and 3-channel 8-bit images are supported in BackgroundSubtractorMOG" );
}
Ptr<BackgroundSubtractorMOG> createBackgroundSubtractorMOG(int history, int nmixtures,
double backgroundRatio, double noiseSigma)
{
return new BackgroundSubtractorMOGImpl(history, nmixtures, backgroundRatio, noiseSigma);
}
}
/* End of file. */
......
......@@ -7,9 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
......@@ -22,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
......@@ -114,6 +116,176 @@ static const float defaultfCT2 = 0.05f; // complexity reduction prior constant 0
static const unsigned char defaultnShadowDetection2 = (unsigned char)127; // value to use in the segmentation mask for shadows, set 0 not to do shadow detection
static const float defaultfTau = 0.5f; // Tau - shadow threshold, see the paper for explanation
class CV_EXPORTS BackgroundSubtractorMOG2Impl : public BackgroundSubtractorMOG2
{
public:
//! the default constructor
BackgroundSubtractorMOG2Impl()
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = defaultHistory2;
varThreshold = defaultVarThreshold2;
bShadowDetection = 1;
nmixtures = defaultNMixtures2;
backgroundRatio = defaultBackgroundRatio2;
fVarInit = defaultVarInit2;
fVarMax = defaultVarMax2;
fVarMin = defaultVarMin2;
varThresholdGen = defaultVarThresholdGen2;
fCT = defaultfCT2;
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;
}
//! the full constructor that takes the length of the history,
// the number of gaussian mixtures, the background ratio parameter and the noise strength
BackgroundSubtractorMOG2Impl(int _history, float _varThreshold, bool _bShadowDetection=true)
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = _history > 0 ? _history : defaultHistory2;
varThreshold = (_varThreshold>0)? _varThreshold : defaultVarThreshold2;
bShadowDetection = _bShadowDetection;
nmixtures = defaultNMixtures2;
backgroundRatio = defaultBackgroundRatio2;
fVarInit = defaultVarInit2;
fVarMax = defaultVarMax2;
fVarMin = defaultVarMin2;
varThresholdGen = defaultVarThresholdGen2;
fCT = defaultfCT2;
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;
}
//! the destructor
~BackgroundSubtractorMOG2Impl() {}
//! the update operator
void apply(InputArray image, OutputArray fgmask, double learningRate=-1);
//! computes a background image which are the mean of all background gaussians
virtual void getBackgroundImage(OutputArray backgroundImage) const;
//! re-initiaization method
void initialize(Size _frameSize, int _frameType)
{
frameSize = _frameSize;
frameType = _frameType;
nframes = 0;
int nchannels = CV_MAT_CN(frameType);
CV_Assert( nchannels <= CV_CN_MAX );
// for each gaussian mixture of each pixel bg model we store ...
// the mixture weight (w),
// the mean (nchannels values) and
// the covariance
bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + nchannels), CV_32F );
//make the array for keeping track of the used modes per pixel - all zeros at start
bgmodelUsedModes.create(frameSize,CV_8U);
bgmodelUsedModes = Scalar::all(0);
}
virtual AlgorithmInfo* info() const { return 0; }
virtual int getHistory() const { return history; }
virtual void setHistory(int _nframes) { history = _nframes; }
virtual int getNMixtures() const { return nmixtures; }
virtual void setNMixtures(int nmix) { nmixtures = nmix; }
virtual double getBackgroundRatio() const { return backgroundRatio; }
virtual void setBackgroundRatio(double _backgroundRatio) { backgroundRatio = (float)_backgroundRatio; }
virtual double getVarThreshold() const { return varThreshold; }
virtual void setVarThreshold(double _varThreshold) { varThreshold = _varThreshold; }
virtual double getVarThresholdGen() const { return varThresholdGen; }
virtual void setVarThresholdGen(double _varThresholdGen) { varThresholdGen = (float)_varThresholdGen; }
virtual double getVarInit() const { return fVarInit; }
virtual void setVarInit(double varInit) { fVarInit = (float)varInit; }
virtual double getVarMin() const { return fVarMin; }
virtual void setVarMin(double varMin) { fVarMin = (float)varMin; }
virtual double getVarMax() const { return fVarMax; }
virtual void setVarMax(double varMax) { fVarMax = (float)varMax; }
virtual double getComplexityReductionThreshold() const { return fCT; }
virtual void setComplexityReductionThreshold(double ct) { fCT = (float)ct; }
virtual bool getDetectShadows() const { return bShadowDetection; }
virtual void setDetectShadows(bool detectshadows) { bShadowDetection = detectshadows; }
virtual int getShadowValue() const { return nShadowDetection; }
virtual void setShadowValue(int value) { nShadowDetection = (uchar)value; }
virtual double getShadowThreshold() const { return fTau; }
virtual void setShadowThreshold(double value) { fTau = (float)value; }
protected:
Size frameSize;
int frameType;
Mat bgmodel;
Mat bgmodelUsedModes;//keep track of number of modes per pixel
int nframes;
int history;
int nmixtures;
//! here it is the maximum allowed number of mixture components.
//! Actual number is determined dynamically per pixel
double varThreshold;
// threshold on the squared Mahalanobis distance to decide if it is well described
// by the background model or not. Related to Cthr from the paper.
// This does not influence the update of the background. A typical value could be 4 sigma
// and that is varThreshold=4*4=16; Corresponds to Tb in the paper.
/////////////////////////
// less important parameters - things you might change but be carefull
////////////////////////
float backgroundRatio;
// corresponds to fTB=1-cf from the paper
// TB - threshold when the component becomes significant enough to be included into
// the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
// For alpha=0.001 it means that the mode should exist for approximately 105 frames before
// it is considered foreground
// float noiseSigma;
float varThresholdGen;
//correspondts to Tg - threshold on the squared Mahalan. dist. to decide
//when a sample is close to the existing components. If it is not close
//to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
//Smaller Tg leads to more generated components and higher Tg might make
//lead to small number of components but they can grow too large
float fVarInit;
float fVarMin;
float fVarMax;
//initial variance for the newly generated components.
//It will will influence the speed of adaptation. A good guess should be made.
//A simple way is to estimate the typical standard deviation from the images.
//I used here 10 as a reasonable value
// min and max can be used to further control the variance
float fCT;//CT - complexity reduction prior
//this is related to the number of samples needed to accept that a component
//actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
//the standard Stauffer&Grimson algorithm (maybe not exact but very similar)
//shadow detection parameters
bool bShadowDetection;//default 1 - do shadow detection
unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result - 127 default value
float fTau;
// Tau - shadow threshold. The shadow is detected if the pixel is darker
//version of the background. Tau is a threshold on how much darker the shadow can be.
//Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
//See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
};
struct GaussBGStatModel2Params
{
//image info
......@@ -248,8 +420,9 @@ detectShadowGMM(const float* data, int nchannels, int nmodes,
//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
struct MOG2Invoker
class MOG2Invoker : public ParallelLoopBody
{
public:
MOG2Invoker(const Mat& _src, Mat& _dst,
GMM* _gmm, float* _mean,
uchar* _modesUsed,
......@@ -280,9 +453,9 @@ struct MOG2Invoker
cvtfunc = src->depth() != CV_32F ? getConvertFunc(src->depth(), CV_32F) : 0;
}
void operator()(const BlockedRange& range) const
void operator()(const Range& range) const
{
int y0 = range.begin(), y1 = range.end();
int y0 = range.start, y1 = range.end;
int ncols = src->cols, nchannels = src->channels();
AutoBuffer<float> buf(src->cols*nchannels);
float alpha1 = 1.f - alphaT;
......@@ -479,75 +652,7 @@ struct MOG2Invoker
BinaryFunc cvtfunc;
};
BackgroundSubtractorMOG2::BackgroundSubtractorMOG2()
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = defaultHistory2;
varThreshold = defaultVarThreshold2;
bShadowDetection = 1;
nmixtures = defaultNMixtures2;
backgroundRatio = defaultBackgroundRatio2;
fVarInit = defaultVarInit2;
fVarMax = defaultVarMax2;
fVarMin = defaultVarMin2;
varThresholdGen = defaultVarThresholdGen2;
fCT = defaultfCT2;
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;
}
BackgroundSubtractorMOG2::BackgroundSubtractorMOG2(int _history, float _varThreshold, bool _bShadowDetection)
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = _history > 0 ? _history : defaultHistory2;
varThreshold = (_varThreshold>0)? _varThreshold : defaultVarThreshold2;
bShadowDetection = _bShadowDetection;
nmixtures = defaultNMixtures2;
backgroundRatio = defaultBackgroundRatio2;
fVarInit = defaultVarInit2;
fVarMax = defaultVarMax2;
fVarMin = defaultVarMin2;
varThresholdGen = defaultVarThresholdGen2;
fCT = defaultfCT2;
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;
}
BackgroundSubtractorMOG2::~BackgroundSubtractorMOG2()
{
}
void BackgroundSubtractorMOG2::initialize(Size _frameSize, int _frameType)
{
frameSize = _frameSize;
frameType = _frameType;
nframes = 0;
int nchannels = CV_MAT_CN(frameType);
CV_Assert( nchannels <= CV_CN_MAX );
// for each gaussian mixture of each pixel bg model we store ...
// the mixture weight (w),
// the mean (nchannels values) and
// the covariance
bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + nchannels), CV_32F );
//make the array for keeping track of the used modes per pixel - all zeros at start
bgmodelUsedModes.create(frameSize,CV_8U);
bgmodelUsedModes = Scalar::all(0);
}
void BackgroundSubtractorMOG2::operator()(InputArray _image, OutputArray _fgmask, double learningRate)
void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
{
Mat image = _image.getMat();
bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;
......@@ -562,18 +667,19 @@ void BackgroundSubtractorMOG2::operator()(InputArray _image, OutputArray _fgmask
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history );
CV_Assert(learningRate >= 0);
parallel_for(BlockedRange(0, image.rows),
MOG2Invoker(image, fgmask,
parallel_for_(Range(0, image.rows),
MOG2Invoker(image, fgmask,
(GMM*)bgmodel.data,
(float*)(bgmodel.data + sizeof(GMM)*nmixtures*image.rows*image.cols),
bgmodelUsedModes.data, nmixtures, (float)learningRate,
(float)varThreshold,
backgroundRatio, varThresholdGen,
fVarInit, fVarMin, fVarMax, float(-learningRate*fCT), fTau,
bShadowDetection, nShadowDetection));
bShadowDetection, nShadowDetection),
image.total()/(double)(1 << 16));
}
void BackgroundSubtractorMOG2::getBackgroundImage(OutputArray backgroundImage) const
void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
{
int nchannels = CV_MAT_CN(frameType);
CV_Assert( nchannels == 3 );
......@@ -626,6 +732,13 @@ void BackgroundSubtractorMOG2::getBackgroundImage(OutputArray backgroundImage) c
}
}
Ptr<BackgroundSubtractorMOG2> createBackgroundSubtractorMOG2(int _history, double _varThreshold,
bool _bShadowDetection)
{
return new BackgroundSubtractorMOG2Impl(_history, (float)_varThreshold, _bShadowDetection);
}
}
/* End of file. */
......@@ -8,8 +8,10 @@
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
......@@ -22,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
......@@ -48,7 +50,105 @@
#include "precomp.hpp"
cv::BackgroundSubtractorGMG::BackgroundSubtractorGMG()
namespace cv
{
class CV_EXPORTS BackgroundSubtractorGMGImpl : public BackgroundSubtractorGMG
{
public:
BackgroundSubtractorGMGImpl();
~BackgroundSubtractorGMGImpl();
virtual AlgorithmInfo* info() const { return 0; }
/**
* Validate parameters and set up data structures for appropriate image size.
* Must call before running on data.
* @param frameSize input frame size
* @param min minimum value taken on by pixels in image sequence. Usually 0
* @param max maximum value taken on by pixels in image sequence. e.g. 1.0 or 255
*/
void initialize(Size frameSize, double minVal, double maxVal);
/**
* Performs single-frame background subtraction and builds up a statistical background image
* model.
* @param image Input image
* @param fgmask Output mask image representing foreground and background pixels
*/
virtual void apply(InputArray image, OutputArray fgmask, double learningRate=-1.0);
/**
* Releases all inner buffers.
*/
void release();
virtual int getMaxFeatures() const { return maxFeatures; }
virtual void setMaxFeatures(int _maxFeatures) { maxFeatures = _maxFeatures; }
virtual double getDefaultLearningRate() const { return learningRate; }
virtual void setDefaultLearningRate(double lr) { learningRate = lr; }
virtual int getNumFrames() const { return numInitializationFrames; }
virtual void setNumFrames(int nframes) { numInitializationFrames = nframes; }
virtual int getQuantizationLevels() const { return quantizationLevels; }
virtual void setQuantizationLevels(int nlevels) { quantizationLevels = nlevels; }
virtual double getBackgroundPrior() const { return backgroundPrior; }
virtual void setBackgroundPrior(double bgprior) { backgroundPrior = bgprior; }
virtual int getSmoothingRadius() const { return smoothingRadius; }
virtual void setSmoothingRadius(int radius) { smoothingRadius = radius; }
virtual double getDecisionThreshold() const { return decisionThreshold; }
virtual void setDecisionThreshold(double thresh) { decisionThreshold = thresh; }
virtual bool getUpdateBackgroundModel() const { return updateBackgroundModel; }
virtual void setUpdateBackgroundModel(bool update) { updateBackgroundModel = update; }
virtual double getMinVal() const { return minVal_; }
virtual void setMinVal(double val) { minVal_ = val; }
virtual double getMaxVal() const { return maxVal_; }
virtual void setMaxVal(double val) { maxVal_ = val; }
virtual void getBackgroundImage(OutputArray) const
{
CV_Error( CV_StsNotImplemented, "" );
}
//! Total number of distinct colors to maintain in histogram.
int maxFeatures;
//! Set between 0.0 and 1.0, determines how quickly features are "forgotten" from histograms.
double learningRate;
//! Number of frames of video to use to initialize histograms.
int numInitializationFrames;
//! Number of discrete levels in each channel to be used in histograms.
int quantizationLevels;
//! Prior probability that any given pixel is a background pixel. A sensitivity parameter.
double backgroundPrior;
//! Value above which pixel is determined to be FG.
double decisionThreshold;
//! Smoothing radius, in pixels, for cleaning up FG image.
int smoothingRadius;
//! Perform background model update
bool updateBackgroundModel;
private:
double maxVal_;
double minVal_;
Size frameSize_;
int frameNum_;
Mat_<int> nfeatures_;
Mat_<unsigned int> colors_;
Mat_<float> weights_;
Mat buf_;
};
BackgroundSubtractorGMGImpl::BackgroundSubtractorGMGImpl()
{
/*
* Default Parameter Values. Override with algorithm "set" method.
......@@ -61,23 +161,24 @@ cv::BackgroundSubtractorGMG::BackgroundSubtractorGMG()
decisionThreshold = 0.8;
smoothingRadius = 7;
updateBackgroundModel = true;
minVal_ = maxVal_ = 0;
}
cv::BackgroundSubtractorGMG::~BackgroundSubtractorGMG()
BackgroundSubtractorGMGImpl::~BackgroundSubtractorGMGImpl()
{
}
void cv::BackgroundSubtractorGMG::initialize(cv::Size frameSize, double min, double max)
void BackgroundSubtractorGMGImpl::initialize(Size frameSize, double minVal, double maxVal)
{
CV_Assert(min < max);
CV_Assert(minVal < maxVal);
CV_Assert(maxFeatures > 0);
CV_Assert(learningRate >= 0.0 && learningRate <= 1.0);
CV_Assert(numInitializationFrames >= 1);
CV_Assert(quantizationLevels >= 1 && quantizationLevels <= 255);
CV_Assert(backgroundPrior >= 0.0 && backgroundPrior <= 1.0);
minVal_ = min;
maxVal_ = max;
minVal_ = minVal;
maxVal_ = maxVal;
frameSize_ = frameSize;
frameNum_ = 0;
......@@ -86,7 +187,7 @@ void cv::BackgroundSubtractorGMG::initialize(cv::Size frameSize, double min, dou
colors_.create(frameSize_.area(), maxFeatures);
weights_.create(frameSize_.area(), maxFeatures);
nfeatures_.setTo(cv::Scalar::all(0));
nfeatures_.setTo(Scalar::all(0));
}
namespace
......@@ -181,10 +282,10 @@ namespace
}
};
class GMG_LoopBody : public cv::ParallelLoopBody
class GMG_LoopBody : public ParallelLoopBody
{
public:
GMG_LoopBody(const cv::Mat& frame, const cv::Mat& fgmask, const cv::Mat_<int>& nfeatures, const cv::Mat_<unsigned int>& colors, const cv::Mat_<float>& weights,
GMG_LoopBody(const Mat& frame, const Mat& fgmask, const Mat_<int>& nfeatures, const Mat_<unsigned int>& colors, const Mat_<float>& weights,
int maxFeatures, double learningRate, int numInitializationFrames, int quantizationLevels, double backgroundPrior, double decisionThreshold,
double maxVal, double minVal, int frameNum, bool updateBackgroundModel) :
frame_(frame), fgmask_(fgmask), nfeatures_(nfeatures), colors_(colors), weights_(weights),
......@@ -194,16 +295,16 @@ namespace
{
}
void operator() (const cv::Range& range) const;
void operator() (const Range& range) const;
private:
cv::Mat frame_;
Mat frame_;
mutable cv::Mat_<uchar> fgmask_;
mutable Mat_<uchar> fgmask_;
mutable cv::Mat_<int> nfeatures_;
mutable cv::Mat_<unsigned int> colors_;
mutable cv::Mat_<float> weights_;
mutable Mat_<int> nfeatures_;
mutable Mat_<unsigned int> colors_;
mutable Mat_<float> weights_;
int maxFeatures_;
double learningRate_;
......@@ -218,7 +319,7 @@ namespace
int frameNum_;
};
void GMG_LoopBody::operator() (const cv::Range& range) const
void GMG_LoopBody::operator() (const Range& range) const
{
typedef unsigned int (*func_t)(const void* src_, int x, int cn, double minVal, double maxVal, int quantizationLevels);
static const func_t funcs[] =
......@@ -296,7 +397,7 @@ namespace
}
}
void cv::BackgroundSubtractorGMG::operator ()(InputArray _frame, OutputArray _fgmask, double newLearningRate)
void BackgroundSubtractorGMGImpl::apply(InputArray _frame, OutputArray _fgmask, double newLearningRate)
{
Mat frame = _frame.getMat();
......@@ -310,7 +411,16 @@ void cv::BackgroundSubtractorGMG::operator ()(InputArray _frame, OutputArray _fg
}
if (frame.size() != frameSize_)
initialize(frame.size(), 0.0, frame.depth() == CV_8U ? 255.0 : frame.depth() == CV_16U ? std::numeric_limits<ushort>::max() : 1.0);
{
double minval = minVal_;
double maxval = maxVal_;
if( minVal_ == 0 && maxVal_ == 0 )
{
minval = 0;
maxval = frame.depth() == CV_8U ? 255.0 : frame.depth() == CV_16U ? std::numeric_limits<ushort>::max() : 1.0;
}
initialize(frame.size(), minval, maxval);
}
_fgmask.create(frameSize_, CV_8UC1);
Mat fgmask = _fgmask.getMat();
......@@ -323,19 +433,58 @@ void cv::BackgroundSubtractorGMG::operator ()(InputArray _frame, OutputArray _fg
if (smoothingRadius > 0)
{
medianBlur(fgmask, buf_, smoothingRadius);
cv::swap(fgmask, buf_);
swap(fgmask, buf_);
}
// keep track of how many frames we have processed
++frameNum_;
}
void cv::BackgroundSubtractorGMG::release()
void BackgroundSubtractorGMGImpl::release()
{
frameSize_ = cv::Size();
frameSize_ = Size();
nfeatures_.release();
colors_.release();
weights_.release();
buf_.release();
}
Ptr<BackgroundSubtractorGMG> createBackgroundSubtractorGMG(int initializationFrames, double decisionThreshold)
{
Ptr<BackgroundSubtractorGMG> bgfg = new BackgroundSubtractorGMGImpl;
bgfg->setNumFrames(initializationFrames);
bgfg->setDecisionThreshold(decisionThreshold);
return bgfg;
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(BackgroundSubtractorGMG, "BackgroundSubtractor.GMG",
obj.info()->addParam(obj, "maxFeatures", obj.maxFeatures,false,0,0,
"Maximum number of features to store in histogram. Harsh enforcement of sparsity constraint.");
obj.info()->addParam(obj, "learningRate", obj.learningRate,false,0,0,
"Adaptation rate of histogram. Close to 1, slow adaptation. Close to 0, fast adaptation, features forgotten quickly.");
obj.info()->addParam(obj, "initializationFrames", obj.numInitializationFrames,false,0,0,
"Number of frames to use to initialize histograms of pixels.");
obj.info()->addParam(obj, "quantizationLevels", obj.quantizationLevels,false,0,0,
"Number of discrete colors to be used in histograms. Up-front quantization.");
obj.info()->addParam(obj, "backgroundPrior", obj.backgroundPrior,false,0,0,
"Prior probability that each individual pixel is a background pixel.");
obj.info()->addParam(obj, "smoothingRadius", obj.smoothingRadius,false,0,0,
"Radius of smoothing kernel to filter noise from FG mask image.");
obj.info()->addParam(obj, "decisionThreshold", obj.decisionThreshold,false,0,0,
"Threshold for FG decision rule. Pixel is FG if posterior probability exceeds threshold.");
obj.info()->addParam(obj, "updateBackgroundModel", obj.updateBackgroundModel,false,0,0,
"Perform background model update.");
obj.info()->addParam(obj, "minVal", obj.minVal_,false,0,0,
"Minimum of the value range (mostly for regression testing)");
obj.info()->addParam(obj, "maxVal", obj.maxVal_,false,0,0,
"Maximum of the value range (mostly for regression testing)");
);
*/
}
......@@ -7,10 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
......@@ -40,285 +41,156 @@
//M*/
#include "precomp.hpp"
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvMeanShift
// Purpose: MeanShift algorithm
// Context:
// Parameters:
// imgProb - 2D object probability distribution
// windowIn - CvRect of CAMSHIFT Window intial size
// numIters - If CAMSHIFT iterates this many times, stop
// windowOut - Location, height and width of converged CAMSHIFT window
// len - If != NULL, return equivalent len
// width - If != NULL, return equivalent width
// Returns:
// Number of iterations CAMSHIFT took to converge
// Notes:
//F*/
CV_IMPL int
cvMeanShift( const void* imgProb, CvRect windowIn,
CvTermCriteria criteria, CvConnectedComp* comp )
int cv::meanShift( InputArray _probImage, Rect& window, TermCriteria criteria )
{
CvMoments moments;
int i = 0, eps;
CvMat stub, *mat = (CvMat*)imgProb;
CvMat cur_win;
CvRect cur_rect = windowIn;
if( comp )
comp->rect = windowIn;
moments.m00 = moments.m10 = moments.m01 = 0;
mat = cvGetMat( mat, &stub );
Mat mat = _probImage.getMat();
Rect cur_rect = window;
if( CV_MAT_CN( mat->type ) > 1 )
CV_Error( CV_BadNumChannels, cvUnsupportedFormat );
CV_Assert( mat.channels() == 1 );
if( windowIn.height <= 0 || windowIn.width <= 0 )
if( window.height <= 0 || window.width <= 0 )
CV_Error( CV_StsBadArg, "Input window has non-positive sizes" );
windowIn = cv::Rect(windowIn) & cv::Rect(0, 0, mat->cols, mat->rows);
window = window & Rect(0, 0, mat.cols, mat.rows);
criteria = cvCheckTermCriteria( criteria, 1., 100 );
eps = cvRound( criteria.epsilon * criteria.epsilon );
double eps = (criteria.type & TermCriteria::EPS) ? std::max(criteria.epsilon, 0.) : 1.;
eps = cvRound(eps*eps);
int i, niters = (criteria.type & TermCriteria::MAX_ITER) ? std::max(criteria.maxCount, 1) : 100;
for( i = 0; i < criteria.max_iter; i++ )
for( i = 0; i < niters; i++ )
{
int dx, dy, nx, ny;
double inv_m00;
cur_rect = cv::Rect(cur_rect) & cv::Rect(0, 0, mat->cols, mat->rows);
if( cv::Rect(cur_rect) == cv::Rect() )
cur_rect = cur_rect & Rect(0, 0, mat.cols, mat.rows);
if( cur_rect == Rect() )
{
cur_rect.x = mat->cols/2;
cur_rect.y = mat->rows/2;
cur_rect.x = mat.cols/2;
cur_rect.y = mat.rows/2;
}
cur_rect.width = MAX(cur_rect.width, 1);
cur_rect.height = MAX(cur_rect.height, 1);
cur_rect.width = std::max(cur_rect.width, 1);
cur_rect.height = std::max(cur_rect.height, 1);
cvGetSubRect( mat, &cur_win, cur_rect );
cvMoments( &cur_win, &moments );
Moments m = moments(mat(cur_rect));
/* Calculating center of mass */
if( fabs(moments.m00) < DBL_EPSILON )
// Calculating center of mass
if( fabs(m.m00) < DBL_EPSILON )
break;
inv_m00 = moments.inv_sqrt_m00*moments.inv_sqrt_m00;
dx = cvRound( moments.m10 * inv_m00 - windowIn.width*0.5 );
dy = cvRound( moments.m01 * inv_m00 - windowIn.height*0.5 );
int dx = cvRound( m.m10/m.m00 - window.width*0.5 );
int dy = cvRound( m.m01/m.m00 - window.height*0.5 );
nx = cur_rect.x + dx;
ny = cur_rect.y + dy;
if( nx < 0 )
nx = 0;
else if( nx + cur_rect.width > mat->cols )
nx = mat->cols - cur_rect.width;
if( ny < 0 )
ny = 0;
else if( ny + cur_rect.height > mat->rows )
ny = mat->rows - cur_rect.height;
int nx = std::min(std::max(cur_rect.x + dx, 0), mat.cols - cur_rect.width);
int ny = std::min(std::max(cur_rect.y + dy, 0), mat.rows - cur_rect.height);
dx = nx - cur_rect.x;
dy = ny - cur_rect.y;
cur_rect.x = nx;
cur_rect.y = ny;
/* Check for coverage centers mass & window */
// Check for coverage centers mass & window
if( dx*dx + dy*dy < eps )
break;
}
if( comp )
{
comp->rect = cur_rect;
comp->area = (float)moments.m00;
}
window = cur_rect;
return i;
}
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvCamShift
// Purpose: CAMSHIFT algorithm
// Context:
// Parameters:
// imgProb - 2D object probability distribution
// windowIn - CvRect of CAMSHIFT Window intial size
// criteria - criteria of stop finding window
// windowOut - Location, height and width of converged CAMSHIFT window
// orientation - If != NULL, return distribution orientation
// len - If != NULL, return equivalent len
// width - If != NULL, return equivalent width
// area - sum of all elements in result window
// Returns:
// Number of iterations CAMSHIFT took to converge
// Notes:
//F*/
CV_IMPL int
cvCamShift( const void* imgProb, CvRect windowIn,
CvTermCriteria criteria,
CvConnectedComp* _comp,
CvBox2D* box )
cv::RotatedRect cv::CamShift( InputArray _probImage, Rect& window,
TermCriteria criteria )
{
const int TOLERANCE = 10;
CvMoments moments;
double m00 = 0, m10, m01, mu20, mu11, mu02, inv_m00;
double a, b, c, xc, yc;
double rotate_a, rotate_c;
double theta = 0, square;
double cs, sn;
double length = 0, width = 0;
int itersUsed = 0;
CvConnectedComp comp;
CvMat cur_win, stub, *mat = (CvMat*)imgProb;
comp.rect = windowIn;
Mat mat = _probImage.getMat();
mat = cvGetMat( mat, &stub );
meanShift( mat, window, criteria );
itersUsed = cvMeanShift( mat, windowIn, criteria, &comp );
windowIn = comp.rect;
window.x -= TOLERANCE;
if( window.x < 0 )
window.x = 0;
windowIn.x -= TOLERANCE;
if( windowIn.x < 0 )
windowIn.x = 0;
window.y -= TOLERANCE;
if( window.y < 0 )
window.y = 0;
windowIn.y -= TOLERANCE;
if( windowIn.y < 0 )
windowIn.y = 0;
window.width += 2 * TOLERANCE;
if( window.x + window.width > mat.cols )
window.width = mat.cols - window.x;
windowIn.width += 2 * TOLERANCE;
if( windowIn.x + windowIn.width > mat->width )
windowIn.width = mat->width - windowIn.x;
window.height += 2 * TOLERANCE;
if( window.y + window.height > mat.rows )
window.height = mat.rows - window.y;
windowIn.height += 2 * TOLERANCE;
if( windowIn.y + windowIn.height > mat->height )
windowIn.height = mat->height - windowIn.y;
// Calculating moments in new center mass
Moments m = moments( mat(window) );
cvGetSubRect( mat, &cur_win, windowIn );
/* Calculating moments in new center mass */
cvMoments( &cur_win, &moments );
m00 = moments.m00;
m10 = moments.m10;
m01 = moments.m01;
mu11 = moments.mu11;
mu20 = moments.mu20;
mu02 = moments.mu02;
double m00 = m.m00, m10 = m.m10, m01 = m.m01;
double mu11 = m.mu11, mu20 = m.mu20, mu02 = m.mu02;
if( fabs(m00) < DBL_EPSILON )
return -1;
return RotatedRect();
inv_m00 = 1. / m00;
xc = cvRound( m10 * inv_m00 + windowIn.x );
yc = cvRound( m01 * inv_m00 + windowIn.y );
a = mu20 * inv_m00;
b = mu11 * inv_m00;
c = mu02 * inv_m00;
double inv_m00 = 1. / m00;
int xc = cvRound( m10 * inv_m00 + window.x );
int yc = cvRound( m01 * inv_m00 + window.y );
double a = mu20 * inv_m00, b = mu11 * inv_m00, c = mu02 * inv_m00;
/* Calculating width & height */
square = sqrt( 4 * b * b + (a - c) * (a - c) );
// Calculating width & height
double square = std::sqrt( 4 * b * b + (a - c) * (a - c) );
/* Calculating orientation */
theta = atan2( 2 * b, a - c + square );
// Calculating orientation
double theta = atan2( 2 * b, a - c + square );
/* Calculating width & length of figure */
cs = cos( theta );
sn = sin( theta );
// Calculating width & length of figure
double cs = cos( theta );
double sn = sin( theta );
rotate_a = cs * cs * mu20 + 2 * cs * sn * mu11 + sn * sn * mu02;
rotate_c = sn * sn * mu20 - 2 * cs * sn * mu11 + cs * cs * mu02;
length = sqrt( rotate_a * inv_m00 ) * 4;
width = sqrt( rotate_c * inv_m00 ) * 4;
double rotate_a = cs * cs * mu20 + 2 * cs * sn * mu11 + sn * sn * mu02;
double rotate_c = sn * sn * mu20 - 2 * cs * sn * mu11 + cs * cs * mu02;
double length = std::sqrt( rotate_a * inv_m00 ) * 4;
double width = std::sqrt( rotate_c * inv_m00 ) * 4;
/* In case, when tetta is 0 or 1.57... the Length & Width may be exchanged */
// In case, when tetta is 0 or 1.57... the Length & Width may be exchanged
if( length < width )
{
double t;
CV_SWAP( length, width, t );
CV_SWAP( cs, sn, t );
std::swap( length, width );
std::swap( cs, sn );
theta = CV_PI*0.5 - theta;
}
/* Saving results */
if( _comp || box )
{
int t0, t1;
int _xc = cvRound( xc );
int _yc = cvRound( yc );
// Saving results
int _xc = cvRound( xc );
int _yc = cvRound( yc );
t0 = cvRound( fabs( length * cs ));
t1 = cvRound( fabs( width * sn ));
int t0 = cvRound( fabs( length * cs ));
int t1 = cvRound( fabs( width * sn ));
t0 = MAX( t0, t1 ) + 2;
comp.rect.width = MIN( t0, (mat->width - _xc) * 2 );
t0 = MAX( t0, t1 ) + 2;
window.width = MIN( t0, (mat.cols - _xc) * 2 );
t0 = cvRound( fabs( length * sn ));
t1 = cvRound( fabs( width * cs ));
t0 = cvRound( fabs( length * sn ));
t1 = cvRound( fabs( width * cs ));
t0 = MAX( t0, t1 ) + 2;
comp.rect.height = MIN( t0, (mat->height - _yc) * 2 );
t0 = MAX( t0, t1 ) + 2;
window.height = MIN( t0, (mat.rows - _yc) * 2 );
comp.rect.x = MAX( 0, _xc - comp.rect.width / 2 );
comp.rect.y = MAX( 0, _yc - comp.rect.height / 2 );
comp.rect.width = MIN( mat->width - comp.rect.x, comp.rect.width );
comp.rect.height = MIN( mat->height - comp.rect.y, comp.rect.height );
comp.area = (float) m00;
}
if( _comp )
*_comp = comp;
if( box )
{
box->size.height = (float)length;
box->size.width = (float)width;
box->angle = (float)((CV_PI*0.5+theta)*180./CV_PI);
while(box->angle < 0)
box->angle += 360;
while(box->angle >= 360)
box->angle -= 360;
if(box->angle >= 180)
box->angle -= 180;
box->center = cvPoint2D32f( comp.rect.x + comp.rect.width*0.5f,
comp.rect.y + comp.rect.height*0.5f);
}
return itersUsed;
}
window.x = MAX( 0, _xc - window.width / 2 );
window.y = MAX( 0, _yc - window.height / 2 );
window.width = MIN( mat.cols - window.x, window.width );
window.height = MIN( mat.rows - window.y, window.height );
cv::RotatedRect cv::CamShift( InputArray _probImage, Rect& window,
TermCriteria criteria )
{
CvConnectedComp comp;
CvBox2D box;
box.center.x = box.center.y = 0; box.angle = 0; box.size.width = box.size.height = 0;
comp.rect.x = comp.rect.y = comp.rect.width = comp.rect.height = 0;
RotatedRect box;
box.size.height = (float)length;
box.size.width = (float)width;
box.angle = (float)((CV_PI*0.5+theta)*180./CV_PI);
while(box.angle < 0)
box.angle += 360;
while(box.angle >= 360)
box.angle -= 360;
if(box.angle >= 180)
box.angle -= 180;
box.center = Point2f( window.x + window.width*0.5f, window.y + window.height*0.5f);
Mat probImage = _probImage.getMat();
CvMat c_probImage = probImage;
cvCamShift(&c_probImage, window, (CvTermCriteria)criteria, &comp, &box);
window = comp.rect;
return RotatedRect(Point2f(box.center), Size2f(box.size), box.angle);
}
int cv::meanShift( InputArray _probImage, Rect& window, TermCriteria criteria )
{
CvConnectedComp comp;
Mat probImage = _probImage.getMat();
CvMat c_probImage = probImage;
int iters = cvMeanShift(&c_probImage, window, (CvTermCriteria)criteria, &comp );
window = comp.rect;
return iters;
return box;
}
/* End of file. */
......@@ -305,23 +305,8 @@ static void update_warping_matrix_ECC (Mat& map_matrix, const Mat& update, const
mapPtr[3] = (float) sin(new_theta);
mapPtr[1] = -mapPtr[3];
}
}
CV_IMPL double cvFindTransformECC (const CvArr* _image1, const CvArr* _image2,
CvMat* _map_matrix,
const int motionType,
const CvTermCriteria _criteria)
{
Mat image1 = cvarrToMat(_image1);
Mat image2 = cvarrToMat(_image2);
Mat map_matrix = cvarrToMat(_map_matrix);
double cc = cv::findTransformECC(image1, image2, map_matrix, motionType,
TermCriteria(TermCriteria::EPS+TermCriteria::COUNT, _criteria.max_iter, _criteria.epsilon));
return cc;
}
double cv::findTransformECC(InputArray templateImage,
InputArray inputImage,
......
......@@ -40,176 +40,6 @@
//M*/
#include "precomp.hpp"
CV_IMPL CvKalman*
cvCreateKalman( int DP, int MP, int CP )
{
CvKalman *kalman = 0;
if( DP <= 0 || MP <= 0 )
CV_Error( CV_StsOutOfRange,
"state and measurement vectors must have positive number of dimensions" );
if( CP < 0 )
CP = DP;
/* allocating memory for the structure */
kalman = (CvKalman *)cvAlloc( sizeof( CvKalman ));
memset( kalman, 0, sizeof(*kalman));
kalman->DP = DP;
kalman->MP = MP;
kalman->CP = CP;
kalman->state_pre = cvCreateMat( DP, 1, CV_32FC1 );
cvZero( kalman->state_pre );
kalman->state_post = cvCreateMat( DP, 1, CV_32FC1 );
cvZero( kalman->state_post );
kalman->transition_matrix = cvCreateMat( DP, DP, CV_32FC1 );
cvSetIdentity( kalman->transition_matrix );
kalman->process_noise_cov = cvCreateMat( DP, DP, CV_32FC1 );
cvSetIdentity( kalman->process_noise_cov );
kalman->measurement_matrix = cvCreateMat( MP, DP, CV_32FC1 );
cvZero( kalman->measurement_matrix );
kalman->measurement_noise_cov = cvCreateMat( MP, MP, CV_32FC1 );
cvSetIdentity( kalman->measurement_noise_cov );
kalman->error_cov_pre = cvCreateMat( DP, DP, CV_32FC1 );
kalman->error_cov_post = cvCreateMat( DP, DP, CV_32FC1 );
cvZero( kalman->error_cov_post );
kalman->gain = cvCreateMat( DP, MP, CV_32FC1 );
if( CP > 0 )
{
kalman->control_matrix = cvCreateMat( DP, CP, CV_32FC1 );
cvZero( kalman->control_matrix );
}
kalman->temp1 = cvCreateMat( DP, DP, CV_32FC1 );
kalman->temp2 = cvCreateMat( MP, DP, CV_32FC1 );
kalman->temp3 = cvCreateMat( MP, MP, CV_32FC1 );
kalman->temp4 = cvCreateMat( MP, DP, CV_32FC1 );
kalman->temp5 = cvCreateMat( MP, 1, CV_32FC1 );
#if 1
kalman->PosterState = kalman->state_pre->data.fl;
kalman->PriorState = kalman->state_post->data.fl;
kalman->DynamMatr = kalman->transition_matrix->data.fl;
kalman->MeasurementMatr = kalman->measurement_matrix->data.fl;
kalman->MNCovariance = kalman->measurement_noise_cov->data.fl;
kalman->PNCovariance = kalman->process_noise_cov->data.fl;
kalman->KalmGainMatr = kalman->gain->data.fl;
kalman->PriorErrorCovariance = kalman->error_cov_pre->data.fl;
kalman->PosterErrorCovariance = kalman->error_cov_post->data.fl;
#endif
return kalman;
}
CV_IMPL void
cvReleaseKalman( CvKalman** _kalman )
{
CvKalman *kalman;
if( !_kalman )
CV_Error( CV_StsNullPtr, "" );
kalman = *_kalman;
if( !kalman )
return;
/* freeing the memory */
cvReleaseMat( &kalman->state_pre );
cvReleaseMat( &kalman->state_post );
cvReleaseMat( &kalman->transition_matrix );
cvReleaseMat( &kalman->control_matrix );
cvReleaseMat( &kalman->measurement_matrix );
cvReleaseMat( &kalman->process_noise_cov );
cvReleaseMat( &kalman->measurement_noise_cov );
cvReleaseMat( &kalman->error_cov_pre );
cvReleaseMat( &kalman->gain );
cvReleaseMat( &kalman->error_cov_post );
cvReleaseMat( &kalman->temp1 );
cvReleaseMat( &kalman->temp2 );
cvReleaseMat( &kalman->temp3 );
cvReleaseMat( &kalman->temp4 );
cvReleaseMat( &kalman->temp5 );
memset( kalman, 0, sizeof(*kalman));
/* deallocating the structure */
cvFree( _kalman );
}
CV_IMPL const CvMat*
cvKalmanPredict( CvKalman* kalman, const CvMat* control )
{
if( !kalman )
CV_Error( CV_StsNullPtr, "" );
/* update the state */
/* x'(k) = A*x(k) */
cvMatMulAdd( kalman->transition_matrix, kalman->state_post, 0, kalman->state_pre );
if( control && kalman->CP > 0 )
/* x'(k) = x'(k) + B*u(k) */
cvMatMulAdd( kalman->control_matrix, control, kalman->state_pre, kalman->state_pre );
/* update error covariance matrices */
/* temp1 = A*P(k) */
cvMatMulAdd( kalman->transition_matrix, kalman->error_cov_post, 0, kalman->temp1 );
/* P'(k) = temp1*At + Q */
cvGEMM( kalman->temp1, kalman->transition_matrix, 1, kalman->process_noise_cov, 1,
kalman->error_cov_pre, CV_GEMM_B_T );
/* handle the case when there will be measurement before the next predict */
cvCopy(kalman->state_pre, kalman->state_post);
return kalman->state_pre;
}
CV_IMPL const CvMat*
cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement )
{
if( !kalman || !measurement )
CV_Error( CV_StsNullPtr, "" );
/* temp2 = H*P'(k) */
cvMatMulAdd( kalman->measurement_matrix, kalman->error_cov_pre, 0, kalman->temp2 );
/* temp3 = temp2*Ht + R */
cvGEMM( kalman->temp2, kalman->measurement_matrix, 1,
kalman->measurement_noise_cov, 1, kalman->temp3, CV_GEMM_B_T );
/* temp4 = inv(temp3)*temp2 = Kt(k) */
cvSolve( kalman->temp3, kalman->temp2, kalman->temp4, CV_SVD );
/* K(k) */
cvTranspose( kalman->temp4, kalman->gain );
/* temp5 = z(k) - H*x'(k) */
cvGEMM( kalman->measurement_matrix, kalman->state_pre, -1, measurement, 1, kalman->temp5 );
/* x(k) = x'(k) + K(k)*temp5 */
cvMatMulAdd( kalman->gain, kalman->temp5, kalman->state_pre, kalman->state_post );
/* P(k) = P'(k) - K(k)*temp2 */
cvGEMM( kalman->gain, kalman->temp2, -1, kalman->error_cov_pre, 1,
kalman->error_cov_post, 0 );
return kalman->state_post;
}
namespace cv
{
......
此差异已折叠。
此差异已折叠。
......@@ -644,18 +644,3 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
prevFlow = flow;
}
}
CV_IMPL void cvCalcOpticalFlowFarneback(
const CvArr* _prev, const CvArr* _next,
CvArr* _flow, double pyr_scale, int levels,
int winsize, int iterations, int poly_n,
double poly_sigma, int flags )
{
cv::Mat prev = cv::cvarrToMat(_prev), next = cv::cvarrToMat(_next);
cv::Mat flow = cv::cvarrToMat(_flow);
CV_Assert( flow.size() == prev.size() && flow.type() == CV_32FC2 );
cv::calcOpticalFlowFarneback( prev, next, flow, pyr_scale, levels,
winsize, iterations, poly_n, poly_sigma, flags );
}
......@@ -41,7 +41,6 @@
//M*/
#include "precomp.hpp"
#include "simpleflow.hpp"
//
// 2D dense optical flow algorithm from the following paper:
......@@ -54,6 +53,39 @@
namespace cv
{
static const uchar MASK_TRUE_VALUE = (uchar)255;
inline static float dist(const Vec3b& p1, const Vec3b& p2) {
return (float)((p1[0] - p2[0]) * (p1[0] - p2[0]) +
(p1[1] - p2[1]) * (p1[1] - p2[1]) +
(p1[2] - p2[2]) * (p1[2] - p2[2]));
}
inline static float dist(const Vec2f& p1, const Vec2f& p2) {
return (p1[0] - p2[0]) * (p1[0] - p2[0]) +
(p1[1] - p2[1]) * (p1[1] - p2[1]);
}
inline static float dist(const Point2f& p1, const Point2f& p2) {
return (p1.x - p2.x) * (p1.x - p2.x) +
(p1.y - p2.y) * (p1.y - p2.y);
}
inline static float dist(float x1, float y1, float x2, float y2) {
return (x1 - x2) * (x1 - x2) +
(y1 - y2) * (y1 - y2);
}
inline static int dist(int x1, int y1, int x2, int y2) {
return (x1 - x2) * (x1 - x2) +
(y1 - y2) * (y1 - y2);
}
template<class T>
inline static T min(T t1, T t2, T t3) {
return (t1 <= t2 && t1 <= t3) ? t1 : min(t2, t3);
}
static void removeOcclusions(const Mat& flow,
const Mat& flow_inv,
float occ_thr,
......
......@@ -46,50 +46,9 @@
namespace cv
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(BackgroundSubtractorMOG, "BackgroundSubtractor.MOG",
obj.info()->addParam(obj, "history", obj.history);
obj.info()->addParam(obj, "nmixtures", obj.nmixtures);
obj.info()->addParam(obj, "backgroundRatio", obj.backgroundRatio);
obj.info()->addParam(obj, "noiseSigma", obj.noiseSigma));
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(BackgroundSubtractorMOG2, "BackgroundSubtractor.MOG2",
obj.info()->addParam(obj, "history", obj.history);
obj.info()->addParam(obj, "nmixtures", obj.nmixtures);
obj.info()->addParam(obj, "varThreshold", obj.varThreshold);
obj.info()->addParam(obj, "detectShadows", obj.bShadowDetection));
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(BackgroundSubtractorGMG, "BackgroundSubtractor.GMG",
obj.info()->addParam(obj, "maxFeatures", obj.maxFeatures,false,0,0,
"Maximum number of features to store in histogram. Harsh enforcement of sparsity constraint.");
obj.info()->addParam(obj, "learningRate", obj.learningRate,false,0,0,
"Adaptation rate of histogram. Close to 1, slow adaptation. Close to 0, fast adaptation, features forgotten quickly.");
obj.info()->addParam(obj, "initializationFrames", obj.numInitializationFrames,false,0,0,
"Number of frames to use to initialize histograms of pixels.");
obj.info()->addParam(obj, "quantizationLevels", obj.quantizationLevels,false,0,0,
"Number of discrete colors to be used in histograms. Up-front quantization.");
obj.info()->addParam(obj, "backgroundPrior", obj.backgroundPrior,false,0,0,
"Prior probability that each individual pixel is a background pixel.");
obj.info()->addParam(obj, "smoothingRadius", obj.smoothingRadius,false,0,0,
"Radius of smoothing kernel to filter noise from FG mask image.");
obj.info()->addParam(obj, "decisionThreshold", obj.decisionThreshold,false,0,0,
"Threshold for FG decision rule. Pixel is FG if posterior probability exceeds threshold.");
obj.info()->addParam(obj, "updateBackgroundModel", obj.updateBackgroundModel,false,0,0,
"Perform background model update."));
bool initModule_video(void)
{
bool all = true;
all &= !BackgroundSubtractorMOG_info_auto.name().empty();
all &= !BackgroundSubtractorMOG2_info_auto.name().empty();
all &= !BackgroundSubtractorGMG_info_auto.name().empty();
return all;
return true;
}
}
......@@ -37,8 +37,7 @@ void CV_BackgroundSubtractorTest::run(int)
int width = 2 + ((unsigned int)rng)%98; //!< Mat will be 2 to 100 in width and height
int height = 2 + ((unsigned int)rng)%98;
Ptr<BackgroundSubtractorGMG> fgbg =
Algorithm::create<BackgroundSubtractorGMG>("BackgroundSubtractor.GMG");
Ptr<BackgroundSubtractorGMG> fgbg = createBackgroundSubtractorGMG();
Mat fgmask;
if (fgbg.empty())
......@@ -47,19 +46,13 @@ void CV_BackgroundSubtractorTest::run(int)
/**
* Set a few parameters
*/
fgbg->set("smoothingRadius",7);
fgbg->set("decisionThreshold",0.7);
fgbg->set("initializationFrames",120);
fgbg->setSmoothingRadius(7);
fgbg->setDecisionThreshold(0.7);
fgbg->setNumFrames(120);
/**
* Generate bounds for the values in the matrix for each type
*/
uchar maxuc = 0, minuc = 0;
char maxc = 0, minc = 0;
unsigned int maxui = 0, minui = 0;
int maxi=0, mini = 0;
long int maxli = 0, minli = 0;
float maxf = 0, minf = 0;
double maxd = 0, mind = 0;
/**
......@@ -69,34 +62,34 @@ void CV_BackgroundSubtractorTest::run(int)
if (type == CV_8U)
{
uchar half = UCHAR_MAX/2;
maxuc = (unsigned char)rng.uniform(half+32, UCHAR_MAX);
minuc = (unsigned char)rng.uniform(0, half-32);
maxd = (unsigned char)rng.uniform(half+32, UCHAR_MAX);
mind = (unsigned char)rng.uniform(0, half-32);
}
else if (type == CV_8S)
{
maxc = (char)rng.uniform(32, CHAR_MAX);
minc = (char)rng.uniform(CHAR_MIN, -32);
maxd = (char)rng.uniform(32, CHAR_MAX);
mind = (char)rng.uniform(CHAR_MIN, -32);
}
else if (type == CV_16U)
{
ushort half = USHRT_MAX/2;
maxui = (unsigned int)rng.uniform(half+32, USHRT_MAX);
minui = (unsigned int)rng.uniform(0, half-32);
maxd = (unsigned int)rng.uniform(half+32, USHRT_MAX);
mind = (unsigned int)rng.uniform(0, half-32);
}
else if (type == CV_16S)
{
maxi = rng.uniform(32, SHRT_MAX);
mini = rng.uniform(SHRT_MIN, -32);
maxd = rng.uniform(32, SHRT_MAX);
mind = rng.uniform(SHRT_MIN, -32);
}
else if (type == CV_32S)
{
maxli = rng.uniform(32, INT_MAX);
minli = rng.uniform(INT_MIN, -32);
maxd = rng.uniform(32, INT_MAX);
mind = rng.uniform(INT_MIN, -32);
}
else if (type == CV_32F)
{
maxf = rng.uniform(32.0f, FLT_MAX);
minf = rng.uniform(-FLT_MAX, -32.0f);
maxd = rng.uniform(32.0f, FLT_MAX);
mind = rng.uniform(-FLT_MAX, -32.0f);
}
else if (type == CV_64F)
{
......@@ -104,60 +97,22 @@ void CV_BackgroundSubtractorTest::run(int)
mind = rng.uniform(-DBL_MAX, -32.0);
}
fgbg->setMinVal(mind);
fgbg->setMaxVal(maxd);
Mat simImage = Mat::zeros(height, width, channelsAndType);
const unsigned int numLearningFrames = 120;
for (unsigned int i = 0; i < numLearningFrames; ++i)
int numLearningFrames = 120;
for (int i = 0; i < numLearningFrames; ++i)
{
/**
* Genrate simulated "image" for any type. Values always confined to upper half of range.
*/
if (type == CV_8U)
{
rng.fill(simImage,RNG::UNIFORM,(unsigned char)(minuc/2+maxuc/2),maxuc);
if (i == 0)
fgbg->initialize(simImage.size(),minuc,maxuc);
}
else if (type == CV_8S)
{
rng.fill(simImage,RNG::UNIFORM,(char)(minc/2+maxc/2),maxc);
if (i==0)
fgbg->initialize(simImage.size(),minc,maxc);
}
else if (type == CV_16U)
{
rng.fill(simImage,RNG::UNIFORM,(unsigned int)(minui/2+maxui/2),maxui);
if (i==0)
fgbg->initialize(simImage.size(),minui,maxui);
}
else if (type == CV_16S)
{
rng.fill(simImage,RNG::UNIFORM,(int)(mini/2+maxi/2),maxi);
if (i==0)
fgbg->initialize(simImage.size(),mini,maxi);
}
else if (type == CV_32F)
{
rng.fill(simImage,RNG::UNIFORM,(float)(minf/2.0+maxf/2.0),maxf);
if (i==0)
fgbg->initialize(simImage.size(),minf,maxf);
}
else if (type == CV_32S)
{
rng.fill(simImage,RNG::UNIFORM,(long int)(minli/2+maxli/2),maxli);
if (i==0)
fgbg->initialize(simImage.size(),minli,maxli);
}
else if (type == CV_64F)
{
rng.fill(simImage,RNG::UNIFORM,(double)(mind/2.0+maxd/2.0),maxd);
if (i==0)
fgbg->initialize(simImage.size(),mind,maxd);
}
rng.fill(simImage, RNG::UNIFORM, (mind + maxd)*0.5, maxd);
/**
* Feed simulated images into background subtractor
*/
(*fgbg)(simImage,fgmask);
fgbg->apply(simImage,fgmask);
Mat fullbg = Mat::zeros(simImage.rows, simImage.cols, CV_8U);
//! fgmask should be entirely background during training
......@@ -166,22 +121,9 @@ void CV_BackgroundSubtractorTest::run(int)
ts->set_failed_test_info( code );
}
//! generate last image, distinct from training images
if (type == CV_8U)
rng.fill(simImage,RNG::UNIFORM,minuc,minuc);
else if (type == CV_8S)
rng.fill(simImage,RNG::UNIFORM,minc,minc);
else if (type == CV_16U)
rng.fill(simImage,RNG::UNIFORM,minui,minui);
else if (type == CV_16S)
rng.fill(simImage,RNG::UNIFORM,mini,mini);
else if (type == CV_32F)
rng.fill(simImage,RNG::UNIFORM,minf,minf);
else if (type == CV_32S)
rng.fill(simImage,RNG::UNIFORM,minli,minli);
else if (type == CV_64F)
rng.fill(simImage,RNG::UNIFORM,mind,mind);
rng.fill(simImage, RNG::UNIFORM, mind, maxd);
(*fgbg)(simImage,fgmask);
fgbg->apply(simImage,fgmask);
//! now fgmask should be entirely foreground
Mat fullfg = 255*Mat::ones(simImage.rows, simImage.cols, CV_8U);
code = cvtest::cmpEps2( ts, fgmask, fullfg, 255, false, "The final foreground mask" );
......
......@@ -153,7 +153,7 @@ bool CV_RigidTransform_Test::testImage()
Mat aff_est = estimateRigidTransform(img, rotated, true);
const double thres = 0.03;
const double thres = 0.033;
if (norm(aff_est, aff, NORM_INF) > thres)
{
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
......
......@@ -32,16 +32,13 @@ int main(int argc, char** argv)
setUseOptimized(true);
setNumThreads(8);
Ptr<BackgroundSubtractorGMG> fgbg = Algorithm::create<BackgroundSubtractorGMG>("BackgroundSubtractor.GMG");
Ptr<BackgroundSubtractor> fgbg = createBackgroundSubtractorGMG(20, 0.7);
if (fgbg.empty())
{
std::cerr << "Failed to create BackgroundSubtractor.GMG Algorithm." << std::endl;
return -1;
}
fgbg->set("initializationFrames", 20);
fgbg->set("decisionThreshold", 0.7);
VideoCapture cap;
if (argc > 1)
cap.open(argv[1]);
......@@ -65,9 +62,9 @@ int main(int argc, char** argv)
if (frame.empty())
break;
(*fgbg)(frame, fgmask);
fgbg->apply(frame, fgmask);
frame.copyTo(segm);
frame.convertTo(segm, CV_8U, 0.5);
add(frame, Scalar(100, 100, 0), segm, fgmask);
imshow("FG Segmentation", segm);
......
......@@ -51,7 +51,7 @@ int main(int argc, const char** argv)
namedWindow("foreground image", CV_WINDOW_NORMAL);
namedWindow("mean background image", CV_WINDOW_NORMAL);
BackgroundSubtractorMOG2 bg_model;//(100, 3, 0.3, 5);
Ptr<BackgroundSubtractor> bg_model = createBackgroundSubtractorMOG2();
Mat img, fgmask, fgimg;
......@@ -68,13 +68,13 @@ int main(int argc, const char** argv)
fgimg.create(img.size(), img.type());
//update the model
bg_model(img, fgmask, update_bg_model ? -1 : 0);
bg_model->apply(img, fgmask, update_bg_model ? -1 : 0);
fgimg = Scalar::all(0);
img.copyTo(fgimg, fgmask);
Mat bgimg;
bg_model.getBackgroundImage(bgimg);
bg_model->getBackgroundImage(bgimg);
imshow("image", img);
imshow("foreground mask", fgmask);
......
......@@ -87,15 +87,15 @@ int main(int argc, char** argv)
namedWindow("video", 1);
namedWindow("segmented", 1);
BackgroundSubtractorMOG bgsubtractor;
bgsubtractor.set("noiseSigma", 10);
Ptr<BackgroundSubtractorMOG> bgsubtractor=createBackgroundSubtractorMOG();
bgsubtractor->setNoiseSigma(10);
for(;;)
{
cap >> tmp_frame;
if( !tmp_frame.data )
break;
bgsubtractor(tmp_frame, bgmask, update_bg_model ? -1 : 0);
bgsubtractor->apply(tmp_frame, bgmask, update_bg_model ? -1 : 0);
//CvMat _bgmask = bgmask;
//cvSegmentFGMask(&_bgmask);
refineSegments(tmp_frame, bgmask, out_frame);
......
......@@ -1316,10 +1316,10 @@ TEST(MOG)
cv::Mat frame;
cap >> frame;
cv::BackgroundSubtractorMOG mog;
cv::Ptr<cv::BackgroundSubtractor> mog = cv::createBackgroundSubtractorMOG();
cv::Mat foreground;
mog(frame, foreground, 0.01);
mog->apply(frame, foreground, 0.01);
while (!TestSystem::instance().stop())
{
......@@ -1327,7 +1327,7 @@ TEST(MOG)
TestSystem::instance().cpuOn();
mog(frame, foreground, 0.01);
mog->apply(frame, foreground, 0.01);
TestSystem::instance().cpuOff();
}
......@@ -1367,12 +1367,12 @@ TEST(MOG2)
cv::Mat frame;
cap >> frame;
cv::BackgroundSubtractorMOG2 mog2;
cv::Ptr<cv::BackgroundSubtractor> mog2 = cv::createBackgroundSubtractorMOG2();
cv::Mat foreground;
cv::Mat background;
mog2(frame, foreground);
mog2.getBackgroundImage(background);
mog2->apply(frame, foreground);
mog2->getBackgroundImage(background);
while (!TestSystem::instance().stop())
{
......@@ -1380,8 +1380,8 @@ TEST(MOG2)
TestSystem::instance().cpuOn();
mog2(frame, foreground);
mog2.getBackgroundImage(background);
mog2->apply(frame, foreground);
mog2->getBackgroundImage(background);
TestSystem::instance().cpuOff();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册