(转载)http://blog.csdn.net/spritsu/article/details/2866018
在智能监控系统中,对于运动目标的检测是中心内容,而在运动目标检测提取中,背景目标对于目标的识别和跟踪至关重要。而建模正是背景目标提取的一个重要环节。
我们首先要提起背景和前景的概念,前景是指在假设背景为静止的情况下,任何有意义的运动物体即为前景。建模的基本思想是从当前帧中提取前景,其目的是使背景更接近当前视频帧的背景。即利用当前帧和视频序列中的当前背景帧进行加权平均来更新背景,但是由于光照突变以及其他外界环境的影响,一般的建模后的背景并非十分干净清晰,而高斯混合模型是是建模最为成功的方法之一。
混合高斯模型使用K(基本为3到5个) 个高斯模型来表征图像中各个像素点的特征,在新一帧图像获得后更新混合高斯模型,用当前图像中的每个像素点与混合高斯模型匹配,如果成功则判定该点为背景点, 否则为前景点。通观整个高斯模型,他主要是有方差和均值两个参数决定,,对均值和方差的学习,采取不同的学习机制,将直接影响到模型的稳定性、精确性和收敛性。由于我们是对运动目标的背景提取建模,因此需要对高斯模型中方差和均值两个参数实时更新。为提高模型的学习能力,改进方法对均值和方差的更新采用不同的学习率;为提高在繁忙的场景下,大而慢的运动目标的检测效果,引入权值均值的概念,建立背景图像并实时更新,然后结合权值、权值均值和背景图像对像素点进行前景和背景的分类。具体更新公式如下:
μt= (1 - ρ)μt- 1 +ρxt (1)
σ2t = (1 - ρ)σ2t- 1 +ρ( xt -μt ) T ( xt -μt ) (2)
ρ =αη( xt | μκ,σκ ) (3)
| xt -μt - 1 | ≤ 2. 5σt- 1 (4)
w k , t = (1 - α) w k , t - 1 +αMk , t (5)
式中ρ为学习率,即反映当前图像融入背景的速率。
建模过程中,我们需要对混合高斯模型中的方差、均值、权值等一些参数初始化,并通过这些参数求出建模所需的数据,如马兹距离。在初始化过程中,一般我们将方差设置的尽量大些(如15),而权值则尽量小些(如0.001)。 这样设置是由于初始化的高斯模型是一个并不准确,可能的模型,我们需要不停的缩小他的范围,更新他的参数值,从而得到最可能的高斯模型,将方差设置大些,就是为了将尽可能多的像素包含到一个模型里面,从而获得最有可能的模型。部分代码如下:
- for(i=0; i<K_MODELS; i++) //K_MODELS为预先定义的模型数
- {
- // calculate the vector, v = (X - u)
- for(j=0; j<3; j++) v[j] = pixel[j] - model[i]->mean[j];
- // calculate the squared distance, d = |v|^2
- model[i]->dist2 = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- // zot: this is only equal to mahalanobis distance
- // when covariance matrix = vI
- // (v = scalar variance for all channels)
- model[i]->mah2 = model[i]->dist2 / model[i]->var; //即为马兹距离
- // see if X is close enough to this model
- if (model[i]->mah2 < SFSquared) break; // the current pixel matches one of the K models
- //SFSquared是预定义的值
- }
- 同时这时又产生了一个疑问,那么如何得知我们的模型是否超过预定义的模型数了呢?这便是我们设置权值的其中一个原因了。根据大量的试验,我们得出当前面几个模型数的权值之和在T值(一般设为0.75)之内时,效果最好,因此当我们将前面的模型权值相加,当超过0.75时便舍去后面的模型。当然其中还有一个重要的问题,我们是如何得知前面的模型是相对来说最有可能的模型,而非被舍去的模型呢?在这里我们首先要对各个模型的权值进行排序,按照权值与方差的比率的从大到小,对模型进行排序。由于一开始建立的模型肯定是不可靠的,在最后基本会被舍弃,因此我们在初始化的时候将初始模型的方差尽量大,而权值尽量小,从而使最不可能的模型排在比较后面。
- 到这里为止,混合高斯模型的建模基本完成,我在归纳一下其中的流程,首先初始化预先定义的几个高斯模型,对高斯模型中的参数进行初始化,并求出之后将要用到的参数。其次,对于每一帧中的每一个像素进行处理,看其是否匹配某个模型,若匹配,则将其归入该模型中,并对该模型根据新的像素值进行更新,若不匹配,则以该像素建立一个高斯模型,初始化参数,代理原有模型中最不可能的模型。最后选择前面几个最有可能的模型作为背景模型,为背景目标提取做铺垫。
=========================
以下代码来自 http://www.opencv.org.cn/index.php/%E9%AB%98%E6%96%AF%E8%83%8C%E6%99%AF%E5%BB%BA%E6%A8%A1
#include <stdio.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <cvaux.h>//必须引此头文件
int main( int argc, char** argv )
{
IplImage* pFrame = NULL;
IplImage* pFrImg = NULL;
IplImage* pBkImg = NULL;
CvCapture* pCapture = NULL;
int nFrmNum = 0;
cvNamedWindow("video", 1);
cvNamedWindow("background",1);
cvNamedWindow("foreground",1);
cvMoveWindow("video", 30, 0);
cvMoveWindow("background", 360, 0);
cvMoveWindow("foreground", 690, 0);
if( argc > 2 )
{
fprintf(stderr, "Usage: bkgrd [video_file_name]\n");
return -1;
}
//打开视频文件
if(argc == 2)
if( !(pCapture = cvCaptureFromFile(argv[1])))
{
fprintf(stderr, "Can not open video file %s\n", argv[1]);
return -2;
}
//打开摄像头
if (argc == 1)
if( !(pCapture = cvCaptureFromCAM(-1)))
{
fprintf(stderr, "Can not open camera.\n");
return -2;
}
//初始化高斯混合模型参数
CvGaussBGModel* bg_model=NULL;
while(pFrame = cvQueryFrame( pCapture ))
{
nFrmNum++;
if(nFrmNum == 1)
{
pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,3);
pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
//高斯背景建模,pFrame可以是多通道图像也可以是单通道图像
//cvCreateGaussianBGModel函数返回值为CvBGStatModel*,
//需要强制转换成CvGaussBGModel*
bg_model = (CvGaussBGModel*)cvCreateGaussianBGModel(pFrame, 0);
}
else
{
//更新高斯模型
cvUpdateBGStatModel(pFrame, (CvBGStatModel *)bg_model );
//pFrImg为前景图像,只能为单通道
//pBkImg为背景图像,可以为单通道或与pFrame通道数相同
cvCopy(bg_model->foreground,pFrImg,0);
cvCopy(bg_model->background,pBkImg,0);
//把图像正过来
pBkImg->origin=1;
pFrImg->origin=1;
cvShowImage("video", pFrame);
cvShowImage("background", pBkImg);
cvShowImage("foreground", pFrImg);
if( cvWaitKey(2) >= 0 )
break;
}
}
//释放高斯模型参数占用内存
cvReleaseBGStatModel((CvBGStatModel**)&bg_model);
cvDestroyWindow("video");
cvDestroyWindow("background");
cvDestroyWindow("foreground");
cvReleaseImage(&pFrImg);
cvReleaseImage(&pBkImg);
cvReleaseCapture(&pCapture);
return 0;
}