diff --git a/modules/calib3d/CMakeLists.txt b/modules/calib3d/CMakeLists.txt index a177c026f9..816e0a2845 100644 --- a/modules/calib3d/CMakeLists.txt +++ b/modules/calib3d/CMakeLists.txt @@ -1 +1 @@ -define_opencv_module(calib3d opencv_core opencv_imgproc opencv_highgui opencv_features2d) +define_opencv_module(calib3d opencv_core opencv_imgproc opencv_highgui opencv_features2d opencv_flann) diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index 431fab7693..164116d3e0 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -1779,7 +1779,7 @@ public: { MSize(int* _p); Size operator()() const; - int operator[](int i) const; + const int& operator[](int i) const; int& operator[](int i); operator const int*() const; bool operator == (const MSize& sz) const; @@ -1792,7 +1792,7 @@ public: { MStep(); MStep(size_t s); - size_t operator[](int i) const; + const size_t& operator[](int i) const; size_t& operator[](int i); operator size_t() const; MStep& operator = (size_t s); diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 4086e180dd..dc8d601903 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -679,7 +679,7 @@ inline Size Mat::MSize::operator()() const CV_DbgAssert(p[-1] <= 2); return Size(p[1], p[0]); } -inline int Mat::MSize::operator[](int i) const { return p[i]; } +inline const int& Mat::MSize::operator[](int i) const { return p[i]; } inline int& Mat::MSize::operator[](int i) { return p[i]; } inline Mat::MSize::operator const int*() const { return p; } @@ -704,7 +704,7 @@ inline bool Mat::MSize::operator != (const MSize& sz) const inline Mat::MStep::MStep() { p = buf; p[0] = p[1] = 0; } inline Mat::MStep::MStep(size_t s) { p = buf; p[0] = s; p[1] = 0; } -inline size_t Mat::MStep::operator[](int i) const { return p[i]; } +inline const size_t& Mat::MStep::operator[](int i) const { return p[i]; } inline size_t& Mat::MStep::operator[](int i) { return p[i]; } inline Mat::MStep::operator size_t() const { diff --git a/modules/gtest/include/opencv2/gtest/gtestcv.hpp b/modules/gtest/include/opencv2/gtest/gtestcv.hpp index ded0044078..8ec387da97 100644 --- a/modules/gtest/include/opencv2/gtest/gtestcv.hpp +++ b/modules/gtest/include/opencv2/gtest/gtestcv.hpp @@ -33,7 +33,7 @@ CV_EXPORTS void randomSize(RNG& rng, int minDims, int maxDims, double maxSizeLog CV_EXPORTS int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels); CV_EXPORTS Mat randomMat(RNG& rng, Size size, int type, bool useRoi); CV_EXPORTS Mat randomMat(RNG& rng, const vector& size, int type, bool useRoi); -CV_EXPORTS Mat add(const Mat& a, double alpha, const Mat& b, double beta, +CV_EXPORTS void add(const Mat& a, double alpha, const Mat& b, double beta, Scalar gamma, Mat& c, int ctype, bool calcAbs); CV_EXPORTS void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta); CV_EXPORTS void copy(const Mat& src, Mat& dst, const Mat& mask=Mat()); diff --git a/modules/gtest/src/gtestcv.cpp b/modules/gtest/src/gtestcv.cpp index 5d9b25d80b..6a434bbdc5 100644 --- a/modules/gtest/src/gtestcv.cpp +++ b/modules/gtest/src/gtestcv.cpp @@ -51,14 +51,15 @@ int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels) Mat randomMat(RNG& rng, Size size, int type, bool useRoi) { - + return Mat(); } Mat randomMat(RNG& rng, const vector& size, int type, bool useRoi) { + return Mat(); } -Mat add(const Mat& _a, double alpha, const Mat& _b, double beta, +void add(const Mat& _a, double alpha, const Mat& _b, double beta, Scalar gamma, Mat& c, int ctype, bool calcAbs) { Mat a = _a, b = _b; @@ -95,7 +96,7 @@ Mat add(const Mat& _a, double alpha, const Mat& _b, double beta, NAryMatIterator it(arrays, planes, 3); int i, nplanes = it.nplanes, cn=a.channels(); - size_t total = planes[0].total(), maxsize = min(12*12*max(12/cn, 1), total); + size_t total = planes[0].total(), maxsize = std::min((size_t)12*12*std::max(12/cn, 1), total); CV_Assert(planes[0].rows == 1); buf[0].create(1, (int)maxsize, CV_64FC(cn)); @@ -142,8 +143,8 @@ Mat add(const Mat& _a, double alpha, const Mat& _b, double beta, } -static template inline void -convert(const _Tp1* src, _Tp2* dst, size_t total, double alpha, double beta) +template inline void +convert_(const _Tp1* src, _Tp2* dst, size_t total, double alpha, double beta) { size_t i; if( alpha == 1 && beta == 0 ) @@ -156,6 +157,37 @@ convert(const _Tp1* src, _Tp2* dst, size_t total, double alpha, double beta) for( i = 0; i < total; i++ ) dst[i] = saturate_cast<_Tp2>(src[i]*alpha + beta); } + +template inline void +convertTo(const _Tp* src, void* dst, int dtype, size_t total, double alpha, double beta) +{ + switch( CV_MAT_DEPTH(dtype) ) + { + case CV_8U: + convert_(src, (uchar*)dst, total, alpha, beta); + break; + case CV_8S: + convert_(src, (schar*)dst, total, alpha, beta); + break; + case CV_16U: + convert_(src, (ushort*)dst, total, alpha, beta); + break; + case CV_16S: + convert_(src, (short*)dst, total, alpha, beta); + break; + case CV_32S: + convert_(src, (int*)dst, total, alpha, beta); + break; + case CV_32F: + convert_(src, (float*)dst, total, alpha, beta); + break; + case CV_64F: + convert_(src, (double*)dst, total, alpha, beta); + break; + default: + CV_Assert(0); + } +} void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta) { @@ -176,7 +208,7 @@ void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta) Mat planes[2]; NAryMatIterator it(arrays, planes, 2); - size_t j, total = total = planes[0].total()*planes[0].channels(); + size_t total = planes[0].total()*planes[0].channels(); int i, nplanes = it.nplanes; for( i = 0; i < nplanes; i++, ++it) @@ -186,15 +218,27 @@ void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta) switch( src.depth() ) { - case - - } - - for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize ) - { - if( mptr[j] ) - for( k = 0; k < elemSize; k++ ) - dptr[k] = sptr[k]; + case CV_8U: + convertTo((const uchar*)sptr, dptr, dtype, total, alpha, beta); + break; + case CV_8S: + convertTo((const schar*)sptr, dptr, dtype, total, alpha, beta); + break; + case CV_16U: + convertTo((const ushort*)sptr, dptr, dtype, total, alpha, beta); + break; + case CV_16S: + convertTo((const short*)sptr, dptr, dtype, total, alpha, beta); + break; + case CV_32S: + convertTo((const int*)sptr, dptr, dtype, total, alpha, beta); + break; + case CV_32F: + convertTo((const float*)sptr, dptr, dtype, total, alpha, beta); + break; + case CV_64F: + convertTo((const double*)sptr, dptr, dtype, total, alpha, beta); + break; } } } @@ -246,7 +290,7 @@ void copy(const Mat& src, Mat& dst, const Mat& mask) void set(Mat& dst, const Scalar& gamma, const Mat& mask) { double buf[12]; - scalarToRawData(gama, &buf, dst.type(), dst.channels()); + scalarToRawData(gamma, &buf, dst.type(), dst.channels()); const uchar* gptr = (const uchar*)&buf[0]; if(mask.empty()) @@ -255,7 +299,7 @@ void set(Mat& dst, const Scalar& gamma, const Mat& mask) Mat plane; NAryMatIterator it(arrays, &plane, 1); int i, nplanes = it.nplanes; - size_t j, k, elemSize = dst.elemSize(), planeSize = planes[0].total()*elemSize; + size_t j, k, elemSize = dst.elemSize(), planeSize = plane.total()*elemSize; for( k = 1; k < elemSize; k++ ) if( gptr[k] != gptr[0] ) @@ -274,7 +318,7 @@ void set(Mat& dst, const Scalar& gamma, const Mat& mask) dptr[k] = gptr[k]; } else - memcpy(dtr, dst.data, planeSize); + memcpy(dptr, dst.data, planeSize); } return; } @@ -285,7 +329,7 @@ void set(Mat& dst, const Scalar& gamma, const Mat& mask) Mat planes[2]; NAryMatIterator it(arrays, planes, 2); - size_t j, k, elemSize = src.elemSize(), total = planes[0].total(); + size_t j, k, elemSize = dst.elemSize(), total = planes[0].total(); int i, nplanes = it.nplanes; for( i = 0; i < nplanes; i++, ++it) @@ -303,7 +347,7 @@ void set(Mat& dst, const Scalar& gamma, const Mat& mask) } -void minMaxFilter(const Mat& a, Mat& maxresult, const Mat& minresult, const Mat& kernel, Point anchor); +/*void minMaxFilter(const Mat& a, Mat& maxresult, const Mat& minresult, const Mat& kernel, Point anchor); void filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel, Point anchor, double delta, int borderType); void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int borderType, Scalar borderValue); void minMaxLoc(const Mat& src, double* maxval, double* minval, @@ -314,6 +358,6 @@ bool cmpEps(const Mat& src1, const Mat& src2, int int_maxdiff, int flt_maxulp, v void logicOp(const Mat& src1, const Mat& src2, Mat& dst, char c); void logicOp(const Mat& src, const Scalar& s, Mat& dst, char c); void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop); -void compare(const Mat& src, const Scalar& s, Mat& dst, int cmpop); +void compare(const Mat& src, const Scalar& s, Mat& dst, int cmpop);*/ } diff --git a/modules/objdetect/CMakeLists.txt b/modules/objdetect/CMakeLists.txt index 92f47cbd37..f41067f82a 100644 --- a/modules/objdetect/CMakeLists.txt +++ b/modules/objdetect/CMakeLists.txt @@ -1 +1 @@ -define_opencv_module(objdetect opencv_core opencv_imgproc opencv_highgui opencv_features2d opencv_calib3d) +define_opencv_module(objdetect opencv_core opencv_imgproc opencv_highgui opencv_features2d opencv_calib3d opencv_flann) diff --git a/modules/video/include/opencv2/video/background_segm.hpp b/modules/video/include/opencv2/video/background_segm.hpp index 1183853453..fca20980bd 100644 --- a/modules/video/include/opencv2/video/background_segm.hpp +++ b/modules/video/include/opencv2/video/background_segm.hpp @@ -399,6 +399,55 @@ public: double noiseSigma; }; + +class CV_EXPORTS_W BackgroundSubtractorMOG2 : public BackgroundSubtractor +{ +public: + //! the default constructor + CV_WRAP BackgroundSubtractorMOG2(); + //! 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 BackgroundSubtractorMOG2(double alphaT, + double sigma=15, + int nmixtures=5, + bool postFiltering=false, + double minArea=15, + bool detectShadows=true, + bool removeForeground=false, + + double Tb=16, + double Tg=9, + double TB=0.9, + double CT=0.05, + + uchar shadowOutputValue=127, + double tau=0.5); + + //! the destructor + virtual ~BackgroundSubtractorMOG2(); + //! the update operator + virtual void operator()(const Mat& image, Mat& fgmask, double learningRate=0); + + //! re-initiaization method + virtual void initialize(Size frameSize, + double alphaT, + double sigma=15, + int nmixtures=5, + bool postFiltering=false, + double minArea=15, + bool detectShadows=true, + bool removeForeground=false, + + double Tb=16, + double Tg=9, + double TB=0.9, + double CT=0.05, + + uchar nShadowDetection=127, + double tau=0.5); + + void* model; +}; + } #endif diff --git a/modules/video/src/bgfg_gaussmix2.cpp b/modules/video/src/bgfg_gaussmix2.cpp index 3e6fb8573c..9f92eaed01 100644 --- a/modules/video/src/bgfg_gaussmix2.cpp +++ b/modules/video/src/bgfg_gaussmix2.cpp @@ -63,7 +63,7 @@ // // // -//Example usage as part of the CvBGStatModel: +// Example usage as part of the CvBGStatModel: // CvBGStatModel* bg_model = cvCreateGaussianBGModel2( first_frame ); // // //update for each frame @@ -76,10 +76,109 @@ //Date: 27-April-2005, Version:0.9 ///////////*/ -#include "cvaux.h" -#include "cvaux_mog2.h" +#include "precomp.hpp" -int _icvRemoveShadowGMM(long posPixel, +#define CV_BG_MODEL_MOG2 3 /* "Mixture of Gaussians 2". */ + +/* default parameters of gaussian background detection algorithm */ +#define CV_BGFG_MOG2_STD_THRESHOLD 4.0f /* lambda=2.5 is 99% */ +#define CV_BGFG_MOG2_WINDOW_SIZE 500 /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */ +#define CV_BGFG_MOG2_BACKGROUND_THRESHOLD 0.9f /* threshold sum of weights for background test */ +#define CV_BGFG_MOG2_STD_THRESHOLD_GENERATE 3.0f /* lambda=2.5 is 99% */ +#define CV_BGFG_MOG2_NGAUSSIANS 5 /* = K = number of Gaussians in mixture */ +#define CV_BGFG_MOG2_SIGMA_INIT 15.0f +#define CV_BGFG_MOG2_MINAREA 15.0f + +/* additional parameters */ +#define CV_BGFG_MOG2_CT 0.05f /* complexity reduction prior constant 0 - no reduction of number of components*/ +#define CV_BGFG_MOG2_SHADOW_VALUE 127 /* value to use in the segmentation mask for shadows, sot 0 not to do shadow detection*/ +#define CV_BGFG_MOG2_SHADOW_TAU 0.5f /* Tau - shadow threshold, see the paper for explanation*/ + +struct CvGaussBGStatModel2Params +{ + bool bPostFiltering;//defult 1 - do postfiltering + double minArea; // for postfiltering + + bool bShadowDetection;//default 1 - do shadow detection + bool bRemoveForeground;//default 0, set to 1 to remove foreground pixels from the image and return background image + bool bInit;//default 1, faster updates at start + + ///////////////////////// + //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 fSigma; + //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) + + //even less important parameters + int nM;//max number of modes - const - 4 is usually enough + + //shadow detection parameters + 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. +}; + +struct CvPBGMMGaussian +{ + float sigma; + float muR; + float muG; + float muB; + float weight; +}; + +struct CvGaussBGStatModel2Data +{ + int nWidth,nHeight,nSize,nNBands;//image info + // dynamic array for the mixture of Gaussians + std::vector rGMM; + std::vector rnUsedModes;//number of Gaussian components per pixel +}; + +//only foreground image is updated +//no filtering included +struct CvGaussBGModel2 +{ + CvGaussBGStatModel2Params params; + CvGaussBGStatModel2Data data; + int countFrames; +}; + +static int _icvRemoveShadowGMM(long posPixel, float red, float green, float blue, unsigned char nModes, CvPBGMMGaussian* m_aGaussians, @@ -137,7 +236,7 @@ int _icvRemoveShadowGMM(long posPixel, return 0; } -int _icvUpdatePixelBackgroundGMM(long posPixel, +static int _icvUpdatePixelBackgroundGMM(long posPixel, float red, float green, float blue, unsigned char* pModesUsed, CvPBGMMGaussian* m_aGaussians, @@ -341,7 +440,7 @@ int _icvUpdatePixelBackgroundGMM(long posPixel, return bBackground; } -void _icvReplacePixelBackgroundGMM(long pos, +static void _icvReplacePixelBackgroundGMM(long pos, unsigned char* pData, CvPBGMMGaussian* m_aGaussians) { @@ -351,11 +450,11 @@ void _icvReplacePixelBackgroundGMM(long pos, } -void icvUpdatePixelBackgroundGMM(CvGaussBGStatModel2Data* pGMMData,CvGaussBGStatModel2Params* pGMM, float m_fAlphaT, unsigned char* data,unsigned char* output) +static void icvUpdatePixelBackgroundGMM(CvGaussBGStatModel2Data* pGMMData,CvGaussBGStatModel2Params* pGMM, float m_fAlphaT, unsigned char* data,unsigned char* output) { int size=pGMMData->nSize; unsigned char* pDataCurrent=data; - unsigned char* pUsedModes=pGMMData->rnUsedModes; + unsigned char* pUsedModes=&pGMMData->rnUsedModes[0]; unsigned char* pDataOutput=output; //some constants int m_nM=pGMM->nM; @@ -368,7 +467,7 @@ void icvUpdatePixelBackgroundGMM(CvGaussBGStatModel2Data* pGMMData,CvGaussBGStat float m_fCT=pGMM->fCT;//CT - complexity reduction prior float m_fPrune=-m_fAlphaT*m_fCT; float m_fTau=pGMM->fTau; - CvPBGMMGaussian* m_aGaussians=pGMMData->rGMM; + CvPBGMMGaussian* m_aGaussians=&pGMMData->rGMM[0]; long posPixel=0; bool m_bShadowDetection=pGMM->bShadowDetection; unsigned char m_nShadowDetection=pGMM->nShadowDetection; @@ -427,214 +526,154 @@ void icvUpdatePixelBackgroundGMM(CvGaussBGStatModel2Data* pGMMData,CvGaussBGStat } } -////////////////////////////////////////////// -//implementation as part of the CvBGStatModel -static void CV_CDECL icvReleaseGaussianBGModel2( CvGaussBGModel2** bg_model ); -static int CV_CDECL icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model ); - -CV_IMPL CvBGStatModel* -cvCreateGaussianBGModel2( IplImage* first_frame, CvGaussBGStatModel2Params* parameters ) +namespace cv { - CvGaussBGModel2* bg_model = 0; - int w,h,size; + +BackgroundSubtractorMOG2::BackgroundSubtractorMOG2() +{ + model = 0; + initialize(Size(), 0); +} + +BackgroundSubtractorMOG2::BackgroundSubtractorMOG2(double alphaT, + double sigma, int nmixtures, bool postFiltering, double minArea, + bool detectShadows, bool removeForeground, double Tb, double Tg, + double TB, double CT, uchar shadowValue, double tau) +{ + model = 0; + initialize(Size(), alphaT, sigma, nmixtures, postFiltering, minArea, + detectShadows, removeForeground, Tb, Tg, TB, CT, shadowValue, tau); +} + - CV_FUNCNAME( "cvCreateGaussianBGModel2" ); +void BackgroundSubtractorMOG2::initialize(Size frameSize, double alphaT, + double sigma, int nmixtures, bool postFiltering, double minArea, + bool detectShadows, bool removeForeground, double Tb, double Tg, + double TB, double CT, uchar shadowValue, double tau) +{ + if(!model) + model = new CvGaussBGModel2; - __BEGIN__; - - CvGaussBGStatModel2Params params; - - if( !CV_IS_IMAGE(first_frame) ) - CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" ); - - if( !(first_frame->nChannels==3) ) - CV_ERROR( CV_StsBadArg, "Need three channel image (RGB)" ); - - CV_CALL( bg_model = (CvGaussBGModel2*)cvAlloc( sizeof(*bg_model) )); - memset( bg_model, 0, sizeof(*bg_model) ); - bg_model->type = CV_BG_MODEL_MOG2; - bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel2; - bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel2; - - //init parameters - if( parameters == NULL ) - { - /* These constants are defined in cvaux/include/cvaux.h: */ - params.bRemoveForeground=0; - params.bShadowDetection = 1; - params.bPostFiltering=0; - params.minArea=CV_BGFG_MOG2_MINAREA; - - //set parameters - // K - max number of Gaussians per pixel - params.nM = CV_BGFG_MOG2_NGAUSSIANS;//4; - // Tb - the threshold - n var - //pGMM->fTb = 4*4; - params.fTb = CV_BGFG_MOG2_STD_THRESHOLD*CV_BGFG_MOG2_STD_THRESHOLD; - // Tbf - the threshold - //pGMM->fTB = 0.9f;//1-cf from the paper - params.fTB = CV_BGFG_MOG2_BACKGROUND_THRESHOLD; - // Tgenerate - the threshold - params.fTg = CV_BGFG_MOG2_STD_THRESHOLD_GENERATE*CV_BGFG_MOG2_STD_THRESHOLD_GENERATE;//update the mode or generate new - //pGMM->fSigma= 11.0f;//sigma for the new mode - params.fSigma= CV_BGFG_MOG2_SIGMA_INIT; - // alpha - the learning factor - params.fAlphaT=1.0f/CV_BGFG_MOG2_WINDOW_SIZE;//0.003f; - // complexity reduction prior constant - params.fCT=CV_BGFG_MOG2_CT;//0.05f; - - //shadow - // Shadow detection - params.nShadowDetection = CV_BGFG_MOG2_SHADOW_VALUE;//value 0 to turn off - params.fTau = CV_BGFG_MOG2_SHADOW_TAU;//0.5f;// Tau - shadow threshold - } - else - { - params = *parameters; - } - - bg_model->params = params; - - //allocate GMM data - w=first_frame->width; - h=first_frame->height; - size=w*h; - - bg_model->data.nWidth=w; - bg_model->data.nHeight=h; - bg_model->data.nNBands=3; - bg_model->data.nSize=size; - - //GMM for each pixel - bg_model->data.rGMM=(CvPBGMMGaussian*) malloc(size * params.nM * sizeof(CvPBGMMGaussian)); - //used modes per pixel - bg_model->data.rnUsedModes = (unsigned char* ) malloc(size); - memset(bg_model->data.rnUsedModes,0,size);//no modes used - - //prepare storages - CV_CALL( bg_model->background = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, first_frame->nChannels)); - CV_CALL( bg_model->foreground = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1)); - - //for eventual filtering - CV_CALL( bg_model->storage = cvCreateMemStorage()); - - bg_model->countFrames = 0; - - __END__; - - if( cvGetErrStatus() < 0 ) - { - CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model; + CvGaussBGModel2* bg_model = (CvGaussBGModel2*)model; - if( bg_model && bg_model->release ) - bg_model->release( &base_ptr ); - else - cvFree( &bg_model ); - bg_model = 0; - } + bg_model->params.bRemoveForeground=removeForeground; + bg_model->params.bShadowDetection = detectShadows; + bg_model->params.bPostFiltering = postFiltering; + bg_model->params.minArea = minArea; + bg_model->params.nM = nmixtures; + bg_model->params.fTb = Tb; + bg_model->params.fTB = TB; + bg_model->params.fTg = Tg; + bg_model->params.fSigma = sigma; + bg_model->params.fAlphaT = alphaT; + bg_model->params.fCT = CT; + bg_model->params.nShadowDetection = shadowValue; + bg_model->params.fTau = tau; - return (CvBGStatModel*)bg_model; -} - - -static void CV_CDECL -icvReleaseGaussianBGModel2( CvGaussBGModel2** _bg_model ) -{ - CV_FUNCNAME( "icvReleaseGaussianBGModel2" ); - - __BEGIN__; + int w = frameSize.width; + int h = frameSize.height; + int size = w*h; - if( !_bg_model ) - CV_ERROR( CV_StsNullPtr, "" ); - - if( *_bg_model ) + if( (bg_model->data.nWidth != w || + bg_model->data.nHeight != h) && + w > 0 && h > 0 ) { - CvGaussBGModel2* bg_model = *_bg_model; - - free (bg_model->data.rGMM); - free (bg_model->data.rnUsedModes); - - cvReleaseImage( &bg_model->background ); - cvReleaseImage( &bg_model->foreground ); - cvReleaseMemStorage(&bg_model->storage); - memset( bg_model, 0, sizeof(*bg_model) ); - cvFree( _bg_model ); + bg_model->data.nWidth=w; + bg_model->data.nHeight=h; + bg_model->data.nNBands=3; + bg_model->data.nSize=size; + + //GMM for each pixel + bg_model->data.rGMM.resize(size * bg_model->params.nM); } - - __END__; + //used modes per pixel + bg_model->data.rnUsedModes.resize(0); + bg_model->data.rnUsedModes.resize(size, (uchar)0); + bg_model->params.bInit = true; + bg_model->countFrames = 0; } - -static int CV_CDECL -icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model ) + +BackgroundSubtractorMOG2::~BackgroundSubtractorMOG2() { + delete (CvGaussBGModel2*)model; +} + +void BackgroundSubtractorMOG2::operator()(const Mat& image0, Mat& fgmask0, double learningRate) +{ + CvGaussBGModel2* bg_model = (CvGaussBGModel2*)model; + + CV_Assert(bg_model != 0); + Mat fgmask = fgmask0, image = image0; + CV_Assert( image.type() == CV_8UC1 || image.type() == CV_8UC3 ); + + if( learningRate <= 0 ) + learningRate = bg_model->params.fAlphaT; + if( learningRate >= 1 ) + { + learningRate = 1; + bg_model->params.bInit = true; + } + if( image.size() != Size(bg_model->data.nWidth, bg_model->data.nHeight) ) + initialize(image.size(), learningRate, bg_model->params.fSigma, + bg_model->params.nM, bg_model->params.bPostFiltering, + bg_model->params.minArea, bg_model->params.bShadowDetection, + bg_model->params.bRemoveForeground, + bg_model->params.fTb, bg_model->params.fTg, bg_model->params.fTB, + bg_model->params.fCT, bg_model->params.nShadowDetection, bg_model->params.fTau); + //int i, j, k, n; - int region_count = 0; - CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL; - float alpha,alphaInit; + float alpha = (float)bg_model->params.fAlphaT; bg_model->countFrames++; - alpha=bg_model->params.fAlphaT; - - if (bg_model->params.bInit){ - //faster initial updates - alphaInit=(1.0f/(2*bg_model->countFrames+1)); - if (alphaInit>alpha) - { - alpha=alphaInit; - } - else - { - bg_model->params.bInit=0; - } - } - - icvUpdatePixelBackgroundGMM(&bg_model->data,&bg_model->params,alpha,(unsigned char*)curr_frame->imageData,(unsigned char*)bg_model->foreground->imageData); - if (bg_model->params.bPostFiltering==1) - { - //foreground filtering - - //filter small regions - cvClearMemStorage(bg_model->storage); - - cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 ); - cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 ); - - cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST ); - for( seq = first_seq; seq; seq = seq->h_next ) + if (bg_model->params.bInit) { - CvContour* cnt = (CvContour*)seq; - if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea ) - { - //delete small contour - prev_seq = seq->h_prev; - if( prev_seq ) - { - prev_seq->h_next = seq->h_next; - if( seq->h_next ) seq->h_next->h_prev = prev_seq; - } - else - { - first_seq = seq->h_next; - if( seq->h_next ) seq->h_next->h_prev = NULL; - } - } + //faster initial updates + float alphaInit = 1.0f/(2*bg_model->countFrames+1); + if( alphaInit > alpha ) + alpha = alphaInit; + else + bg_model->params.bInit = false; + } + + if( !image.isContinuous() || image.channels() != 3 ) + { + image.release(); + image.create(image0.size(), CV_8UC3); + if( image0.type() == image.type() ) + image0.copyTo(image); else - { - region_count++; - } + cvtColor(image0, image, CV_GRAY2BGR); } - bg_model->foreground_regions = first_seq; - cvZero(bg_model->foreground); - cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1); - - return region_count; - } - else - { - return 1; - } + + if( !fgmask.isContinuous() ) + fgmask.release(); + fgmask.create(image.size(), CV_8UC1); + + icvUpdatePixelBackgroundGMM(&bg_model->data,&bg_model->params,alpha,image.data,fgmask.data); + + if (!bg_model->params.bPostFiltering) + return; + + //foreground filtering: filter out small regions + morphologyEx(fgmask, fgmask, CV_MOP_OPEN, Mat()); + morphologyEx(fgmask, fgmask, CV_MOP_CLOSE, Mat()); + + vector > contours; + findContours(fgmask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); + fgmask = Scalar::all(0); + + for( size_t i = 0; i < contours.size(); i++ ) + { + if( boundingRect(Mat(contours[i])).area() < bg_model->params.minArea ) + continue; + drawContours(fgmask, contours, (int)i, Scalar::all(255), -1, 8, vector(), 1); + } + + fgmask.copyTo(fgmask0); +} + } /* End of file. */