2010-12-29 00:25:39 +08:00
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// 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
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
/*//Implementation of the Gaussian mixture model background subtraction from:
//
//"Improved adaptive Gausian mixture model for background subtraction"
//Z.Zivkovic
//International Conference Pattern Recognition, UK, August, 2004
//http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
//The code is very fast and performs also shadow detection.
//Number of Gausssian components is adapted per pixel.
//
// and
//
//"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
//Z.Zivkovic, F. van der Heijden
//Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
//
//The algorithm similar to the standard Stauffer&Grimson algorithm with
//additional selection of the number of the Gaussian components based on:
//
//"Recursive unsupervised learning of finite mixture models "
//Z.Zivkovic, F.van der Heijden
//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
//
//
2011-04-17 21:14:45 +08:00
//Example usage with as cpp class
// BackgroundSubtractorMOG2 bg_model;
//For each new image the model is updates using:
// bg_model(img, fgmask);
2010-12-29 00:25:39 +08:00
//
2011-04-17 21:14:45 +08:00
//Example usage as part of the CvBGStatModel:
2010-12-29 00:25:39 +08:00
// CvBGStatModel* bg_model = cvCreateGaussianBGModel2( first_frame );
//
// //update for each frame
// cvUpdateBGStatModel( tmp_frame, bg_model );//segmentation result is in bg_model->foreground
//
// //release at the program termination
// cvReleaseBGStatModel( &bg_model );
//
//Author: Z.Zivkovic, www.zoranz.net
2011-04-17 21:14:45 +08:00
//Date: 7-April-2011, Version:1.0
2010-12-29 00:25:39 +08:00
///////////*/
2010-12-29 05:15:58 +08:00
# include "precomp.hpp"
2010-12-29 00:25:39 +08:00
2012-04-20 23:32:54 +08:00
namespace cv
{
2011-04-17 21:14:45 +08:00
/*
Interface of Gaussian mixture algorithm from :
" Improved adaptive Gausian mixture model for background subtraction "
Z . Zivkovic
International Conference Pattern Recognition , UK , August , 2004
http : //www.zoranz.net/Publications/zivkovic2004ICPR.pdf
Advantages :
- fast - number of Gausssian components is constantly adapted per pixel .
- performs also shadow detection ( see bgfg_segm_test . cpp example )
2012-04-20 23:32:54 +08:00
*/
// default parameters of gaussian background detection algorithm
static const int defaultHistory2 = 500 ; // Learning rate; alpha = 1/defaultHistory2
static const float defaultVarThreshold2 = 4.0f * 4.0f ;
static const int defaultNMixtures2 = 5 ; // maximal number of Gaussians in mixture
static const float defaultBackgroundRatio2 = 0.9f ; // threshold sum of weights for background test
static const float defaultVarThresholdGen2 = 3.0f * 3.0f ;
static const float defaultVarInit2 = 15.0f ; // initial variance for new components
static const float defaultVarMax2 = 5 * defaultVarInit2 ;
static const float defaultVarMin2 = 4.0f ;
// additional parameters
static const float defaultfCT2 = 0.05f ; // complexity reduction prior constant 0 - no reduction of number of components
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
struct GaussBGStatModel2Params
2011-04-17 21:14:45 +08:00
{
//image info
int nWidth ;
int nHeight ;
int nND ; //number of data dimensions (image channels)
bool bPostFiltering ; //defult 1 - do postfiltering - will make shadow detection results also give value 255
2010-12-29 05:15:58 +08:00
double minArea ; // for postfiltering
2011-04-17 21:14:45 +08:00
bool bInit ; //default 1, faster updates at start
2010-12-29 05:15:58 +08:00
2011-04-17 21:14:45 +08:00
/////////////////////////
//very important parameters - things you will change
////////////////////////
float fAlphaT ;
//alpha - speed of update - if the time interval you want to average over is T
//set alpha=1/T. It is also usefull at start to make T slowly increase
//from 1 until the desired T
float fTb ;
//Tb - threshold on the squared Mahalan. dist. 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 Tb=4*4=16;
/////////////////////////
//less important parameters - things you might change but be carefull
////////////////////////
float fTg ;
//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 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 fVarInit ;
float fVarMax ;
float fVarMin ;
//initial standard deviation 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
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)
2010-12-29 05:15:58 +08:00
2011-04-17 21:14:45 +08:00
//even less important parameters
int nM ; //max number of modes - const - 4 is usually enough
2010-12-29 05:15:58 +08:00
2011-04-17 21:14:45 +08:00
//shadow detection parameters
bool bShadowDetection ; //default 1 - do shadow detection
unsigned char nShadowDetection ; //do shadow detection - insert this value as the detection result
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.
2012-04-20 23:32:54 +08:00
} ;
2011-04-17 21:14:45 +08:00
2012-04-20 23:32:54 +08:00
struct GMM
2010-12-29 05:15:58 +08:00
{
2011-04-17 21:14:45 +08:00
float weight ;
float variance ;
2012-04-20 23:32:54 +08:00
} ;
2012-03-30 20:19:25 +08:00
2012-04-20 23:32:54 +08:00
// shadow detection performed per pixel
2011-04-17 21:14:45 +08:00
// should work for rgb data, could be usefull for gray scale and depth data as well
2012-04-20 23:32:54 +08:00
// See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
static CV_INLINE bool
detectShadowGMM ( const float * data , int nchannels , int nmodes ,
const GMM * gmm , const float * mean ,
float Tb , float TB , float tau )
2010-12-29 00:25:39 +08:00
{
2011-08-12 01:59:30 +08:00
float tWeight = 0 ;
2012-04-20 23:32:54 +08:00
2011-08-12 01:59:30 +08:00
// check all the components marked as background:
2012-04-20 23:32:54 +08:00
for ( int mode = 0 ; mode < nmodes ; mode + + , mean + = nchannels )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
GMM g = gmm [ mode ] ;
2011-08-12 01:59:30 +08:00
2012-04-20 23:32:54 +08:00
float numerator = 0.0f ;
float denominator = 0.0f ;
for ( int c = 0 ; c < nchannels ; c + + )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
numerator + = data [ c ] * mean [ c ] ;
denominator + = mean [ c ] * mean [ c ] ;
2011-08-12 01:59:30 +08:00
}
// no division by zero allowed
2012-04-20 23:32:54 +08:00
if ( denominator = = 0 )
return false ;
2011-08-12 01:59:30 +08:00
// if tau < a < 1 then also check the color distortion
2012-04-20 23:32:54 +08:00
if ( numerator < = denominator & & numerator > = tau * denominator )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
float a = numerator / denominator ;
float dist2a = 0.0f ;
2011-08-12 01:59:30 +08:00
2012-04-20 23:32:54 +08:00
for ( int c = 0 ; c < nchannels ; c + + )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
float dD = a * mean [ c ] - data [ c ] ;
dist2a + = dD * dD ;
2011-08-12 01:59:30 +08:00
}
2012-04-20 23:32:54 +08:00
if ( dist2a < Tb * g . variance * a * a )
return true ;
2011-08-12 01:59:30 +08:00
} ;
tWeight + = g . weight ;
2012-04-20 23:32:54 +08:00
if ( tWeight > TB )
return false ;
2011-08-12 01:59:30 +08:00
} ;
2012-04-20 23:32:54 +08:00
return false ;
2010-12-29 00:25:39 +08:00
}
2011-04-17 21:14:45 +08:00
//update GMM - the base update function performed per pixel
//
//"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
//Z.Zivkovic, F. van der Heijden
//Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
//
//The algorithm similar to the standard Stauffer&Grimson algorithm with
//additional selection of the number of the Gaussian components based on:
//
//"Recursive unsupervised learning of finite mixture models "
//Z.Zivkovic, F.van der Heijden
//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
2012-04-20 23:32:54 +08:00
struct MOG2Invoker
2010-12-29 00:25:39 +08:00
{
2012-04-20 23:32:54 +08:00
MOG2Invoker ( const Mat & _src , Mat & _dst ,
GMM * _gmm , float * _mean ,
uchar * _modesUsed ,
int _nmixtures , float _alphaT ,
float _Tb , float _TB , float _Tg ,
float _varInit , float _varMin , float _varMax ,
float _prune , float _tau , bool _detectShadows ,
uchar _shadowVal )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
src = & _src ;
dst = & _dst ;
gmm0 = _gmm ;
mean0 = _mean ;
modesUsed0 = _modesUsed ;
nmixtures = _nmixtures ;
alphaT = _alphaT ;
Tb = _Tb ;
TB = _TB ;
Tg = _Tg ;
varInit = _varInit ;
varMin = MIN ( _varMin , _varMax ) ;
varMax = MAX ( _varMin , _varMax ) ;
prune = _prune ;
tau = _tau ;
detectShadows = _detectShadows ;
shadowVal = _shadowVal ;
2011-08-12 01:59:30 +08:00
2012-04-20 23:32:54 +08:00
cvtfunc = src - > depth ( ) ! = CV_32F ? getConvertFunc ( src - > depth ( ) , CV_32F ) : 0 ;
2011-08-12 01:59:30 +08:00
}
2012-04-20 23:32:54 +08:00
void operator ( ) ( const BlockedRange & range ) const
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
int y0 = range . begin ( ) , y1 = range . end ( ) ;
int ncols = src - > cols , nchannels = src - > channels ( ) ;
AutoBuffer < float > buf ( src - > cols * nchannels ) ;
float alpha1 = 1.f - alphaT ;
float dData [ CV_CN_MAX ] ;
2011-08-12 01:59:30 +08:00
2012-04-20 23:32:54 +08:00
for ( int y = y0 ; y < y1 ; y + + )
{
const float * data = buf ;
if ( cvtfunc )
cvtfunc ( src - > ptr ( y ) , src - > step , 0 , 0 , ( uchar * ) data , 0 , Size ( ncols * nchannels , 1 ) , 0 ) ;
else
data = src - > ptr < float > ( y ) ;
2011-08-12 01:59:30 +08:00
2012-04-20 23:32:54 +08:00
float * mean = mean0 + ncols * nmixtures * nchannels * y ;
GMM * gmm = gmm0 + ncols * nmixtures * y ;
uchar * modesUsed = modesUsed0 + ncols * y ;
uchar * mask = dst - > ptr ( y ) ;
for ( int x = 0 ; x < ncols ; x + + , data + = nchannels , gmm + = nmixtures , mean + = nmixtures * nchannels )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
//calculate distances to the modes (+ sort)
//here we need to go in descending order!!!
bool background = false ; //return value -> true - the pixel classified as background
2011-08-12 01:59:30 +08:00
2012-04-20 23:32:54 +08:00
//internal:
bool fitsPDF = false ; //if it remains zero a new GMM mode will be added
int nmodes = modesUsed [ x ] , nNewModes = nmodes ; //current number of modes in GMM
float totalWeight = 0.f ;
2011-08-12 01:59:30 +08:00
2012-04-20 23:32:54 +08:00
float * mean_m = mean ;
//////
//go through all modes
for ( int mode = 0 ; mode < nmodes ; mode + + , mean_m + = nchannels )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
float weight = alpha1 * gmm [ mode ] . weight + prune ; //need only weight if fit is found
////
//fit not found yet
if ( ! fitsPDF )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
//check if it belongs to some of the remaining modes
float var = gmm [ mode ] . variance ;
//calculate difference and distance
float dist2 ;
if ( nchannels = = 3 )
{
dData [ 0 ] = mean_m [ 0 ] - data [ 0 ] ;
dData [ 1 ] = mean_m [ 1 ] - data [ 1 ] ;
dData [ 2 ] = mean_m [ 2 ] - data [ 2 ] ;
dist2 = dData [ 0 ] * dData [ 0 ] + dData [ 1 ] * dData [ 1 ] + dData [ 2 ] * dData [ 2 ] ;
}
else
{
dist2 = 0.f ;
for ( int c = 0 ; c < nchannels ; c + + )
{
dData [ c ] = mean_m [ c ] - data [ c ] ;
dist2 + = dData [ c ] * dData [ c ] ;
}
}
//background? - Tb - usually larger than Tg
if ( totalWeight < TB & & dist2 < Tb * var )
background = true ;
//check fit
if ( dist2 < Tg * var )
{
/////
//belongs to the mode
fitsPDF = true ;
//update distribution
//update weight
weight + = alphaT ;
float k = alphaT / weight ;
//update mean
for ( int c = 0 ; c < nchannels ; c + + )
mean_m [ c ] - = k * dData [ c ] ;
//update variance
float varnew = var + k * ( dist2 - var ) ;
//limit the variance
varnew = MAX ( varnew , varMin ) ;
varnew = MIN ( varnew , varMax ) ;
gmm [ mode ] . variance = varnew ;
//sort
//all other weights are at the same place and
//only the matched (iModes) is higher -> just find the new place for it
for ( int i = mode ; i > 0 ; i - - )
{
//check one up
if ( weight < gmm [ i - 1 ] . weight )
break ;
//swap one up
std : : swap ( gmm [ i ] , gmm [ i - 1 ] ) ;
for ( int c = 0 ; c < nchannels ; c + + )
std : : swap ( mean [ i * nchannels + c ] , mean [ ( i - 1 ) * nchannels + c ] ) ;
}
//belongs to the mode - bFitsPDF becomes 1
/////
}
} //!bFitsPDF)
//check prune
if ( weight < - prune )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
weight = 0.0 ;
nmodes - - ;
2011-08-12 01:59:30 +08:00
}
2012-04-20 23:32:54 +08:00
gmm [ mode ] . weight = weight ; //update weight by the calculated value
totalWeight + = weight ;
2011-08-12 01:59:30 +08:00
}
2012-04-20 23:32:54 +08:00
//go through all modes
//////
//renormalize weights
totalWeight = 1.f / totalWeight ;
for ( int mode = 0 ; mode < nmodes ; mode + + )
{
gmm [ mode ] . weight * = totalWeight ;
}
nmodes = nNewModes ;
//make new mode if needed and exit
if ( ! fitsPDF )
{
// replace the weakest or add a new one
int mode = nmodes = = nmixtures ? nmixtures - 1 : nmodes + + ;
if ( nmodes = = 1 )
gmm [ mode ] . weight = 1.f ;
else
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
gmm [ mode ] . weight = alphaT ;
// renormalize all other weights
for ( int i = 0 ; i < nmodes - 1 ; i + + )
gmm [ i ] . weight * = alpha1 ;
2011-08-12 01:59:30 +08:00
}
2012-04-20 23:32:54 +08:00
// init
for ( int c = 0 ; c < nchannels ; c + + )
mean [ mode * nchannels + c ] = data [ c ] ;
gmm [ mode ] . variance = varInit ;
//sort
//find the new place for it
for ( int i = nmodes - 1 ; i > 0 ; i - - )
2011-08-12 01:59:30 +08:00
{
2012-04-20 23:32:54 +08:00
// check one up
if ( alphaT < gmm [ i - 1 ] . weight )
break ;
// swap one up
std : : swap ( gmm [ i ] , gmm [ i - 1 ] ) ;
for ( int c = 0 ; c < nchannels ; c + + )
std : : swap ( mean [ i * nchannels + c ] , mean [ ( i - 1 ) * nchannels + c ] ) ;
2011-08-12 01:59:30 +08:00
}
2012-04-20 23:32:54 +08:00
}
//set the number of modes
modesUsed [ x ] = nmodes ;
mask [ x ] = background ? 0 :
detectShadows & & detectShadowGMM ( data , nchannels , nmodes , gmm , mean , Tb , TB , tau ) ?
shadowVal : 255 ;
2011-08-12 01:59:30 +08:00
}
}
}
2012-04-20 23:32:54 +08:00
const Mat * src ;
Mat * dst ;
GMM * gmm0 ;
float * mean0 ;
uchar * modesUsed0 ;
int nmixtures ;
float alphaT , Tb , TB , Tg ;
float varInit , varMin , varMax , prune , tau ;
bool detectShadows ;
uchar shadowVal ;
BinaryFunc cvtfunc ;
} ;
2011-04-17 21:14:45 +08:00
2010-12-29 05:15:58 +08:00
BackgroundSubtractorMOG2 : : BackgroundSubtractorMOG2 ( )
2010-12-29 00:25:39 +08:00
{
2011-04-17 21:14:45 +08:00
frameSize = Size ( 0 , 0 ) ;
frameType = 0 ;
nframes = 0 ;
history = defaultHistory2 ;
2011-08-12 01:59:30 +08:00
varThreshold = defaultVarThreshold2 ;
bShadowDetection = 1 ;
nmixtures = defaultNMixtures2 ;
backgroundRatio = defaultBackgroundRatio2 ;
fVarInit = defaultVarInit2 ;
fVarMax = defaultVarMax2 ;
fVarMin = defaultVarMin2 ;
varThresholdGen = defaultVarThresholdGen2 ;
fCT = defaultfCT2 ;
nShadowDetection = defaultnShadowDetection2 ;
fTau = defaultfTau ;
2011-04-17 21:14:45 +08:00
}
2010-12-29 00:25:39 +08:00
2011-04-17 21:14:45 +08:00
BackgroundSubtractorMOG2 : : BackgroundSubtractorMOG2 ( int _history , float _varThreshold , bool _bShadowDetection )
2010-12-29 05:15:58 +08:00
{
2011-04-17 21:14:45 +08:00
frameSize = Size ( 0 , 0 ) ;
frameType = 0 ;
2010-12-29 05:15:58 +08:00
2011-04-17 21:14:45 +08:00
nframes = 0 ;
history = _history > 0 ? _history : defaultHistory2 ;
2011-08-12 01:59:30 +08:00
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 ;
2011-04-17 21:14:45 +08:00
}
2010-12-29 05:15:58 +08:00
BackgroundSubtractorMOG2 : : ~ BackgroundSubtractorMOG2 ( )
2010-12-29 00:25:39 +08:00
{
2010-12-29 05:15:58 +08:00
}
2010-12-29 00:25:39 +08:00
2011-04-17 21:14:45 +08:00
void BackgroundSubtractorMOG2 : : initialize ( Size _frameSize , int _frameType )
2010-12-29 05:15:58 +08:00
{
2011-04-17 21:14:45 +08:00
frameSize = _frameSize ;
frameType = _frameType ;
nframes = 0 ;
2010-12-29 00:25:39 +08:00
2011-04-17 21:14:45 +08:00
int nchannels = CV_MAT_CN ( frameType ) ;
2012-04-20 23:32:54 +08:00
CV_Assert ( nchannels < = CV_CN_MAX ) ;
2010-12-29 05:15:58 +08:00
2011-04-17 21:14:45 +08:00
// for each gaussian mixture of each pixel bg model we store ...
// the mixture weight (w),
// the mean (nchannels values) and
// the covariance
2012-04-20 23:32:54 +08:00
bgmodel . create ( 1 , frameSize . height * frameSize . width * nmixtures * ( 2 + nchannels ) , CV_32F ) ;
2011-08-12 01:59:30 +08:00
//make the array for keeping track of the used modes per pixel - all zeros at start
bgmodelUsedModes . create ( frameSize , CV_8U ) ;
2011-04-17 21:14:45 +08:00
bgmodelUsedModes = Scalar : : all ( 0 ) ;
}
2011-06-06 22:51:27 +08:00
void BackgroundSubtractorMOG2 : : operator ( ) ( InputArray _image , OutputArray _fgmask , double learningRate )
2011-04-17 21:14:45 +08:00
{
Mat image = _image . getMat ( ) ;
bool needToInitialize = nframes = = 0 | | learningRate > = 1 | | image . size ( ) ! = frameSize | | image . type ( ) ! = frameType ;
2010-12-29 05:15:58 +08:00
2011-04-17 21:14:45 +08:00
if ( needToInitialize )
initialize ( image . size ( ) , image . type ( ) ) ;
2010-12-29 05:15:58 +08:00
2011-04-17 21:14:45 +08:00
_fgmask . create ( image . size ( ) , CV_8U ) ;
Mat fgmask = _fgmask . getMat ( ) ;
2010-12-29 00:25:39 +08:00
2011-04-17 21:14:45 +08:00
+ + nframes ;
learningRate = learningRate > = 0 & & nframes > 1 ? learningRate : 1. / min ( 2 * nframes , history ) ;
CV_Assert ( learningRate > = 0 ) ;
2010-12-29 05:15:58 +08:00
2012-04-20 23:32:54 +08:00
if ( learningRate > 0 )
{
parallel_for ( BlockedRange ( 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 , fCT , fTau ,
bShadowDetection , nShadowDetection ) ) ;
}
2010-12-29 05:15:58 +08:00
}
2011-06-03 22:10:12 +08:00
void BackgroundSubtractorMOG2 : : getBackgroundImage ( OutputArray backgroundImage ) const
{
2012-04-20 23:32:54 +08:00
int nchannels = CV_MAT_CN ( frameType ) ;
CV_Assert ( nchannels = = 3 ) ;
2011-06-03 22:10:12 +08:00
Mat meanBackground ( frameSize , CV_8UC3 , Scalar : : all ( 0 ) ) ;
int firstGaussianIdx = 0 ;
2012-04-20 23:32:54 +08:00
const GMM * gmm = ( GMM * ) bgmodel . data ;
const Vec3f * mean = reinterpret_cast < const Vec3f * > ( gmm + frameSize . width * frameSize . height * nmixtures ) ;
2011-06-03 22:10:12 +08:00
for ( int row = 0 ; row < meanBackground . rows ; row + + )
{
for ( int col = 0 ; col < meanBackground . cols ; col + + )
{
2012-04-20 23:32:54 +08:00
int nmodes = bgmodelUsedModes . at < uchar > ( row , col ) ;
Vec3f meanVal ;
float totalWeight = 0.f ;
for ( int gaussianIdx = firstGaussianIdx ; gaussianIdx < firstGaussianIdx + nmodes ; gaussianIdx + + )
2011-06-03 22:10:12 +08:00
{
2012-04-20 23:32:54 +08:00
GMM gaussian = gmm [ gaussianIdx ] ;
meanVal + = gaussian . weight * mean [ gaussianIdx ] ;
2011-06-03 22:10:12 +08:00
totalWeight + = gaussian . weight ;
if ( totalWeight > backgroundRatio )
break ;
}
2012-04-20 23:32:54 +08:00
meanVal * = ( 1.f / totalWeight ) ;
meanBackground . at < Vec3b > ( row , col ) = Vec3b ( meanVal ) ;
2011-06-03 22:10:12 +08:00
firstGaussianIdx + = nmixtures ;
}
}
switch ( CV_MAT_CN ( frameType ) )
{
2012-04-20 23:32:54 +08:00
case 1 :
{
vector < Mat > channels ;
split ( meanBackground , channels ) ;
channels [ 0 ] . copyTo ( backgroundImage ) ;
break ;
}
2011-06-03 22:10:12 +08:00
2012-04-20 23:32:54 +08:00
case 3 :
{
meanBackground . copyTo ( backgroundImage ) ;
break ;
}
2011-06-03 22:10:12 +08:00
2012-04-20 23:32:54 +08:00
default :
CV_Error ( CV_StsUnsupportedFormat , " " ) ;
2011-06-03 22:10:12 +08:00
}
}
2010-12-29 00:25:39 +08:00
}
/* End of file. */