From a25c27ca05fdddfdedfe14fe0207e48dfde3785a Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Thu, 28 Jun 2012 20:42:26 +0000 Subject: [PATCH] Fixed windows build problems of BackgroundSubtractorGMG but code still need more work. --- .../include/opencv2/video/background_segm.hpp | 462 ++++++------ modules/video/src/bgfg_gmg.cpp | 656 +++++++++--------- modules/video/src/video_init.cpp | 2 +- 3 files changed, 559 insertions(+), 561 deletions(-) diff --git a/modules/video/include/opencv2/video/background_segm.hpp b/modules/video/include/opencv2/video/background_segm.hpp index 28a9f21d1..9f5dfe5b3 100644 --- a/modules/video/include/opencv2/video/background_segm.hpp +++ b/modules/video/include/opencv2/video/background_segm.hpp @@ -50,7 +50,7 @@ namespace cv /*! The Base Class for Background/Foreground Segmentation - + The class is only used to define the common interface for the whole family of background/foreground segmentation algorithms. */ @@ -70,13 +70,13 @@ public: /*! Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm - + The class implements the following algorithm: "An improved adaptive background mixture model for real-time tracking with shadow detection" P. KadewTraKuPong and R. Bowden, Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001." http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf - + */ class CV_EXPORTS_W BackgroundSubtractorMOG : public BackgroundSubtractor { @@ -89,13 +89,13 @@ public: 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: +protected: Size frameSize; int frameType; Mat bgmodel; @@ -105,7 +105,7 @@ protected: double varThreshold; double backgroundRatio; double noiseSigma; -}; +}; /*! @@ -126,16 +126,16 @@ public: 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: + +protected: Size frameSize; int frameType; Mat bgmodel; @@ -150,7 +150,7 @@ protected: // 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 //////////////////////// @@ -179,7 +179,7 @@ protected: //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 @@ -188,7 +188,7 @@ protected: //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. -}; +}; /** * Background Subtractor module. Takes a series of images and returns a sequence of mask (8UC1) @@ -200,252 +200,250 @@ protected: class CV_EXPORTS BackgroundSubtractorGMG: public cv::BackgroundSubtractor { private: - /** - * A general flexible datatype. - * - * Used internally to enable background subtraction algorithm to be robust to any input Mat type. - * Datatype can be char, unsigned char, int, unsigned int, long int, float, or double. - */ - union flexitype{ - char c; - uchar uc; - int i; - unsigned int ui; - long int li; - float f; - double d; + /** + * A general flexible datatype. + * + * Used internally to enable background subtraction algorithm to be robust to any input Mat type. + * Datatype can be char, unsigned char, int, unsigned int, long int, float, or double. + */ + union flexitype{ + char c; + uchar uc; + int i; + unsigned int ui; + long int li; + float f; + double d; - flexitype(){d = 0.0;} //!< Default constructor, set all bits of the union to 0. - flexitype(char cval){c = cval;} //!< Char type constructor + flexitype(){d = 0.0;} //!< Default constructor, set all bits of the union to 0. + flexitype(char cval){c = cval;} //!< Char type constructor - bool operator ==(flexitype& rhs) - { - return d == rhs.d; - } + bool operator ==(flexitype& rhs) + { + return d == rhs.d; + } - //! Char type assignment operator - flexitype& operator =(char cval){ - if (this->c == cval){return *this;} - c = cval; return *this; - } - flexitype(unsigned char ucval){uc = ucval;} //!< unsigned char type constructor + //! Char type assignment operator + flexitype& operator =(char cval){ + if (this->c == cval){return *this;} + c = cval; return *this; + } + flexitype(unsigned char ucval){uc = ucval;} //!< unsigned char type constructor - //! unsigned char type assignment operator - flexitype& operator =(unsigned char ucval){ - if (this->uc == ucval){return *this;} - uc = ucval; return *this; - } - flexitype(int ival){i = ival;} //!< int type constructor - //! int type assignment operator - flexitype& operator =(int ival){ - if (this->i == ival){return *this;} - i = ival; return *this; - } - flexitype(unsigned int uival){ui = uival;} //!< unsigned int type constructor + //! unsigned char type assignment operator + flexitype& operator =(unsigned char ucval){ + if (this->uc == ucval){return *this;} + uc = ucval; return *this; + } + flexitype(int ival){i = ival;} //!< int type constructor + //! int type assignment operator + flexitype& operator =(int ival){ + if (this->i == ival){return *this;} + i = ival; return *this; + } + flexitype(unsigned int uival){ui = uival;} //!< unsigned int type constructor - //! unsigned int type assignment operator - flexitype& operator =(unsigned int uival){ - if (this->ui == uival){return *this;} - ui = uival; return *this; - } - flexitype(float fval){f = fval;} //!< float type constructor - //! float type assignment operator - flexitype& operator =(float fval){ - if (this->f == fval){return *this;} - f = fval; return *this; - } - flexitype(long int lival){li = lival;} //!< long int type constructor - //! long int type assignment operator - flexitype& operator =(long int lival){ - if (this->li == lival){return *this;} - li = lival; return *this; - } + //! unsigned int type assignment operator + flexitype& operator =(unsigned int uival){ + if (this->ui == uival){return *this;} + ui = uival; return *this; + } + flexitype(float fval){f = fval;} //!< float type constructor + //! float type assignment operator + flexitype& operator =(float fval){ + if (this->f == fval){return *this;} + f = fval; return *this; + } + flexitype(long int lival){li = lival;} //!< long int type constructor + //! long int type assignment operator + flexitype& operator =(long int lival){ + if (this->li == lival){return *this;} + li = lival; return *this; + } - flexitype(double dval){d=dval;} //!< double type constructor - //! double type assignment operator - flexitype& operator =(double dval){ - if (this->d == dval){return *this;} - d = dval; return *this; - } - }; - /** - * Used internally to represent a single feature in a histogram. - * Feature is a color and an associated likelihood (weight in the histogram). - */ - struct HistogramFeatureGMG - { - /** - * Default constructor. - * Initializes likelihood of feature to 0, color remains uninitialized. - */ - HistogramFeatureGMG(){likelihood = 0.0;} + flexitype(double dval){d=dval;} //!< double type constructor + //! double type assignment operator + flexitype& operator =(double dval){ + if (this->d == dval){return *this;} + d = dval; return *this; + } + }; + /** + * Used internally to represent a single feature in a histogram. + * Feature is a color and an associated likelihood (weight in the histogram). + */ + struct CV_EXPORTS HistogramFeatureGMG + { + /** + * Default constructor. + * Initializes likelihood of feature to 0, color remains uninitialized. + */ + HistogramFeatureGMG(){likelihood = 0.0;} - /** - * Copy constructor. - * Required to use HistogramFeatureGMG in a std::vector - * @see operator =() - */ - HistogramFeatureGMG(const HistogramFeatureGMG& orig){ - color = orig.color; likelihood = orig.likelihood; - } + /** + * Copy constructor. + * Required to use HistogramFeatureGMG in a std::vector + * @see operator =() + */ + HistogramFeatureGMG(const HistogramFeatureGMG& orig){ + color = orig.color; likelihood = orig.likelihood; + } - /** - * Assignment operator. - * Required to use HistogramFeatureGMG in a std::vector - */ - HistogramFeatureGMG& operator =(const HistogramFeatureGMG& orig){ - color = orig.color; likelihood = orig.likelihood; return *this; - } + /** + * Assignment operator. + * Required to use HistogramFeatureGMG in a std::vector + */ + HistogramFeatureGMG& operator =(const HistogramFeatureGMG& orig){ + color = orig.color; likelihood = orig.likelihood; return *this; + } - /** - * Tests equality of histogram features. - * Equality is tested only by matching the color (feature), not the likelihood. - * This operator is used to look up an observed feature in a histogram. - */ - bool operator ==(HistogramFeatureGMG &rhs); + /** + * Tests equality of histogram features. + * Equality is tested only by matching the color (feature), not the likelihood. + * This operator is used to look up an observed feature in a histogram. + */ + bool operator ==(HistogramFeatureGMG &rhs); - //! Regardless of the image datatype, it is quantized and mapped to an integer and represented as a vector. - vector color; + //! Regardless of the image datatype, it is quantized and mapped to an integer and represented as a vector. + vector color; - //! Represents the weight of feature in the histogram. - float likelihood; - friend class PixelModelGMG; - }; + //! Represents the weight of feature in the histogram. + float likelihood; + friend class PixelModelGMG; + }; - /** - * Representation of the statistical model of a single pixel for use in the background subtraction - * algorithm. - */ - class PixelModelGMG - { - public: - PixelModelGMG(); - virtual ~PixelModelGMG(); + /** + * Representation of the statistical model of a single pixel for use in the background subtraction + * algorithm. + */ + class CV_EXPORTS PixelModelGMG + { + public: + PixelModelGMG(); + ~PixelModelGMG(); - /** - * Incorporate the last observed feature into the statistical model. - * - * @param learningRate The adaptation parameter for the histogram. -1.0 to use default. Value - * should be between 0.0 and 1.0, the higher the value, the faster the - * adaptation. 1.0 is limiting case where fast adaptation means no memory. - */ - void insertFeature(double learningRate = -1.0); + /** + * Incorporate the last observed feature into the statistical model. + * + * @param learningRate The adaptation parameter for the histogram. -1.0 to use default. Value + * should be between 0.0 and 1.0, the higher the value, the faster the + * adaptation. 1.0 is limiting case where fast adaptation means no memory. + */ + void insertFeature(double learningRate = -1.0); - /** - * Set the feature last observed, to save before incorporating it into the statistical - * model with insertFeature(). - * - * @param feature The feature (color) just observed. - */ - void setLastObservedFeature(BackgroundSubtractorGMG::HistogramFeatureGMG feature); - /** - * Set the upper limit for the number of features to store in the histogram. Use to adjust - * memory requirements. - * - * @param max size_t representing the max number of features. - */ - void setMaxFeatures(size_t max) { - maxFeatures = max; histogram.resize(max); histogram.clear(); - } - /** - * Normalize the histogram, so sum of weights of all features = 1.0 - */ - void normalizeHistogram(); - /** - * Return the weight of a feature in the histogram. If the feature is not represented in the - * histogram, the weight returned is 0.0. - */ - double getLikelihood(HistogramFeatureGMG f); - PixelModelGMG& operator *=(const float &rhs); - //friend class BackgroundSubtractorGMG; - //friend class HistogramFeatureGMG; - protected: - size_t numFeatures; //!< number of features in histogram - size_t maxFeatures; //!< max allowable features in histogram - std::list histogram; //!< represents the histogram as a list of features - HistogramFeatureGMG lastObservedFeature; - //!< store last observed feature in case we need to add it to histogram - }; + /** + * Set the feature last observed, to save before incorporating it into the statistical + * model with insertFeature(). + * + * @param feature The feature (color) just observed. + */ + void setLastObservedFeature(BackgroundSubtractorGMG::HistogramFeatureGMG feature); + /** + * Set the upper limit for the number of features to store in the histogram. Use to adjust + * memory requirements. + * + * @param max size_t representing the max number of features. + */ + void setMaxFeatures(size_t max) { + maxFeatures = max; histogram.resize(max); histogram.clear(); + } + /** + * Normalize the histogram, so sum of weights of all features = 1.0 + */ + void normalizeHistogram(); + /** + * Return the weight of a feature in the histogram. If the feature is not represented in the + * histogram, the weight returned is 0.0. + */ + double getLikelihood(HistogramFeatureGMG f); + PixelModelGMG& operator *=(const float &rhs); + //friend class BackgroundSubtractorGMG; + //friend class HistogramFeatureGMG; + private: + size_t numFeatures; //!< number of features in histogram + size_t maxFeatures; //!< max allowable features in histogram + std::list histogram; //!< represents the histogram as a list of features + HistogramFeatureGMG lastObservedFeature; + //!< store last observed feature in case we need to add it to histogram + }; public: - BackgroundSubtractorGMG(); - virtual ~BackgroundSubtractorGMG(); - virtual AlgorithmInfo* info() const; + BackgroundSubtractorGMG(); + virtual ~BackgroundSubtractorGMG(); + virtual AlgorithmInfo* info() const; - /** - * 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); + /** + * 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); - /** - * Validate parameters and set up data structures for appropriate image type. Must call before - * running on data. - * @param image One sample image from dataset - * @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 initializeType(InputArray image, flexitype min, flexitype max); - /** - * Selectively update the background model. Only update background model for pixels identified - * as background. - * @param mask Mask image same size as images in sequence. Must be 8UC1 matrix, 255 for foreground - * and 0 for background. - */ - void updateBackgroundModel(InputArray mask); - /** - * Retrieve the greyscale image representing the probability that each pixel is foreground given - * the current estimated background model. Values are 0.0 (black) to 1.0 (white). - * @param img The 32FC1 image representing per-pixel probabilities that the pixel is foreground. - */ - void getPosteriorImage(OutputArray img); + /** + * Validate parameters and set up data structures for appropriate image type. Must call before + * running on data. + * @param image One sample image from dataset + * @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 initializeType(InputArray image, flexitype min, flexitype max); + /** + * Selectively update the background model. Only update background model for pixels identified + * as background. + * @param mask Mask image same size as images in sequence. Must be 8UC1 matrix, 255 for foreground + * and 0 for background. + */ + void updateBackgroundModel(InputArray mask); + /** + * Retrieve the greyscale image representing the probability that each pixel is foreground given + * the current estimated background model. Values are 0.0 (black) to 1.0 (white). + * @param img The 32FC1 image representing per-pixel probabilities that the pixel is foreground. + */ + void getPosteriorImage(OutputArray img); protected: - //! 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; + //! 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; - double decisionThreshold; //!< value above which pixel is determined to be FG. - int smoothingRadius; //!< smoothing radius, in pixels, for cleaning up FG image. + double decisionThreshold; //!< value above which pixel is determined to be FG. + int smoothingRadius; //!< smoothing radius, in pixels, for cleaning up FG image. - flexitype maxVal, minVal; + flexitype maxVal, minVal; - /* - * General Parameters - */ - size_t imWidth; //!< width of image. - size_t imHeight; //!< height of image. - size_t numPixels; + /* + * General Parameters + */ + size_t imWidth; //!< width of image. + size_t imHeight; //!< height of image. + size_t numPixels; - int imageDepth; //!< Depth of image, e.g. CV_8U - unsigned int numChannels; //!< Number of channels in image. + int imageDepth; //!< Depth of image, e.g. CV_8U + unsigned int numChannels; //!< Number of channels in image. - bool isDataInitialized; - //!< After general parameters are set, data structures must be initialized. + bool isDataInitialized; + //!< After general parameters are set, data structures must be initialized. - size_t elemSize; //!< store image mat element sizes - size_t elemSize1; + size_t elemSize; //!< store image mat element sizes + size_t elemSize1; - /* - * Data Structures - */ - vector pixels; //!< Probabilistic background models for each pixel in image. - int frameNum; //!< Frame number counter, used to count frames in training mode. - Mat posteriorImage; //!< Posterior probability image. - Mat fgMaskImage; //!< Foreground mask image. + /* + * Data Structures + */ + vector pixels; //!< Probabilistic background models for each pixel in image. + int frameNum; //!< Frame number counter, used to count frames in training mode. + Mat posteriorImage; //!< Posterior probability image. + Mat fgMaskImage; //!< Foreground mask image. }; -bool initModule_BackgroundSubtractorGMG(void); - } #endif diff --git a/modules/video/src/bgfg_gmg.cpp b/modules/video/src/bgfg_gmg.cpp index f808cab23..145ecc64a 100644 --- a/modules/video/src/bgfg_gmg.cpp +++ b/modules/video/src/bgfg_gmg.cpp @@ -7,7 +7,7 @@ // copy or use the software. // // -// License Agreement +// License Agreement // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Third party copyrights are property of their respective owners. @@ -66,245 +66,245 @@ BackgroundSubtractorGMG::BackgroundSubtractorGMG() decisionThreshold = 0.8; smoothingRadius = 7; } - + void BackgroundSubtractorGMG::initializeType(InputArray _image,flexitype min, flexitype max) { - minVal = min; - maxVal = max; + minVal = min; + maxVal = max; - if (minVal == maxVal) - { - CV_Error_(CV_StsBadArg,("minVal and maxVal cannot be the same.")); - } + if (minVal == maxVal) + { + CV_Error_(CV_StsBadArg,("minVal and maxVal cannot be the same.")); + } - /* - * Parameter validation - */ - if (maxFeatures <= 0) - { - CV_Error_(CV_StsBadArg, - ("maxFeatures parameter must be 1 or greater. Instead, it is %d.",maxFeatures)); - } - if (learningRate < 0.0 || learningRate > 1.0) - { - CV_Error_(CV_StsBadArg, - ("learningRate parameter must be in the range [0.0,1.0]. Instead, it is %f.", - learningRate)); - } - if (numInitializationFrames < 1) - { - CV_Error_(CV_StsBadArg, - ("numInitializationFrames must be at least 1. Instead, it is %d.", - numInitializationFrames)); - } - if (quantizationLevels < 1) - { - CV_Error_(CV_StsBadArg, - ("quantizationLevels must be at least 1 (preferably more). Instead it is %d.", - quantizationLevels)); - } - if (backgroundPrior < 0.0 || backgroundPrior > 1.0) - { - CV_Error_(CV_StsBadArg, - ("backgroundPrior must be a probability, between 0.0 and 1.0. Instead it is %f.", - backgroundPrior)); - } + /* + * Parameter validation + */ + if (maxFeatures <= 0) + { + CV_Error_(CV_StsBadArg, + ("maxFeatures parameter must be 1 or greater. Instead, it is %d.",maxFeatures)); + } + if (learningRate < 0.0 || learningRate > 1.0) + { + CV_Error_(CV_StsBadArg, + ("learningRate parameter must be in the range [0.0,1.0]. Instead, it is %f.", + learningRate)); + } + if (numInitializationFrames < 1) + { + CV_Error_(CV_StsBadArg, + ("numInitializationFrames must be at least 1. Instead, it is %d.", + numInitializationFrames)); + } + if (quantizationLevels < 1) + { + CV_Error_(CV_StsBadArg, + ("quantizationLevels must be at least 1 (preferably more). Instead it is %d.", + quantizationLevels)); + } + if (backgroundPrior < 0.0 || backgroundPrior > 1.0) + { + CV_Error_(CV_StsBadArg, + ("backgroundPrior must be a probability, between 0.0 and 1.0. Instead it is %f.", + backgroundPrior)); + } - /* - * Detect and accommodate the image depth - */ - Mat image = _image.getMat(); - imageDepth = image.depth(); // 32f, 8u, etc. - numChannels = image.channels(); + /* + * Detect and accommodate the image depth + */ + Mat image = _image.getMat(); + imageDepth = image.depth(); // 32f, 8u, etc. + numChannels = image.channels(); - /* - * Color quantization [0 | | | | max] --> [0 | | max] - * (0) Use double as intermediary to convert all types to int. - * (i) Shift min to 0, - * (ii) max/(num intervals) = factor. x/factor * factor = quantized result, after integer operation. - */ + /* + * Color quantization [0 | | | | max] --> [0 | | max] + * (0) Use double as intermediary to convert all types to int. + * (i) Shift min to 0, + * (ii) max/(num intervals) = factor. x/factor * factor = quantized result, after integer operation. + */ - /* - * Data Structure Initialization - */ - Size imsize = image.size(); - imWidth = imsize.width; - imHeight = imsize.height; - numPixels = imWidth*imHeight; - pixels.resize(numPixels); - frameNum = 0; + /* + * Data Structure Initialization + */ + Size imsize = image.size(); + imWidth = imsize.width; + imHeight = imsize.height; + numPixels = imWidth*imHeight; + pixels.resize(numPixels); + frameNum = 0; - // used to iterate through matrix of type unknown at compile time - elemSize = image.elemSize(); - elemSize1 = image.elemSize1(); + // used to iterate through matrix of type unknown at compile time + elemSize = image.elemSize(); + elemSize1 = image.elemSize1(); - vector::iterator pixel; - vector::iterator pixel_end = pixels.end(); - for (pixel = pixels.begin(); pixel != pixel_end; ++pixel) - { - pixel->setMaxFeatures(maxFeatures); - } + vector::iterator pixel; + vector::iterator pixel_end = pixels.end(); + for (pixel = pixels.begin(); pixel != pixel_end; ++pixel) + { + pixel->setMaxFeatures(maxFeatures); + } - fgMaskImage = Mat::zeros(imHeight,imWidth,CV_8UC1); // 8-bit unsigned mask. 255 for FG, 0 for BG - posteriorImage = Mat::zeros(imHeight,imWidth,CV_32FC1); // float for storing probabilities. Can be viewed directly with imshow. - isDataInitialized = true; + fgMaskImage = Mat::zeros(imHeight,imWidth,CV_8UC1); // 8-bit unsigned mask. 255 for FG, 0 for BG + posteriorImage = Mat::zeros(imHeight,imWidth,CV_32FC1); // float for storing probabilities. Can be viewed directly with imshow. + isDataInitialized = true; } void BackgroundSubtractorGMG::operator()(InputArray _image, OutputArray _fgmask, double newLearningRate) { - if (!isDataInitialized) - { - CV_Error(CV_StsError,"BackgroundSubstractorGMG has not been initialized. Call initialize() first.\n"); - } + if (!isDataInitialized) + { + CV_Error(CV_StsError,"BackgroundSubstractorGMG has not been initialized. Call initialize() first.\n"); + } - /* - * Update learning rate parameter, if desired - */ - if (newLearningRate != -1.0) - { - if (newLearningRate < 0.0 || newLearningRate > 1.0) - { - CV_Error(CV_StsOutOfRange,"Learning rate for Operator () must be between 0.0 and 1.0.\n"); - } - this->learningRate = newLearningRate; - } + /* + * Update learning rate parameter, if desired + */ + if (newLearningRate != -1.0) + { + if (newLearningRate < 0.0 || newLearningRate > 1.0) + { + CV_Error(CV_StsOutOfRange,"Learning rate for Operator () must be between 0.0 and 1.0.\n"); + } + this->learningRate = newLearningRate; + } - Mat image = _image.getMat(); + Mat image = _image.getMat(); - _fgmask.create(Size(imHeight,imWidth),CV_8U); - fgMaskImage = _fgmask.getMat(); // 8-bit unsigned mask. 255 for FG, 0 for BG + _fgmask.create(Size(imHeight,imWidth),CV_8U); + fgMaskImage = _fgmask.getMat(); // 8-bit unsigned mask. 255 for FG, 0 for BG - /* - * Iterate over pixels in image - */ - // grab data at each pixel (1,2,3 channels, int, float, etc.) - // grab data as an array of bytes. Then, send that array to a function that reads data into vector of appropriate types... and quantizing... before saving as a feature, which is a vector of flexitypes, so code can be portable. - // multiple channels do have sequential storage, use mat::elemSize() and mat::elemSize1() - vector::iterator pixel; - vector::iterator pixel_end = pixels.end(); - size_t i; + /* + * Iterate over pixels in image + */ + // grab data at each pixel (1,2,3 channels, int, float, etc.) + // grab data as an array of bytes. Then, send that array to a function that reads data into vector of appropriate types... and quantizing... before saving as a feature, which is a vector of flexitypes, so code can be portable. + // multiple channels do have sequential storage, use mat::elemSize() and mat::elemSize1() + vector::iterator pixel; + vector::iterator pixel_end = pixels.end(); + size_t i; //#pragma omp parallel - for (i = 0, pixel=pixels.begin(); pixel != pixel_end; ++i,++pixel) - { - HistogramFeatureGMG newFeature; - newFeature.color.clear(); - for (size_t c = 0; c < numChannels; ++c) - { - /* - * Perform quantization. in each channel. (color-min)*(levels)/(max-min). - * Shifts min to 0 and scales, finally casting to an int. - */ - size_t quantizedColor; - // pixel at data+elemSize*i. Individual channel c at data+elemSize*i+elemSize1*c - if (imageDepth == CV_8U) - { - uchar *color = (uchar*)(image.data+elemSize*i+elemSize1*c); - quantizedColor = (size_t)((double)(*color-minVal.uc)*quantizationLevels/(maxVal.uc-minVal.uc)); - } - else if (imageDepth == CV_8S) - { - char *color = (char*)(image.data+elemSize*i+elemSize1*c); - quantizedColor = (size_t)((double)(*color-minVal.c)*quantizationLevels/(maxVal.c-minVal.c)); - } - else if (imageDepth == CV_16U) - { - unsigned int *color = (unsigned int*)(image.data+elemSize*i+elemSize1*c); - quantizedColor = (size_t)((double)(*color-minVal.ui)*quantizationLevels/(maxVal.ui-minVal.ui)); - } - else if (imageDepth == CV_16S) - { - int *color = (int*)(image.data+elemSize*i+elemSize1*c); - quantizedColor = (size_t)((double)(*color-minVal.i)*quantizationLevels/(maxVal.i-minVal.i)); - } - else if (imageDepth == CV_32F) - { - float *color = (float*)image.data+elemSize*i+elemSize1*c; - quantizedColor = (size_t)((double)(*color-minVal.ui)*quantizationLevels/(maxVal.ui-minVal.ui)); - } - else if (imageDepth == CV_32S) - { - long int *color = (long int*)(image.data+elemSize*i+elemSize1*c); - quantizedColor = (size_t)((double)(*color-minVal.li)*quantizationLevels/(maxVal.li-minVal.li)); - } - else if (imageDepth == CV_64F) - { - double *color = (double*)image.data+elemSize*i+elemSize1*c; - quantizedColor = (size_t)((double)(*color-minVal.d)*quantizationLevels/(maxVal.d-minVal.d)); - } - newFeature.color.push_back(quantizedColor); - } - // now that the feature is ready for use, put it in the histogram + for (i = 0, pixel=pixels.begin(); pixel != pixel_end; ++i,++pixel) + { + HistogramFeatureGMG newFeature; + newFeature.color.clear(); + for (size_t c = 0; c < numChannels; ++c) + { + /* + * Perform quantization. in each channel. (color-min)*(levels)/(max-min). + * Shifts min to 0 and scales, finally casting to an int. + */ + size_t quantizedColor; + // pixel at data+elemSize*i. Individual channel c at data+elemSize*i+elemSize1*c + if (imageDepth == CV_8U) + { + uchar *color = (uchar*)(image.data+elemSize*i+elemSize1*c); + quantizedColor = (size_t)((double)(*color-minVal.uc)*quantizationLevels/(maxVal.uc-minVal.uc)); + } + else if (imageDepth == CV_8S) + { + char *color = (char*)(image.data+elemSize*i+elemSize1*c); + quantizedColor = (size_t)((double)(*color-minVal.c)*quantizationLevels/(maxVal.c-minVal.c)); + } + else if (imageDepth == CV_16U) + { + unsigned int *color = (unsigned int*)(image.data+elemSize*i+elemSize1*c); + quantizedColor = (size_t)((double)(*color-minVal.ui)*quantizationLevels/(maxVal.ui-minVal.ui)); + } + else if (imageDepth == CV_16S) + { + int *color = (int*)(image.data+elemSize*i+elemSize1*c); + quantizedColor = (size_t)((double)(*color-minVal.i)*quantizationLevels/(maxVal.i-minVal.i)); + } + else if (imageDepth == CV_32F) + { + float *color = (float*)image.data+elemSize*i+elemSize1*c; + quantizedColor = (size_t)((double)(*color-minVal.ui)*quantizationLevels/(maxVal.ui-minVal.ui)); + } + else if (imageDepth == CV_32S) + { + long int *color = (long int*)(image.data+elemSize*i+elemSize1*c); + quantizedColor = (size_t)((double)(*color-minVal.li)*quantizationLevels/(maxVal.li-minVal.li)); + } + else if (imageDepth == CV_64F) + { + double *color = (double*)image.data+elemSize*i+elemSize1*c; + quantizedColor = (size_t)((double)(*color-minVal.d)*quantizationLevels/(maxVal.d-minVal.d)); + } + newFeature.color.push_back(quantizedColor); + } + // now that the feature is ready for use, put it in the histogram - if (frameNum > numInitializationFrames) // typical operation - { - newFeature.likelihood = learningRate; - /* - * (1) Query histogram to find posterior probability of feature under model. - */ - float likelihood = (float)pixel->getLikelihood(newFeature); + if (frameNum > numInitializationFrames) // typical operation + { + newFeature.likelihood = float(learningRate); + /* + * (1) Query histogram to find posterior probability of feature under model. + */ + float likelihood = (float)pixel->getLikelihood(newFeature); - // see Godbehere, Matsukawa, Goldberg (2012) for reasoning behind this implementation of Bayes rule - float posterior = (likelihood*backgroundPrior)/(likelihood*backgroundPrior+(1-likelihood)*(1-backgroundPrior)); + // see Godbehere, Matsukawa, Goldberg (2012) for reasoning behind this implementation of Bayes rule + float posterior = float((likelihood*backgroundPrior)/(likelihood*backgroundPrior+(1-likelihood)*(1-backgroundPrior))); - /* - * (2) feed posterior probability into the posterior image - */ - int row,col; - col = i%imWidth; - row = (i-col)/imWidth; - posteriorImage.at(row,col) = (1.0-posterior); - } - pixel->setLastObservedFeature(newFeature); - } - /* - * (3) Perform filtering and threshold operations to yield final mask image. - * - * 2 options. First is morphological open/close as before. Second is "median filtering" which Jon Barron says is good to remove noise - */ - Mat thresholdedPosterior; - threshold(posteriorImage,thresholdedPosterior,decisionThreshold,1.0,THRESH_BINARY); - thresholdedPosterior.convertTo(fgMaskImage,CV_8U,255); // convert image to integer space for further filtering and mask creation - medianBlur(fgMaskImage,fgMaskImage,smoothingRadius); + /* + * (2) feed posterior probability into the posterior image + */ + int row,col; + col = i%imWidth; + row = (i-col)/imWidth; + posteriorImage.at(row,col) = (1.0f-posterior); + } + pixel->setLastObservedFeature(newFeature); + } + /* + * (3) Perform filtering and threshold operations to yield final mask image. + * + * 2 options. First is morphological open/close as before. Second is "median filtering" which Jon Barron says is good to remove noise + */ + Mat thresholdedPosterior; + threshold(posteriorImage,thresholdedPosterior,decisionThreshold,1.0,THRESH_BINARY); + thresholdedPosterior.convertTo(fgMaskImage,CV_8U,255); // convert image to integer space for further filtering and mask creation + medianBlur(fgMaskImage,fgMaskImage,smoothingRadius); - fgMaskImage.copyTo(_fgmask); + fgMaskImage.copyTo(_fgmask); - ++frameNum; // keep track of how many frames we have processed + ++frameNum; // keep track of how many frames we have processed } void BackgroundSubtractorGMG::getPosteriorImage(OutputArray _img) { - _img.create(Size(imWidth,imHeight),CV_32F); - Mat img = _img.getMat(); - posteriorImage.copyTo(img); + _img.create(Size(imWidth,imHeight),CV_32F); + Mat img = _img.getMat(); + posteriorImage.copyTo(img); } void BackgroundSubtractorGMG::updateBackgroundModel(InputArray _mask) { - CV_Assert(_mask.size() == Size(imWidth,imHeight)); // mask should be same size as image + CV_Assert(_mask.size() == Size(imWidth,imHeight)); // mask should be same size as image - Mat maskImg = _mask.getMat(); + Mat maskImg = _mask.getMat(); //#pragma omp parallel - for (size_t i = 0; i < imHeight; ++i) - { + for (size_t i = 0; i < imHeight; ++i) + { //#pragma omp parallel - for (size_t j = 0; j < imWidth; ++j) - { - if (frameNum <= numInitializationFrames + 1) - { - // insert previously observed feature into the histogram. -1.0 parameter indicates training. - pixels[i*imWidth+j].insertFeature(-1.0); - if (frameNum >= numInitializationFrames+1) // training is done, normalize - { - pixels[i*imWidth+j].normalizeHistogram(); - } - } - // if mask is 0, pixel is identified as a background pixel, so update histogram. - else if (maskImg.at(i,j) == 0) - { - pixels[i*imWidth+j].insertFeature(learningRate); // updates the histogram for the next iteration. - } - } - } + for (size_t j = 0; j < imWidth; ++j) + { + if (frameNum <= numInitializationFrames + 1) + { + // insert previously observed feature into the histogram. -1.0 parameter indicates training. + pixels[i*imWidth+j].insertFeature(-1.0); + if (frameNum >= numInitializationFrames+1) // training is done, normalize + { + pixels[i*imWidth+j].normalizeHistogram(); + } + } + // if mask is 0, pixel is identified as a background pixel, so update histogram. + else if (maskImg.at(i,j) == 0) + { + pixels[i*imWidth+j].insertFeature(learningRate); // updates the histogram for the next iteration. + } + } + } } BackgroundSubtractorGMG::~BackgroundSubtractorGMG() @@ -314,8 +314,8 @@ BackgroundSubtractorGMG::~BackgroundSubtractorGMG() BackgroundSubtractorGMG::PixelModelGMG::PixelModelGMG() { - numFeatures = 0; - maxFeatures = 0; + numFeatures = 0; + maxFeatures = 0; } BackgroundSubtractorGMG::PixelModelGMG::~PixelModelGMG() @@ -325,154 +325,154 @@ BackgroundSubtractorGMG::PixelModelGMG::~PixelModelGMG() void BackgroundSubtractorGMG::PixelModelGMG::setLastObservedFeature(HistogramFeatureGMG f) { - this->lastObservedFeature = f; + this->lastObservedFeature = f; } double BackgroundSubtractorGMG::PixelModelGMG::getLikelihood(BackgroundSubtractorGMG::HistogramFeatureGMG f) { - std::list::iterator feature = histogram.begin(); - std::list::iterator feature_end = histogram.end(); + std::list::iterator feature = histogram.begin(); + std::list::iterator feature_end = histogram.end(); - for (feature = histogram.begin(); feature != feature_end; ++feature) - { - // comparing only feature color, not likelihood. See equality operator for HistogramFeatureGMG - if (f == *feature) - { - return feature->likelihood; - } - } + for (feature = histogram.begin(); feature != feature_end; ++feature) + { + // comparing only feature color, not likelihood. See equality operator for HistogramFeatureGMG + if (f == *feature) + { + return feature->likelihood; + } + } - return 0.0; // not in histogram, so return 0. + return 0.0; // not in histogram, so return 0. } void BackgroundSubtractorGMG::PixelModelGMG::insertFeature(double learningRate) { - std::list::iterator feature; - std::list::iterator swap_end; - std::list::iterator last_feature = histogram.end(); - /* - * If feature is in histogram already, add the weights, and move feature to front. - * If there are too many features, remove the end feature and push new feature to beginning - */ - if (learningRate == -1.0) // then, this is a training-mode update. - { - /* - * (1) Check if feature already represented in histogram - */ - lastObservedFeature.likelihood = 1.0; + std::list::iterator feature; + std::list::iterator swap_end; + std::list::iterator last_feature = histogram.end(); + /* + * If feature is in histogram already, add the weights, and move feature to front. + * If there are too many features, remove the end feature and push new feature to beginning + */ + if (learningRate == -1.0) // then, this is a training-mode update. + { + /* + * (1) Check if feature already represented in histogram + */ + lastObservedFeature.likelihood = 1.0; - for (feature = histogram.begin(); feature != last_feature; ++feature) - { - if (lastObservedFeature == *feature) // feature in histogram - { - feature->likelihood += lastObservedFeature.likelihood; - // now, move feature to beginning of list and break the loop - HistogramFeatureGMG tomove = *feature; - histogram.erase(feature); - histogram.push_front(tomove); - return; - } - } - if (numFeatures == maxFeatures) - { - histogram.pop_back(); // discard oldest feature - histogram.push_front(lastObservedFeature); - } - else - { - histogram.push_front(lastObservedFeature); - ++numFeatures; - } - } - else - { - /* - * (1) Scale entire histogram by scaling factor - * (2) Scale input feature. - * (3) Check if feature already represented. If so, simply add. - * (4) If feature is not represented, remove old feature, distribute weight evenly among existing features, add in new feature. - */ - *this *= (1.0-learningRate); - lastObservedFeature.likelihood = learningRate; + for (feature = histogram.begin(); feature != last_feature; ++feature) + { + if (lastObservedFeature == *feature) // feature in histogram + { + feature->likelihood += lastObservedFeature.likelihood; + // now, move feature to beginning of list and break the loop + HistogramFeatureGMG tomove = *feature; + histogram.erase(feature); + histogram.push_front(tomove); + return; + } + } + if (numFeatures == maxFeatures) + { + histogram.pop_back(); // discard oldest feature + histogram.push_front(lastObservedFeature); + } + else + { + histogram.push_front(lastObservedFeature); + ++numFeatures; + } + } + else + { + /* + * (1) Scale entire histogram by scaling factor + * (2) Scale input feature. + * (3) Check if feature already represented. If so, simply add. + * (4) If feature is not represented, remove old feature, distribute weight evenly among existing features, add in new feature. + */ + *this *= float(1.0-learningRate); + lastObservedFeature.likelihood = float(learningRate); - for (feature = histogram.begin(); feature != last_feature; ++feature) - { - if (lastObservedFeature == *feature) // feature in histogram - { - lastObservedFeature.likelihood += feature->likelihood; - histogram.erase(feature); - histogram.push_front(lastObservedFeature); - return; // done with the update. - } - } - if (numFeatures == maxFeatures) - { - histogram.pop_back(); // discard oldest feature - histogram.push_front(lastObservedFeature); - normalizeHistogram(); - } - else - { - histogram.push_front(lastObservedFeature); - ++numFeatures; - } - } + for (feature = histogram.begin(); feature != last_feature; ++feature) + { + if (lastObservedFeature == *feature) // feature in histogram + { + lastObservedFeature.likelihood += feature->likelihood; + histogram.erase(feature); + histogram.push_front(lastObservedFeature); + return; // done with the update. + } + } + if (numFeatures == maxFeatures) + { + histogram.pop_back(); // discard oldest feature + histogram.push_front(lastObservedFeature); + normalizeHistogram(); + } + else + { + histogram.push_front(lastObservedFeature); + ++numFeatures; + } + } } BackgroundSubtractorGMG::PixelModelGMG& BackgroundSubtractorGMG::PixelModelGMG::operator *=(const float &rhs) { - /* - * Used to scale histogram by a constant factor - */ - list::iterator feature; - list::iterator last_feature = histogram.end(); - for (feature = histogram.begin(); feature != last_feature; ++feature) - { - feature->likelihood *= rhs; - } - return *this; + /* + * Used to scale histogram by a constant factor + */ + list::iterator feature; + list::iterator last_feature = histogram.end(); + for (feature = histogram.begin(); feature != last_feature; ++feature) + { + feature->likelihood *= rhs; + } + return *this; } void BackgroundSubtractorGMG::PixelModelGMG::normalizeHistogram() { - /* - * First, calculate the total weight in the histogram - */ - list::iterator feature; - list::iterator last_feature = histogram.end(); - double total = 0.0; - for (feature = histogram.begin(); feature != last_feature; ++feature) - { - total += feature->likelihood; - } + /* + * First, calculate the total weight in the histogram + */ + list::iterator feature; + list::iterator last_feature = histogram.end(); + double total = 0.0; + for (feature = histogram.begin(); feature != last_feature; ++feature) + { + total += feature->likelihood; + } - /* - * Then, if weight is not 0, divide every feature by the total likelihood to re-normalize. - */ - for (feature = histogram.begin(); feature != last_feature; ++feature) - { - if (total != 0.0) - feature->likelihood /= total; - } + /* + * Then, if weight is not 0, divide every feature by the total likelihood to re-normalize. + */ + for (feature = histogram.begin(); feature != last_feature; ++feature) + { + if (total != 0.0) + feature->likelihood = float(feature->likelihood / total); + } } bool BackgroundSubtractorGMG::HistogramFeatureGMG::operator ==(HistogramFeatureGMG &rhs) { - CV_Assert(color.size() == rhs.color.size()); + CV_Assert(color.size() == rhs.color.size()); - std::vector::iterator color_a; - std::vector::iterator color_b; - std::vector::iterator color_a_end = this->color.end(); - std::vector::iterator color_b_end = rhs.color.end(); - for (color_a = color.begin(),color_b =rhs.color.begin();color_a!=color_a_end;++color_a,++color_b) - { - if (*color_a != *color_b) - { - return false; - } - } - return true; + std::vector::iterator color_a; + std::vector::iterator color_b; + std::vector::iterator color_a_end = this->color.end(); + std::vector::iterator color_b_end = rhs.color.end(); + for (color_a = color.begin(),color_b =rhs.color.begin();color_a!=color_a_end;++color_a,++color_b) + { + if (*color_a != *color_b) + { + return false; + } + } + return true; } diff --git a/modules/video/src/video_init.cpp b/modules/video/src/video_init.cpp index 04b9a8d5d..def0cd7c8 100644 --- a/modules/video/src/video_init.cpp +++ b/modules/video/src/video_init.cpp @@ -79,7 +79,7 @@ CV_INIT_ALGORITHM(BackgroundSubtractorGMG, "BackgroundSubtractor.GMG", "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.")); - + bool initModule_video(void) { bool all = true;