1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
12 // Copyright (C) 2000, Intel Corporation, all rights reserved.
13 // Third party copyrights are property of their respective owners.
15 // Redistribution and use in source and binary forms, with or without modification,
16 // are permitted provided that the following conditions are met:
18 // * Redistribution's of source code must retain the above copyright notice,
19 // this list of conditions and the following disclaimer.
21 // * Redistribution's in binary form must reproduce the above copyright notice,
22 // this list of conditions and the following disclaimer in the documentation
23 // and/or other materials provided with the distribution.
25 // * The name of Intel Corporation may not be used to endorse or promote products
26 // derived from this software without specific prior written permission.
28 // This software is provided by the copyright holders and contributors "as is" and
29 // any express or implied warranties, including, but not limited to, the implied
30 // warranties of merchantability and fitness for a particular purpose are disclaimed.
31 // In no event shall the Intel Corporation or contributors be liable for any direct,
32 // indirect, incidental, special, exemplary, or consequential damages
33 // (including, but not limited to, procurement of substitute goods or services;
34 // loss of use, data, or profits; or business interruption) however caused
35 // and on any theory of liability, whether in contract, strict liability,
36 // or tort (including negligence or otherwise) arising in any way out of
37 // the use of this software, even if advised of the possibility of such damage.
41 #include "precomp.hpp"
43 /////////////////////////////////////// MOG model //////////////////////////////////////////
46 icvReleaseGaussianBGModel( CvGaussBGModel** bg_model )
49 CV_Error( CV_StsNullPtr, "" );
53 delete (cv::Ptr<cv::BackgroundSubtractor>*)((*bg_model)->mog);
54 cvReleaseImage( &(*bg_model)->background );
55 cvReleaseImage( &(*bg_model)->foreground );
56 memset( *bg_model, 0, sizeof(**bg_model) );
64 icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model, double learningRate )
66 cv::Mat image = cv::cvarrToMat(curr_frame), mask = cv::cvarrToMat(bg_model->foreground);
68 cv::Ptr<cv::BackgroundSubtractor>* mog = (cv::Ptr<cv::BackgroundSubtractor>*)(bg_model->mog);
71 (*mog)->apply(image, mask, learningRate);
72 bg_model->countFrames++;
77 CV_IMPL CvBGStatModel*
78 cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters )
80 CvGaussBGStatModelParams params;
82 CV_Assert( CV_IS_IMAGE(first_frame) );
85 if( parameters == NULL )
86 { // These constants are defined in cvaux/include/cvaux.h
87 params.win_size = CV_BGFG_MOG_WINDOW_SIZE;
88 params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD;
90 params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD;
91 params.weight_init = CV_BGFG_MOG_WEIGHT_INIT;
93 params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT;
94 params.minArea = CV_BGFG_MOG_MINAREA;
95 params.n_gauss = CV_BGFG_MOG_NGAUSSIANS;
100 CvGaussBGModel* bg_model = new CvGaussBGModel;
101 memset( bg_model, 0, sizeof(*bg_model) );
102 bg_model->type = CV_BG_MODEL_MOG;
103 bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel;
104 bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel;
106 bg_model->params = params;
108 cv::Ptr<cv::BackgroundSubtractor> mog = cv::createBackgroundSubtractorMOG(params.win_size, params.n_gauss,
109 params.bg_threshold);
110 cv::Ptr<cv::BackgroundSubtractor>* pmog = new cv::Ptr<cv::BackgroundSubtractor>;
112 bg_model->mog = pmog;
114 CvSize sz = cvGetSize(first_frame);
115 bg_model->background = cvCreateImage(sz, IPL_DEPTH_8U, first_frame->nChannels);
116 bg_model->foreground = cvCreateImage(sz, IPL_DEPTH_8U, 1);
118 bg_model->countFrames = 0;
120 icvUpdateGaussianBGModel( first_frame, bg_model, 1 );
122 return (CvBGStatModel*)bg_model;
126 //////////////////////////////////////////// MOG2 //////////////////////////////////////////////
128 /*M///////////////////////////////////////////////////////////////////////////////////////
130 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
132 // By downloading, copying, installing or using the software you agree to this license.
133 // If you do not agree to this license, do not download, install,
134 // copy or use the software.
137 // Intel License Agreement
139 // Copyright (C) 2000, Intel Corporation, all rights reserved.
140 // Third party copyrights are property of their respective owners.
142 // Redistribution and use in source and binary forms, with or without modification,
143 // are permitted provided that the following conditions are met:
145 // * Redistribution's of source code must retain the above copyright notice,
146 // this list of conditions and the following disclaimer.
148 // * Redistribution's in binary form must reproduce the above copyright notice,
149 // this list of conditions and the following disclaimer in the documentation
150 // and/or other materials provided with the distribution.
152 // * The name of Intel Corporation may not be used to endorse or promote products
153 // derived from this software without specific prior written permission.
155 // This software is provided by the copyright holders and contributors "as is" and
156 // any express or implied warranties, including, but not limited to, the implied
157 // warranties of merchantability and fitness for a particular purpose are disclaimed.
158 // In no event shall the Intel Corporation or contributors be liable for any direct,
159 // indirect, incidental, special, exemplary, or consequential damages
160 // (including, but not limited to, procurement of substitute goods or services;
161 // loss of use, data, or profits; or business interruption) however caused
162 // and on any theory of liability, whether in contract, strict liability,
163 // or tort (including negligence or otherwise) arising in any way out of
164 // the use of this software, even if advised of the possibility of such damage.
168 /*//Implementation of the Gaussian mixture model background subtraction from:
170 //"Improved adaptive Gausian mixture model for background subtraction"
172 //International Conference Pattern Recognition, UK, August, 2004
173 //http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
174 //The code is very fast and performs also shadow detection.
175 //Number of Gausssian components is adapted per pixel.
179 //"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
180 //Z.Zivkovic, F. van der Heijden
181 //Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
183 //The algorithm similar to the standard Stauffer&Grimson algorithm with
184 //additional selection of the number of the Gaussian components based on:
186 //"Recursive unsupervised learning of finite mixture models "
187 //Z.Zivkovic, F.van der Heijden
188 //IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
189 //http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
192 //Example usage with as cpp class
193 // BackgroundSubtractorMOG2 bg_model;
194 //For each new image the model is updates using:
195 // bg_model(img, fgmask);
197 //Example usage as part of the CvBGStatModel:
198 // CvBGStatModel* bg_model = cvCreateGaussianBGModel2( first_frame );
200 // //update for each frame
201 // cvUpdateBGStatModel( tmp_frame, bg_model );//segmentation result is in bg_model->foreground
203 // //release at the program termination
204 // cvReleaseBGStatModel( &bg_model );
206 //Author: Z.Zivkovic, www.zoranz.net
207 //Date: 7-April-2011, Version:1.0
210 #include "precomp.hpp"
214 Interface of Gaussian mixture algorithm from:
216 "Improved adaptive Gausian mixture model for background subtraction"
218 International Conference Pattern Recognition, UK, August, 2004
219 http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
222 -fast - number of Gausssian components is constantly adapted per pixel.
223 -performs also shadow detection (see bgfg_segm_test.cpp example)
228 #define CV_BG_MODEL_MOG2 3 /* "Mixture of Gaussians 2". */
231 /* default parameters of gaussian background detection algorithm */
232 #define CV_BGFG_MOG2_STD_THRESHOLD 4.0f /* lambda=2.5 is 99% */
233 #define CV_BGFG_MOG2_WINDOW_SIZE 500 /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */
234 #define CV_BGFG_MOG2_BACKGROUND_THRESHOLD 0.9f /* threshold sum of weights for background test */
235 #define CV_BGFG_MOG2_STD_THRESHOLD_GENERATE 3.0f /* lambda=2.5 is 99% */
236 #define CV_BGFG_MOG2_NGAUSSIANS 5 /* = K = number of Gaussians in mixture */
237 #define CV_BGFG_MOG2_VAR_INIT 15.0f /* initial variance for new components*/
238 #define CV_BGFG_MOG2_VAR_MIN 4.0f
239 #define CV_BGFG_MOG2_VAR_MAX 5*CV_BGFG_MOG2_VAR_INIT
240 #define CV_BGFG_MOG2_MINAREA 15.0f /* for postfiltering */
242 /* additional parameters */
243 #define CV_BGFG_MOG2_CT 0.05f /* complexity reduction prior constant 0 - no reduction of number of components*/
244 #define CV_BGFG_MOG2_SHADOW_VALUE 127 /* value to use in the segmentation mask for shadows, sot 0 not to do shadow detection*/
245 #define CV_BGFG_MOG2_SHADOW_TAU 0.5f /* Tau - shadow threshold, see the paper for explanation*/
247 typedef struct CvGaussBGStatModel2Params
252 int nND;//number of data dimensions (image channels)
254 bool bPostFiltering;//defult 1 - do postfiltering - will make shadow detection results also give value 255
255 double minArea; // for postfiltering
257 bool bInit;//default 1, faster updates at start
259 /////////////////////////
260 //very important parameters - things you will change
261 ////////////////////////
263 //alpha - speed of update - if the time interval you want to average over is T
264 //set alpha=1/T. It is also usefull at start to make T slowly increase
265 //from 1 until the desired T
267 //Tb - threshold on the squared Mahalan. dist. to decide if it is well described
268 //by the background model or not. Related to Cthr from the paper.
269 //This does not influence the update of the background. A typical value could be 4 sigma
270 //and that is Tb=4*4=16;
272 /////////////////////////
273 //less important parameters - things you might change but be carefull
274 ////////////////////////
276 //Tg - threshold on the squared Mahalan. dist. to decide
277 //when a sample is close to the existing components. If it is not close
278 //to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
279 //Smaller Tg leads to more generated components and higher Tg might make
280 //lead to small number of components but they can grow too large
281 float fTB;//1-cf from the paper
282 //TB - threshold when the component becomes significant enough to be included into
283 //the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
284 //For alpha=0.001 it means that the mode should exist for approximately 105 frames before
285 //it is considered foreground
289 //initial standard deviation for the newly generated components.
290 //It will will influence the speed of adaptation. A good guess should be made.
291 //A simple way is to estimate the typical standard deviation from the images.
292 //I used here 10 as a reasonable value
293 float fCT;//CT - complexity reduction prior
294 //this is related to the number of samples needed to accept that a component
295 //actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
296 //the standard Stauffer&Grimson algorithm (maybe not exact but very similar)
298 //even less important parameters
299 int nM;//max number of modes - const - 4 is usually enough
301 //shadow detection parameters
302 bool bShadowDetection;//default 1 - do shadow detection
303 unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result
305 // Tau - shadow threshold. The shadow is detected if the pixel is darker
306 //version of the background. Tau is a threshold on how much darker the shadow can be.
307 //Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
308 //See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
309 } CvGaussBGStatModel2Params;
311 #define CV_BGFG_MOG2_NDMAX 3
313 typedef struct CvPBGMMGaussian
316 float mean[CV_BGFG_MOG2_NDMAX];
320 typedef struct CvGaussBGStatModel2Data
322 CvPBGMMGaussian* rGMM; //array for the mixture of Gaussians
323 unsigned char* rnUsedModes;//number of Gaussian components per pixel (maximum 255)
324 } CvGaussBGStatModel2Data;
328 //only foreground image is updated
329 //no filtering included
330 typedef struct CvGaussBGModel2
332 CV_BG_STAT_MODEL_FIELDS();
333 CvGaussBGStatModel2Params params;
334 CvGaussBGStatModel2Data data;
338 CVAPI(CvBGStatModel*) cvCreateGaussianBGModel2( IplImage* first_frame,
339 CvGaussBGStatModel2Params* params CV_DEFAULT(NULL) );
342 //shadow detection performed per pixel
343 // should work for rgb data, could be usefull for gray scale and depth data as well
344 // See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
345 CV_INLINE int _icvRemoveShadowGMM(float* data, int nD,
346 unsigned char nModes,
347 CvPBGMMGaussian* pGMM,
353 float numerator, denominator;
354 // check all the components marked as background:
355 for (int iModes=0;iModes<nModes;iModes++)
358 CvPBGMMGaussian g=pGMM[iModes];
362 for (int iD=0;iD<nD;iD++)
364 numerator += data[iD] * g.mean[iD];
365 denominator += g.mean[iD]* g.mean[iD];
368 // no division by zero allowed
369 if (denominator == 0)
373 float a = numerator / denominator;
375 // if tau < a < 1 then also check the color distortion
376 if ((a <= 1) && (a >= m_fTau))
381 for (int iD=0;iD<nD;iD++)
383 float dD= a*g.mean[iD] - data[iD];
387 if (dist2a<m_fTb*g.variance*a*a)
402 //update GMM - the base update function performed per pixel
404 //"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
405 //Z.Zivkovic, F. van der Heijden
406 //Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
408 //The algorithm similar to the standard Stauffer&Grimson algorithm with
409 //additional selection of the number of the Gaussian components based on:
411 //"Recursive unsupervised learning of finite mixture models "
412 //Z.Zivkovic, F.van der Heijden
413 //IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
414 //http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
416 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
417 # pragma GCC diagnostic push
418 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
421 CV_INLINE int _icvUpdateGMM(float* data, int nD,
422 unsigned char* pModesUsed,
423 CvPBGMMGaussian* pGMM,
434 //calculate distances to the modes (+ sort)
435 //here we need to go in descending order!!!
436 bool bBackground=0;//return value -> true - the pixel classified as background
439 bool bFitsPDF=0;//if it remains zero a new GMM mode will be added
440 float m_fOneMinAlpha=1-m_fAlphaT;
441 unsigned char nModes=*pModesUsed;//current number of modes in GMM
442 float totalWeight=0.0f;
445 //go through all modes
447 CvPBGMMGaussian* pGauss=pGMM;
448 for (;iMode<nModes;iMode++,pGauss++)
450 float weight = pGauss->weight;//need only weight if fit is found
451 weight=m_fOneMinAlpha*weight+m_fPrune;
457 //check if it belongs to some of the remaining modes
458 float var=pGauss->variance;
460 //calculate difference and distance
462 #if (CV_BGFG_MOG2_NDMAX==1)
463 float dData=pGauss->mean[0]-data[0];
466 float dData[CV_BGFG_MOG2_NDMAX];
468 for (int iD=0;iD<nD;iD++)
470 dData[iD]=pGauss->mean[iD]-data[iD];
471 dist2+=dData[iD]*dData[iD];
474 //background? - m_fTb - usually larger than m_fTg
475 if ((totalWeight<m_fTB)&&(dist2<m_fTb*var))
482 //belongs to the mode - bFitsPDF becomes 1
485 //update distribution
490 float k = m_fAlphaT/weight;
493 #if (CV_BGFG_MOG2_NDMAX==1)
494 pGauss->mean[0]-=k*dData;
496 for (int iD=0;iD<nD;iD++)
498 pGauss->mean[iD]-=k*dData[iD];
503 float varnew = var + k*(dist2-var);
505 pGauss->variance = MIN(m_fVarMax,MAX(varnew,m_fVarMin));
508 //all other weights are at the same place and
509 //only the matched (iModes) is higher -> just find the new place for it
510 for (int iLocal = iMode;iLocal>0;iLocal--)
513 if (weight < (pGMM[iLocal-1].weight))
520 CvPBGMMGaussian temp = pGMM[iLocal];
521 pGMM[iLocal] = pGMM[iLocal-1];
522 pGMM[iLocal-1] = temp;
526 //belongs to the mode - bFitsPDF becomes 1
532 if (weight<-m_fPrune)
538 pGauss->weight=weight;//update weight by the calculated value
541 //go through all modes
544 //renormalize weights
545 for (iMode = 0; iMode < nModes; iMode++)
547 pGMM[iMode].weight = pGMM[iMode].weight/totalWeight;
550 //make new mode if needed and exit
555 //replace the weakest
571 pGauss->weight=m_fAlphaT;
573 //renormalize all weights
574 for (iMode = 0; iMode < nModes-1; iMode++)
576 pGMM[iMode].weight *=m_fOneMinAlpha;
581 memcpy(pGauss->mean,data,nD*sizeof(float));
582 pGauss->variance=m_fVarInit;
585 //find the new place for it
586 for (int iLocal = nModes-1;iLocal>0;iLocal--)
589 if (m_fAlphaT < (pGMM[iLocal-1].weight))
596 CvPBGMMGaussian temp = pGMM[iLocal];
597 pGMM[iLocal] = pGMM[iLocal-1];
598 pGMM[iLocal-1] = temp;
603 //set the number of modes
609 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
610 # pragma GCC diagnostic pop
613 // a bit more efficient implementation for common case of 3 channel (rgb) images
614 CV_INLINE int _icvUpdateGMM_C3(float r,float g, float b,
615 unsigned char* pModesUsed,
616 CvPBGMMGaussian* pGMM,
627 //calculate distances to the modes (+ sort)
628 //here we need to go in descending order!!!
629 bool bBackground=0;//return value -> true - the pixel classified as background
632 bool bFitsPDF=0;//if it remains zero a new GMM mode will be added
633 float m_fOneMinAlpha=1-m_fAlphaT;
634 unsigned char nModes=*pModesUsed;//current number of modes in GMM
635 float totalWeight=0.0f;
638 //go through all modes
640 CvPBGMMGaussian* pGauss=pGMM;
641 for (;iMode<nModes;iMode++,pGauss++)
643 float weight = pGauss->weight;//need only weight if fit is found
644 weight=m_fOneMinAlpha*weight+m_fPrune;
650 //check if it belongs to some of the remaining modes
651 float var=pGauss->variance;
653 //calculate difference and distance
654 float muR = pGauss->mean[0];
655 float muG = pGauss->mean[1];
656 float muB = pGauss->mean[2];
662 float dist2=(dR*dR+dG*dG+dB*dB);
664 //background? - m_fTb - usually larger than m_fTg
665 if ((totalWeight<m_fTB)&&(dist2<m_fTb*var))
672 //belongs to the mode - bFitsPDF becomes 1
675 //update distribution
680 float k = m_fAlphaT/weight;
683 pGauss->mean[0] = muR - k*(dR);
684 pGauss->mean[1] = muG - k*(dG);
685 pGauss->mean[2] = muB - k*(dB);
688 float varnew = var + k*(dist2-var);
690 pGauss->variance = MIN(m_fVarMax,MAX(varnew,m_fVarMin));
693 //all other weights are at the same place and
694 //only the matched (iModes) is higher -> just find the new place for it
695 for (int iLocal = iMode;iLocal>0;iLocal--)
698 if (weight < (pGMM[iLocal-1].weight))
705 CvPBGMMGaussian temp = pGMM[iLocal];
706 pGMM[iLocal] = pGMM[iLocal-1];
707 pGMM[iLocal-1] = temp;
711 //belongs to the mode - bFitsPDF becomes 1
718 if (weight<-m_fPrune)
724 pGauss->weight=weight;
727 //go through all modes
730 //renormalize weights
731 for (iMode = 0; iMode < nModes; iMode++)
733 pGMM[iMode].weight = pGMM[iMode].weight/totalWeight;
736 //make new mode if needed and exit
741 //replace the weakest
757 pGauss->weight=m_fAlphaT;
759 //renormalize all weights
760 for (iMode = 0; iMode < nModes-1; iMode++)
762 pGMM[iMode].weight *=m_fOneMinAlpha;
771 pGauss->variance=m_fVarInit;
774 //find the new place for it
775 for (int iLocal = nModes-1;iLocal>0;iLocal--)
778 if (m_fAlphaT < (pGMM[iLocal-1].weight))
785 CvPBGMMGaussian temp = pGMM[iLocal];
786 pGMM[iLocal] = pGMM[iLocal-1];
787 pGMM[iLocal-1] = temp;
792 //set the number of modes
798 //the main function to update the background model
799 static void icvUpdatePixelBackgroundGMM2( const CvArr* srcarr, CvArr* dstarr ,
800 CvPBGMMGaussian *pGMM,
801 unsigned char *pUsedModes,
802 //CvGaussBGStatModel2Params* pGMMPar,
812 bool bShadowDetection,
813 unsigned char nShadowDetection,
816 CvMat sstub, *src = cvGetMat(srcarr, &sstub);
817 CvMat dstub, *dst = cvGetMat(dstarr, &dstub);
818 CvSize size = cvGetMatSize(src);
819 int nD=CV_MAT_CN(src->type);
821 //reshape if possible
822 if( CV_IS_MAT_CONT(src->type & dst->type) )
824 size.width *= size.height;
829 float data[CV_BGFG_MOG2_NDMAX];
830 float prune=-alpha*fCT;
836 switch (CV_MAT_DEPTH(src->type))
839 for( y = 0; y < size.height; y++ )
841 uchar* sptr = src->data.ptr + src->step*y;
842 uchar* pDataOutput = dst->data.ptr + dst->step*y;
843 for( x = 0; x < size.width; x++,
844 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
847 for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
849 int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
850 //detect shadows in the foreground
851 if (bShadowDetection)
852 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
854 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
859 for( y = 0; y < size.height; y++ )
861 short* sptr = src->data.s + src->step*y;
862 uchar* pDataOutput = dst->data.ptr + dst->step*y;
863 for( x = 0; x < size.width; x++,
864 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
867 for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
869 int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
870 //detect shadows in the foreground
871 if (bShadowDetection)
872 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
874 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
879 for( y = 0; y < size.height; y++ )
881 unsigned short* sptr = (unsigned short*) (src->data.s + src->step*y);
882 uchar* pDataOutput = dst->data.ptr + dst->step*y;
883 for( x = 0; x < size.width; x++,
884 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
887 for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
889 int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
890 //detect shadows in the foreground
891 if (bShadowDetection)
892 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
894 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
899 for( y = 0; y < size.height; y++ )
901 int* sptr = src->data.i + src->step*y;
902 uchar* pDataOutput = dst->data.ptr + dst->step*y;
903 for( x = 0; x < size.width; x++,
904 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
907 for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
909 int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
910 //detect shadows in the foreground
911 if (bShadowDetection)
912 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
914 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
919 for( y = 0; y < size.height; y++ )
921 float* sptr = src->data.fl + src->step*y;
922 uchar* pDataOutput = dst->data.ptr + dst->step*y;
923 for( x = 0; x < size.width; x++,
924 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
927 int result = _icvUpdateGMM(sptr,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
928 //detect shadows in the foreground
929 if (bShadowDetection)
930 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
932 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
937 for( y = 0; y < size.height; y++ )
939 double* sptr = src->data.db + src->step*y;
940 uchar* pDataOutput = dst->data.ptr + dst->step*y;
941 for( x = 0; x < size.width; x++,
942 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
945 for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
947 int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
948 //detect shadows in the foreground
949 if (bShadowDetection)
950 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
952 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
957 }else ///if (nD==3) - a bit faster
959 switch (CV_MAT_DEPTH(src->type))
962 for( y = 0; y < size.height; y++ )
964 uchar* sptr = src->data.ptr + src->step*y;
965 uchar* pDataOutput = dst->data.ptr + dst->step*y;
966 for( x = 0; x < size.width; x++,
967 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
970 data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
972 int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
973 //detect shadows in the foreground
974 if (bShadowDetection)
975 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
977 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
982 for( y = 0; y < size.height; y++ )
984 short* sptr = src->data.s + src->step*y;
985 uchar* pDataOutput = dst->data.ptr + dst->step*y;
986 for( x = 0; x < size.width; x++,
987 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
990 data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
992 int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
993 //detect shadows in the foreground
994 if (bShadowDetection)
995 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
997 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
1002 for( y = 0; y < size.height; y++ )
1004 unsigned short* sptr = (unsigned short*) src->data.s + src->step*y;
1005 uchar* pDataOutput = dst->data.ptr + dst->step*y;
1006 for( x = 0; x < size.width; x++,
1007 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
1010 data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
1012 int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
1013 //detect shadows in the foreground
1014 if (bShadowDetection)
1015 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
1017 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
1022 for( y = 0; y < size.height; y++ )
1024 int* sptr = src->data.i + src->step*y;
1025 uchar* pDataOutput = dst->data.ptr + dst->step*y;
1026 for( x = 0; x < size.width; x++,
1027 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
1030 data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
1032 int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
1033 //detect shadows in the foreground
1034 if (bShadowDetection)
1035 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
1037 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
1042 for( y = 0; y < size.height; y++ )
1044 float* sptr = src->data.fl + src->step*y;
1045 uchar* pDataOutput = dst->data.ptr + dst->step*y;
1046 for( x = 0; x < size.width; x++,
1047 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
1050 int result = _icvUpdateGMM_C3(sptr[0],sptr[1],sptr[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
1051 //detect shadows in the foreground
1052 if (bShadowDetection)
1053 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
1055 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
1060 for( y = 0; y < size.height; y++ )
1062 double* sptr = src->data.db + src->step*y;
1063 uchar* pDataOutput = dst->data.ptr + dst->step*y;
1064 for( x = 0; x < size.width; x++,
1065 pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
1068 data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
1070 int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
1071 //detect shadows in the foreground
1072 if (bShadowDetection)
1073 if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
1075 (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
1080 }//a bit faster for nD=3;
1084 //only foreground image is updated
1085 //no filtering included
1086 typedef struct CvGaussBGModel2
1088 CV_BG_STAT_MODEL_FIELDS();
1089 CvGaussBGStatModel2Params params;
1090 CvGaussBGStatModel2Data data;
1094 CVAPI(CvBGStatModel*) cvCreateGaussianBGModel2( IplImage* first_frame,
1095 CvGaussBGStatModel2Params* params CV_DEFAULT(NULL) );
1097 //////////////////////////////////////////////
1098 //implementation as part of the CvBGStatModel
1099 static void CV_CDECL icvReleaseGaussianBGModel2( CvGaussBGModel2** bg_model );
1100 static int CV_CDECL icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model );
1103 CV_IMPL CvBGStatModel*
1104 cvCreateGaussianBGModel2( IplImage* first_frame, CvGaussBGStatModel2Params* parameters )
1106 CvGaussBGModel2* bg_model = 0;
1109 CV_FUNCNAME( "cvCreateGaussianBGModel2" );
1113 CvGaussBGStatModel2Params params;
1115 if( !CV_IS_IMAGE(first_frame) )
1116 CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
1118 if( first_frame->nChannels>CV_BGFG_MOG2_NDMAX )
1119 CV_ERROR( CV_StsBadArg, "Maxumum number of channels in the image is excedded (change CV_BGFG_MOG2_MAXBANDS constant)!" );
1122 CV_CALL( bg_model = (CvGaussBGModel2*)cvAlloc( sizeof(*bg_model) ));
1123 memset( bg_model, 0, sizeof(*bg_model) );
1124 bg_model->type = CV_BG_MODEL_MOG2;
1125 bg_model->release = (CvReleaseBGStatModel) icvReleaseGaussianBGModel2;
1126 bg_model->update = (CvUpdateBGStatModel) icvUpdateGaussianBGModel2;
1129 if( parameters == NULL )
1131 memset(¶ms, 0, sizeof(params));
1133 // These constants are defined in cvaux/include/cvaux.h
1134 params.bShadowDetection = 1;
1135 params.bPostFiltering=0;
1136 params.minArea=CV_BGFG_MOG2_MINAREA;
1139 // K - max number of Gaussians per pixel
1140 params.nM = CV_BGFG_MOG2_NGAUSSIANS;//4;
1141 // Tb - the threshold - n var
1143 params.fTb = CV_BGFG_MOG2_STD_THRESHOLD*CV_BGFG_MOG2_STD_THRESHOLD;
1144 // Tbf - the threshold
1145 //pGMM->fTB = 0.9f;//1-cf from the paper
1146 params.fTB = CV_BGFG_MOG2_BACKGROUND_THRESHOLD;
1147 // Tgenerate - the threshold
1148 params.fTg = CV_BGFG_MOG2_STD_THRESHOLD_GENERATE*CV_BGFG_MOG2_STD_THRESHOLD_GENERATE;//update the mode or generate new
1149 //pGMM->fSigma= 11.0f;//sigma for the new mode
1150 params.fVarInit = CV_BGFG_MOG2_VAR_INIT;
1151 params.fVarMax = CV_BGFG_MOG2_VAR_MAX;
1152 params.fVarMin = CV_BGFG_MOG2_VAR_MIN;
1153 // alpha - the learning factor
1154 params.fAlphaT = 1.0f/CV_BGFG_MOG2_WINDOW_SIZE;//0.003f;
1155 // complexity reduction prior constant
1156 params.fCT = CV_BGFG_MOG2_CT;//0.05f;
1160 params.nShadowDetection = (unsigned char)CV_BGFG_MOG2_SHADOW_VALUE;//value 0 to turn off
1161 params.fTau = CV_BGFG_MOG2_SHADOW_TAU;//0.5f;// Tau - shadow threshold
1165 params = *parameters;
1168 bg_model->params = params;
1171 w = first_frame->width;
1172 h = first_frame->height;
1174 bg_model->params.nWidth = w;
1175 bg_model->params.nHeight = h;
1177 bg_model->params.nND = first_frame->nChannels;
1182 //GMM for each pixel
1183 bg_model->data.rGMM = (CvPBGMMGaussian*) malloc(w*h * params.nM * sizeof(CvPBGMMGaussian));
1184 //used modes per pixel
1185 bg_model->data.rnUsedModes = (unsigned char* ) malloc(w*h);
1186 memset(bg_model->data.rnUsedModes,0,w*h);//no modes used
1189 CV_CALL( bg_model->background = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, first_frame->nChannels));
1190 CV_CALL( bg_model->foreground = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1));
1192 //for eventual filtering
1193 CV_CALL( bg_model->storage = cvCreateMemStorage());
1195 bg_model->countFrames = 0;
1199 if( cvGetErrStatus() < 0 )
1201 CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model;
1203 if( bg_model && bg_model->release )
1204 bg_model->release( &base_ptr );
1206 cvFree( &bg_model );
1210 return (CvBGStatModel*)bg_model;
1214 static void CV_CDECL
1215 icvReleaseGaussianBGModel2( CvGaussBGModel2** _bg_model )
1217 CV_FUNCNAME( "icvReleaseGaussianBGModel2" );
1222 CV_ERROR( CV_StsNullPtr, "" );
1226 CvGaussBGModel2* bg_model = *_bg_model;
1228 free (bg_model->data.rGMM);
1229 free (bg_model->data.rnUsedModes);
1231 cvReleaseImage( &bg_model->background );
1232 cvReleaseImage( &bg_model->foreground );
1233 cvReleaseMemStorage(&bg_model->storage);
1234 memset( bg_model, 0, sizeof(*bg_model) );
1235 cvFree( _bg_model );
1243 icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model )
1246 if ((curr_frame->height!=bg_model->params.nHeight)||(curr_frame->width!=bg_model->params.nWidth)||(curr_frame->nChannels!=bg_model->params.nND))
1247 CV_Error( CV_StsBadSize, "the image not the same size as the reserved GMM background model");
1249 float alpha=bg_model->params.fAlphaT;
1250 bg_model->countFrames++;
1252 //faster initial updates - increase value of alpha
1253 if (bg_model->params.bInit){
1254 float alphaInit=(1.0f/(2*bg_model->countFrames+1));
1255 if (alphaInit>alpha)
1261 bg_model->params.bInit = 0;
1266 //icvUpdatePixelBackgroundGMM2( curr_frame, bg_model->foreground, bg_model->data.rGMM,bg_model->data.rnUsedModes,&(bg_model->params),alpha);
1267 icvUpdatePixelBackgroundGMM2( curr_frame, bg_model->foreground, bg_model->data.rGMM,bg_model->data.rnUsedModes,
1268 bg_model->params.nM,
1269 bg_model->params.fTb,
1270 bg_model->params.fTB,
1271 bg_model->params.fTg,
1272 bg_model->params.fVarInit,
1273 bg_model->params.fVarMax,
1274 bg_model->params.fVarMin,
1275 bg_model->params.fCT,
1276 bg_model->params.fTau,
1277 bg_model->params.bShadowDetection,
1278 bg_model->params.nShadowDetection,
1281 //foreground filtering
1282 if (bg_model->params.bPostFiltering==1)
1284 int region_count = 0;
1285 CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
1288 //filter small regions
1289 cvClearMemStorage(bg_model->storage);
1291 cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 );
1292 cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 );
1294 cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
1295 for( seq = first_seq; seq; seq = seq->h_next )
1297 CvContour* cnt = (CvContour*)seq;
1298 if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea )
1300 //delete small contour
1301 prev_seq = seq->h_prev;
1304 prev_seq->h_next = seq->h_next;
1305 if( seq->h_next ) seq->h_next->h_prev = prev_seq;
1309 first_seq = seq->h_next;
1310 if( seq->h_next ) seq->h_next->h_prev = NULL;
1318 bg_model->foreground_regions = first_seq;
1319 cvZero(bg_model->foreground);
1320 cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
1322 return region_count;