OpenCV: Background difference method for video using Gaussian mixture model (GMM) source

Source: Internet
Author: User

Thank you very much, thefutureisour. The source code of the C + + version of the OPENCV is fully commented on, the direct use of the OPENCV source code programming is relatively few, but want to optimize the Gaussian mixture model, or to be in the paper to the Gaussian mixture model has been innovative, You must use the OPENCV source code to program, and not just use the OpenCV source interface to call modify parameters. To waste some of their brains to provide users with a communication ,

1, MY_BACKGROUND_SEGM.HPP

#include "opencv2/core/core.hpp" #include <list> #include "opencv2/video/background_segm.hpp"// Find the location of the file in your own installation package namespace cv{class Cv_exports_w my_backgroundsubtractormog:public backgroundsubtractor {Pub LIC://!         The default constructor cv_wrap My_backgroundsubtractormog (); //!  The full constructor this takes the length of the history, the number of Gaussian mixtures, the background ratio parameter and the Noise strength cv_wrap my_backgroundsubtractormog (int history, int nmixtures, double backgroundratio, Dou         ble noisesigma=0); //!         The destructor virtual ~my_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://public:size framesize;         int frametype;         Mat Bgmodel;         int nframes;         int history;         int nmixtures;         Double Varthreshold;         Double Backgroundratio;     Double Noisesigma; };}

2, My_background_segm.cpp

#include "my_background_segm.hpp" using namespace cv;static const int defaultnmixtures = 5;//default number of mixed models static const int DEFA Ulthistory = 200;//Default History frame number static const double Defaultbackgroundratio = 0.7;//default background threshold static Const double Defaultvarthreshold = 2.5*2.5;//Default variance threshold static const double DEFAULTNOISESIGMA = 30*0.5;//default noise variance static const double    Defaultinitialweight = 0.05;//Default initial weight//constructor without parameters, use default value My_backgroundsubtractormog::my_backgroundsubtractormog () {    Framesize = Size (0,0);        Frametype = 0;    Nframes = 0;    Nmixtures = Defaultnmixtures;    History = Defaulthistory;    Varthreshold = Defaultvarthreshold;    Backgroundratio = Defaultbackgroundratio; Noisesigma = Defaultnoisesigma;}                                                 A constructor with parameters, using parameters to pass in values My_backgroundsubtractormog::my_backgroundsubtractormog (int _history, int _nmixtures, Double _backgroundratio, double _noises    Igma) {framesize = Size (0,0);        Frametype = 0; NfrAmes = 0; nmixtures = min (_nmixtures > 0? _nmixtures:defaultnmixtures, 8);//not more than 8, otherwise the default history = _history > 0? _history:defaulthistory;//cannot be less than 0, otherwise the default Varthreshold = defaultvarthreshold;//threshold is used with the default backgroundratio = Min (_backgr Oundratio > 0? _backgroundratio:0.95, 1.);//background threshold must be greater than 0, less than 1, otherwise use 0.95 noisesigma = _noisesigma <= 0? Defaultnoisesigma: _noisesigma;//noise threshold greater than 0} my_backgroundsubtractormog::~my_backgroundsubtractormog () {}void My_    Backgroundsubtractormog::initialize (Size _framesize, int _frametype) {framesize = _framesize;    Frametype = _frametype;        Nframes = 0;    int nchannels = CV_MAT_CN (Frametype);        Cv_assert (cv_mat_depth (frametype) = = cv_8u); For each Gaussian mixture of each pixel BG model we store ...//the mixture sort key (w/sum_of_variances), the Mixt Ure weight (W),///mean (Nchannels values) and//The diagonal covariance matrix (another nchannels values) b Gmodel.create (1, FRAMESIZE.HEIGHT*FRAmesize.width*nmixtures* (2 + 2*nchannels), cv_32f);//Initialize a 1 row *xx column Matrix//XX is calculated as follows: the number of rows * columns * of the image mixed model * (1 (priority) + 1 (weight) + 2 (mean + Variance) * Number of Channels) Bgmodel = Scalar::all (0);//Clear 0}//set as the template, is to take into account the color image and grayscale image of the two cases Template<typename vt> struct mixdata{f    Loat SortKey;    float weight;    VT mean;    VT var;}; static void Process8uc1 (const mat& image, mat& fgmask, double learningrate, mat& Bgmo  del, int nmixtures, double backgroundratio, double varthreshold, double noisesigma) {int x, Y,    K, k1, rows = image.rows, cols = Image.cols; float alpha = (float) learningrate, T = (float) backgroundratio, VT = (float) varthreshold;//learning rate, background threshold, variance threshold int K = Nmixtu        res;//Mixed model number mixdata<float>* Mptr = (mixdata<float>*) bgmodel.data; const float W0 = (float) defaultinitialweight;//initial weight const float Sk0 = (float) (w0/(defaultnoisesigma*2));//Initial priority cons t float var0 = (float) (defaultnoisesigma*defaultnoisesigma*4);//Initial Variance CoNST float Minvar = (float) (noisesigma*noisesigma);//minimum variance for (y = 0; y < rows; y++) {const uchar* SR        c = image.ptr<uchar> (y);                uchar* DST = fgmask.ptr<uchar> (y);                if (Alpha > 0)//If the learning rate is 0, then the degradation is the background subtraction {for (x = 0; x < cols; Mptr + = K) {                float wsum = 0; FLOAT pix = src[x];//per pixel int kHit =-1, Kforeground = -1;//Whether it belongs to the model, whether it belongs to the foreground fo                    R (k = 0; k < K; k++)//each Gaussian model {float w = mptr[k].weight;//weight of the current model                    Wsum + = w;//weight accumulation if (W < Flt_epsilon) break;  float mu = mptr[k].mean;//current model mean value float var = mptr[k].var;//variance of current model float diff = pix                     -mu;//The difference between the current pixel and the model mean float D2 = diff*diff;//squared if (D2 < Vt*var)//is less than the square threshold, that is, whether it belongs to the model    {                    Wsum-= w;//if matched, subtract it, since it will update float DW = alpha* (1.f-w); Mptr[k].weight = w + dw;//Increase weight//Note the portion of the source article that deals with probabilities is simplified, changing the probability to 1 Mptr[k].mean = mu + alpha*diff;//correction                        Mean var = max (var + alpha* (D2-var), minvar);//start Fangchaqing 00, so use the noise variance as the default variance, otherwise use the previous variance Mptr[k].var = var;//correction Variance Mptr[k].sortkey = W/sqrt (var);//recalculate priority, it seems wrong here, should use the updated Mptr[k].weig HT instead of W for (k1 = k-1; K1 >= 0; k1--)//starting from a matching K-model, if the updated Gaussian model takes precedence over his The previous one, then the interchange order {if (Mptr[k1].sortkey >= mptr[k1+1].sortkey)//If the priority does not occur                            Change, then stop comparing break;                                                Std::swap (Mptr[k1], mptr[k1+1]);//exchange their order, always guarantee the highest priority in front}             KHit = k1+1;//record belongs to which model break;       }} if (KHit < 0)//No appropriate Gaussian mixture found at all , remove the weakest mixture and create a new one//the current pixel does not belong to any one of the models {//Initializes a newer model kHit = k =                    Min (k, K-1);//There are two cases, when the initial initialization, K is not equal to K-1 wsum + = w0-mptr[k].weight;//expediency value of the sum of the total minus the original model, plus the default weight Mptr[k].weight = w0;//initialization Weight Mptr[k].mean = pix;//initialization mean Mptr[k].var = var0  ;//Initialize Variance Mptr[k].sortkey = sk0;//initialization weight} else for (; k < K; k++) Wsum + = mptr[k].weight;//to find the remaining total weight value float Wscale = 1.f/wsum;//                wsum = 0;                    for (k = 0; k < K; k++) {wsum + = Mptr[k].weight *= Wscale; Mptr[k].sortkey *= wscale;//Calculate normalized weights if (wsum > T && kforeground < 0 Kforeground = k+1;//After the first few models are awarded the foreground} Dst[x] = (ucha            R) (-(KHit >= kforeground));//Verdict: (Ucahr) (-true) = 255; (Uchar) (-(false)) = 0;            }} else//If the learning rate is less than or equal to 0, there is no background update process, and the other process is similar to {for (x = 0; x < cols; + +, mptr + K)                {float pix = src[x];                                int kHit =-1, kforeground =-1;                        for (k = 0; k < K; k++) {if (Mptr[k].weight < Flt_epsilon)                    Break                    float mu = mptr[k].mean;                    float var = mptr[k].var;                    float diff = Pix-mu;                    float D2 = Diff*diff;                        if (D2 < Vt*var) {kHit = k;                    Break               }} if (KHit >= 0) {     float wsum = 0;                        for (k = 0; k < K; k++) {wsum + = Mptr[k].weight;                            if (Wsum > T) {kforeground = k+1;                        Break }}} Dst[x] = (UCHAR) (KHit < 0 | | kHit >= Kforegro Und?            255:0);                         }}}} static void Process8uc3 (const mat& image, mat& fgmask, double learningrate, mat& Bgmodel, int nmixtures, double backgroundratio, double varthreshold, double noises    IGMA) {int x, y, K, k1, rows = image.rows, cols = Image.cols;    float alpha = (float) learningrate, T = (float) backgroundratio, VT = (float) varthreshold;        int K = Nmixtures;    const float W0 = (float) defaultinitialweight;    const float Sk0 = (float) (W0/(Defaultnoisesigma*2*sqrt (3.))); COnst float var0 = (float) (defaultnoisesigma*defaultnoisesigma*4);    const float Minvar = (float) (NOISESIGMA*NOISESIGMA);        mixdata<vec3f>* mptr = (mixdata<vec3f>*) bgmodel.data;        for (y = 0; y < rows; y++) {const uchar* src = image.ptr<uchar> (y);                uchar* DST = fgmask.ptr<uchar> (y); if (Alpha > 0) {for (x = 0; x < cols; + x, mptr + = K) {Float wsum =                0;                vec3f pix (Src[x*3], src[x*3+1], src[x*3+2]);                                int kHit =-1, kforeground =-1;                    for (k = 0; k < K; k++) {Float w = mptr[k].weight;                    Wsum + = W;                    if (W < Flt_epsilon) break;                    vec3f mu = Mptr[k].mean;                    vec3f var = mptr[k].var;                    vec3f diff = Pix-mu;                 float D2 = Diff.dot (diff);   if (D2 < vt* (Var[0] + var[1] + var[2])) {wsum-= W;                        Float DW = alpha* (1.f-w);                        Mptr[k].weight = w + DW;                        Mptr[k].mean = mu + alpha*diff; var = vec3f (Max (var[0] + alpha* (diff[0]*diff[0]-var[0]), Minvar), Max (var[1] + alpha* (Diff[1]*diff[1]-var[1]), Minvar), Max (var[2] + alpha* (diff[2]*diff[2]-var[2]), min                        Var));                        Mptr[k].var = var;                                                Mptr[k].sortkey = W/sqrt (var[0] + var[1] + var[2]); for (k1 = k-1; K1 >= 0; k1--) {if (Mptr[k1].sortkey >= mptr[k1+1                            ].sortkey) break;                        Std::swap (Mptr[k1], mptr[k1+1]);                                                }KHit = k1+1;                    Break }} if (KHit < 0)//No appropriate Gaussian mixture found at all, Remov                    E The weakest mixture and create a new one {kHit = k = min (k, K-1);                    Wsum + = W0-mptr[k].weight;                    Mptr[k].weight = W0;                    Mptr[k].mean = pix;                    Mptr[k].var = vec3f (var0, var0, var0);                Mptr[k].sortkey = Sk0;                            } else for (; k < K; k++) Wsum + = Mptr[k].weight;                float Wscale = 1.f/wsum;                wsum = 0;                    for (k = 0; k < K; k++) {wsum + = Mptr[k].weight *= Wscale;                    Mptr[k].sortkey *= Wscale;                if (Wsum > T && kforeground < 0) Kforeground = k+1;} Dst[x] = (Uchar) (-(KHit >= kforeground)); }} else {for (x = 0; x < cols; + x, Mptr + K) {vec3f pix                (Src[x*3], src[x*3+1], src[x*3+2]);                                int kHit =-1, kforeground =-1;                        for (k = 0; k < K; k++) {if (Mptr[k].weight < Flt_epsilon)                    Break                    vec3f mu = Mptr[k].mean;                    vec3f var = mptr[k].var;                    vec3f diff = Pix-mu;                    float D2 = Diff.dot (diff);                        if (D2 < vt* (Var[0] + var[1] + var[2])) {kHit = k;                    Break                    }} if (KHit >= 0) {float wsum = 0; for (k = 0; k < K; k++) {WSUM + = Mptr[k].weight;                            if (Wsum > T) {kforeground = k+1;                        Break }}} Dst[x] = (UCHAR) (KHit < 0 | | kHit >= Kforegro Und?            255:0);    }}}}void My_backgroundsubtractormog::operator () (Inputarray _image, Outputarray _fgmask, double learningRate) {    Mat image = _image.getmat (); BOOL Needtoinitialize = Nframes = = 0 | | Learningrate >= 1 | | Image.size ()! = Framesize | |        Image.type ()! = frametype;//need to initialize if (needtoinitialize) Initialize (Image.size (), Image.type ());//initialization    Cv_assert (image.depth () = = cv_8u);    _fgmask.create (Image.size (), cv_8u);        Mat fgmask = _fgmask.getmat ();    ++nframes; learningrate = learningrate >= 0 && nframes > 1?    Learningrate:1./min (nframes, history);        Cv_assert (learningrate >= 0); If(Image.type () = = CV_8UC1)//Processing grayscale image process8uc1 (image, Fgmask, Learningrate, Bgmodel, Nmixtures, Backgroundratio,    Varthreshold, Noisesigma); else if (image.type () = = CV_8UC3)//Processing color image process8uc3 (image, Fgmask, Learningrate, Bgmodel, nmixtures, background    Ratio, Varthreshold, Noisesigma); else Cv_error (Cv_stsunsupportedformat, "only 1-and 3-channel 8-bit images is supported in My_backgroundsubtracto    Rmog ");} //}

3, Main.cpp

#include <iostream> #include <string> #include <opencv2/opencv.hpp> #include "my_background_segm.hp P "//self-defined header file, the default is to call the OpenCV self-contained GMM related functions, so this article redefine a different class using namespace Cv;using namespace Std;int count_frame = 0;int m  Ain () {Videocapture capture ("3.avi");    if (!capture.isopened ()) {cout<< "read video failed" <<endl;  return-1;  }//Get the entire frame number long Totalframenumber = Capture.get (Cv_cap_prop_frame_count);  cout<< "Total video" <<totalFrameNumber<< "Frame" <<endl;  Set start frame () long frametostart = 1;  Capture.set (Cv_cap_prop_pos_frames,frametostart);  cout<< "Start reading from" <<frameToStart<< "<<endl;  Set End frame int frametostop = 650; if (Frametostop < Frametostart) {cout<< "end frame is less than start frame, program error, exiting soon!    "<<endl;  return-1;  } else {cout<< "End frame is:" <<frameToStop<< "Frame" <<endl;  } Double rate = Capture.get (cv_cap_prop_fps);  int delay = 1000/rate;  Mat frame;  foreground picture Mat foreground;  Mat Gmm_gray; MaT Gmm_canny;   Use the default parameters to call the mixed Gaussian model My_backgroundsubtractormog Mog;  Use your own defined Gaussian mixture Model class bool Stop (FALSE);  Currentframe is a variable that controls the loop end after reading to a specified frame in the loop body long currentframe = Frametostart;    while (!stop) {count_frame + +;      if (!capture.read (frame) {cout<< "failed to read image from video or finished reading entire video" <<endl;    Return-2;     } cvtcolor (Frame,gmm_gray,cv_rgb2gray);//canny (gmm_gray,gmm_canny,50,150,3);    Imshow ("Gmm_canny", Gmm_canny);    Imshow ("Input video", frame); Parameters are: Input image, output image, learning rate//mog (gmm_canny,foreground,0.01); Mog (gmm_gray,foreground,0.01);//cout<<mog.nframes    << "";    Imshow ("foreground", foreground); Medianblur (foreground,foreground,3); Imshow ("foreground after median filtering", foreground);    Press the ESC key to exit, press the other key to stop at the current frame int c = Waitkey (delay);    if (char) c = = | | currentframe >= frametostop) {stop = true;    } if (c >= 0) {waitkey (0);  } currentframe++; } waitkey (0);}


It is said to use a cmake OPENCV source code to operate, I did not yo use, also said CMake quite simple, if there are users can put forward a better method ha


OpenCV: Background difference method for video using Gaussian mixture model (GMM) source

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.