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