图像算法之九:混合高斯模型GMM

 一、 原理
      混合高斯背景建模是基于像素样本统计信息的背景表示方法,利用像素在较长时间内大量样本值的概率密度等统计信息(如模式数量、每个模式的均值和标准差)表示背景,然后使用统计差分(如3σ原则)进行目标像素判断,可以对复杂动态背景进行建模,计算量较大。
在混合高斯背景模型中,认为像素之间的颜色信息互不相关,对各像素点的处理都是相互独立的。对于视频图像中的每一个像素点,其值在序列图像中的变化可看作是不断产生像素值的随机过程,即用高斯分布来描述每个像素点的颜色呈现规律【单模态(单峰),多模态(多峰)】。

        对于多峰高斯分布模型,图像的每一个像素点按不同权值的多个高斯分布的叠加来建模,每种高斯分布对应一个可能产生像素点所呈现颜色的状态,各个高斯分布的权值和分布参数随时间更新。当处理彩色图像时,假定图像像素点R、G、B三色通道相互独立并具有相同的方差。对于随机变量X的观测数据集{x1,x2,…,xN},xt=(rt,gt,bt)为t时刻像素的样本,则单个采样点xt其服从的混合高斯分布概率密度函数:
图像算法之九:混合高斯模型GMM_第1张图片


其中k为分布模式总数,η(xt,μi,tτi,t)为t时刻第i个高斯分布,μi,t为其均值,τi,t为其协方差矩阵,δi,t为方差,I为三维单位矩阵,ωi,tt时刻第i个高斯分布的权重。

详细算法流程:



图像算法之九:混合高斯模型GMM_第2张图片
图像算法之九:混合高斯模型GMM_第3张图片


每个 GMM 由一 个 Gaussian 分布组成,每个 Gaussian 称为一个“Component”,这些 Component 线性加成在一起就组成了 GMM 的概率密度函数:

图像算法之九:混合高斯模型GMM_第4张图片                                                                     

根据上面的式子,如果我们要从 GMM 的分布中随机地取一个点的话,实际上可以分为两步:首先随机地在这  个 Component 之中选一个,每个 Component 被选中的概率实际上就是它的系数  ,选中了 Component 之后,再单独地考虑从这个 Component 的分布中选取一个点就可以了──这里已经回到了普通的 Gaussian 分布,转化为了已知的问题。

那么如何用 GMM 来做 clustering 呢?其实很简单,现在我们有了数据,假定它们是由 GMM 生成出来的,那么我们只要根据数据推出 GMM 的概率分布来就可以了,然后 GMM 的  个 Component 实际上就对应了  个 cluster 了。根据数据来推算概率密度通常被称作 density estimation ,特别地,当我们在已知(或假定)了概率密度函数的形式,而要估计其中的参数的过程被称作“参数估计”。

二、OpenCV实现

OpenCV中实现了两个版本的高斯混合背景/前景分割方法(Gaussian Mixture-based Background/Foreground Segmentation Algorithm),调用接口很明朗,效果也很好。

BackgroundSubtractorMOG 使用示例

[cpp]  view plain  copy 
  1. int main(){  
  2.     VideoCapture video("1.avi");  
  3.     Mat frame,mask,thresholdImage, output;  
  4.     video>>frame;  
  5.     BackgroundSubtractorMOG bgSubtractor(20,10,0.5,false);  
  6.     while(true){  
  7.         video>>frame;  
  8.         ++frameNum;  
  9.         bgSubtractor(frame,mask,0.001);  
  10.         imshow("mask",mask);  
  11.         waitKey(10);  
  12.     }  
  13.     return 0;  
  14. }  

构造函数可以使用默认构造函数或带形参的构造函数:

[cpp]  view plain  copy 
  1. BackgroundSubtractorMOG::BackgroundSubtractorMOG()  
  2. BackgroundSubtractorMOG::BackgroundSubtractorMOG(int history, int nmixtures,   
  3. double backgroundRatio, double noiseSigma=0)  

其中history为使用历史帧的数目,nmixtures为混合高斯数量,backgroundRatio为背景比例,noiseSigma为噪声权重。

而调用的接口只有重载操作符():

[cpp]  view plain  copy 
  1. void BackgroundSubtractorMOG::operator()(InputArray image, OutputArray fgmask, double learningRate=0)  
其中image为当前帧图像,fgmask为输出的前景mask,learningRate为背景学习速率。

以下是使用BackgroundSubtractorMOG进行前景/背景检测的一个截图。

图像算法之九:混合高斯模型GMM_第5张图片


BackgroundSubtractorMOG2 使用示例

[cpp]  view plain  copy 
  1. int main(){  
  2.     VideoCapture video("1.avi");  
  3.     Mat frame,mask,thresholdImage, output;  
  4.     //video>>frame;  
  5.     BackgroundSubtractorMOG2 bgSubtractor(20,16,true);  
  6.       
  7.     while(true){  
  8.         video>>frame;  
  9.         ++frameNum;  
  10.         bgSubtractor(frame,mask,0.001);  
  11.         cout<
  12.         //imshow("mask",mask);  
  13.         //waitKey(10);  
  14.     }  
  15.     return 0;  
  16. }  

同样的,构造函数可以使用默认构造函数和带形参的构造函数

[cpp]  view plain  copy 
  1. BackgroundSubtractorMOG2::BackgroundSubtractorMOG2()  
  2. BackgroundSubtractorMOG2::BackgroundSubtractorMOG2(int history,   
  3. float varThreshold, bool bShadowDetection=true )  

history同上,varThreshold表示马氏平方距离上使用的来判断是否为背景的阈值(此值不影响背景更新速率),bShadowDetection表示是否使用阴影检测(如果开启阴影检测,则mask中使用127表示阴影)。

使用重载操作符()调用每帧检测函数:

[cpp]  view plain  copy 
  1. void BackgroundSubtractorMOG2::operator()(InputArray image, OutputArray fgmask, double learningRate=-1)  
参数意义同BackgroundSubtractorMOG中的operator()函数。

同时BackgroundSubtractorMOG2提供了getBackgroundImage()函数用以返回背景图像:

[cpp]  view plain  copy 
  1. void BackgroundSubtractorMOG2::getBackgroundImage(OutputArray backgroundImage)  

另外OpenCV的refman中说新建对象以后还有其他和模型油有关的参数可以修改,不过比较坑的是opencv把这个这些函数参数声明为protected,同时没有提供访问接口,所以要修改的话还是要自己修改源文件提供访问接口。

[cpp]  view plain  copy 
  1. protected:  
  2.     Size frameSize;  
  3.     int frameType;  
  4.     Mat bgmodel;  
  5.     Mat bgmodelUsedModes;//keep track of number of modes per pixel  
  6.     int nframes;  
  7.     int history;  
  8.     int nmixtures;  
  9.     //! here it is the maximum allowed number of mixture components.  
  10.     //! Actual number is determined dynamically per pixel  
  11.     double varThreshold;  
  12.     // threshold on the squared Mahalanobis distance to decide if it is well described  
  13.     // by the background model or not. Related to Cthr from the paper.  
  14.     // This does not influence the update of the background. A typical value could be 4 sigma  
  15.     // and that is varThreshold=4*4=16; Corresponds to Tb in the paper.  
  16.     /////////////////////////  
  17.     // less important parameters - things you might change but be carefull  
  18.     ////////////////////////  
  19.     float backgroundRatio;  
  20.     // corresponds to fTB=1-cf from the paper  
  21.     // TB - threshold when the component becomes significant enough to be included into  
  22.     // the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.  
  23.     // For alpha=0.001 it means that the mode should exist for approximately 105 frames before  
  24.     // it is considered foreground  
  25.     // float noiseSigma;  
  26.     float varThresholdGen;  
  27.     //correspondts to Tg - threshold on the squared Mahalan. dist. to decide  
  28.     //when a sample is close to the existing components. If it is not close  
  29.     //to any a new component will be generated. I use 3 sigma => Tg=3*3=9.  
  30.     //Smaller Tg leads to more generated components and higher Tg might make  
  31.     //lead to small number of components but they can grow too large  
  32.     float fVarInit;  
  33.     float fVarMin;  
  34.     float fVarMax;  
  35.     //initial variance  for the newly generated components.  
  36.     //It will will influence the speed of adaptation. A good guess should be made.  
  37.     //A simple way is to estimate the typical standard deviation from the images.  
  38.     //I used here 10 as a reasonable value  
  39.     // min and max can be used to further control the variance  
  40.     float fCT;//CT - complexity reduction prior  
  41.     //this is related to the number of samples needed to accept that a component  
  42.     //actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get  
  43.     //the standard Stauffer&Grimson algorithm (maybe not exact but very similar)  
  44.     //shadow detection parameters  
  45.     bool bShadowDetection;//default 1 - do shadow detection  
  46.     unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result - 127 default value  
  47.     float fTau;  
  48.     // Tau - shadow threshold. The shadow is detected if the pixel is darker  
  49.     //version of the background. Tau is a threshold on how much darker the shadow can be.  
  50.     //Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow  
  51.     //See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.  

以下是使用BackgroundSubtractorMOG2检测的前景和背景:

图像算法之九:混合高斯模型GMM_第6张图片


采用GMM前景提取的方法对车辆进行跟踪:
#include 
#include 
#include 
#include 
#include 
#include 

using namespace cv;
int main()
{
	VideoCapture capture("parking.avi");
	if (!capture.isOpened())
		return 0;
	Mat frame;
	Mat foreground;
	double delay = 1000. / capture.get(CV_CAP_PROP_FPS);
	namedWindow("Original Video");
	namedWindow("Extracted Foreground");
	BackgroundSubtractorMOG mog;
	bool stop(false);
	while (!stop)
	{
		if (!capture.read(frame))
			break;
		imshow("Original Video", frame);
		mog(frame, foreground, 0.01);
		//对图像取反
		threshold(foreground, foreground, 128, 255, THRESH_BINARY_INV);
		imshow("Extracted Foreground",foreground);
		if (waitKey(delay) >= 0)
			stop = true;
	}
}
运行结果:
图像算法之九:混合高斯模型GMM_第7张图片

图像算法之九:混合高斯模型GMM_第8张图片

你可能感兴趣的:(【计算机视觉与图像处理】,【计算机视觉与模式识别】)