您的位置:首页 > 其它

混合高斯背景建模

2010-07-22 17:31 148 查看
摘自:http://caimingdong2008.blog.163.com/blog/static/50452429200811711059396/



#include <stdio.h>

#include <cv.h>

#include <cxcore.h>

#include <highgui.h>

#include <cvaux.h>//必须引此头文件

void main( )

{

//参数初始化定义

IplImage* pFrame = NULL;

IplImage* pFrImg = NULL;

IplImage* pBkImg = NULL;

CvCapture* pCapture = NULL;

IplImage* origin_rgb = NULL ;//定义rgb空间的存储

IplImage* origin_ycc = NULL ;//定义转换成YCrCb空间的存储

IplImage* lumi = NULL ;//定义亮度分量的存储空间



//定义窗口

cvNamedWindow("lumi",1);//定义显示窗口的名字,显示原始的视频

cvMoveWindow("lumi",30,0);//定义显示窗口的位置

cvNamedWindow("background",1);//显示经过转换格式的视频

cvMoveWindow("background",360,0);

cvNamedWindow("foreground",1);//显示经过亮度提取的视频

cvMoveWindow("foreground",690,0);



//读取一帧视频文件作为初始化

pCapture = cvCaptureFromFile("video.long.xvid.avi") ;

pFrame = cvQueryFrame(pCapture);

int i ;

for (i=0;i<2;i++)

{

pFrame = cvQueryFrame(pCapture);

}

//RGB转换成亮度

origin_rgb = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 3 );

origin_ycc = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 3 );

lumi = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1 );

pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1 );

pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1 );



//origin_rgb = cvCloneImage(pFrame) ;//或者 cvCopy(pFrame,origin_rgb,NULL) ;

cvCopy(pFrame,origin_rgb,NULL) ;//复制视频

cvCvtColor(origin_rgb,origin_ycc,CV_BGR2YCrCb) ; //实现视频格式转换

cvSplit(origin_ycc,lumi,NULL,NULL,NULL); //获取亮度分量



//为高斯模型设置初时参数

CvGaussBGStatModelParams* params = new CvGaussBGStatModelParams;

params->win_size = 50;

params->n_gauss = 3;

params->bg_threshold = 0.7;

params->std_threshold = 3.5;

params->minArea = 15;

params->weight_init = 0.333;

params->variance_init = 30;



CvBGStatModel* bgModel = cvCreateGaussianBGModel(lumi,params);



int key=-1;

while(key != 'q')

{

//获取下一帧视频

pFrame = cvQueryFrame(pCapture);

cvCopy(pFrame,origin_rgb,NULL) ;//复制视频

cvCvtColor(origin_rgb,origin_ycc,CV_BGR2YCrCb) ; //实现视频格式转换

cvSplit(origin_ycc,lumi,NULL,NULL,NULL); //获取亮度分量

if( !pFrame )

break;



//更新高斯模型

cvUpdateBGStatModel(lumi,bgModel);

pFrImg = bgModel->foreground ;//前景图象

pBkImg = bgModel->background ; //背景图象



//将图象倒转过来

pBkImg->origin = 1 ;

pFrImg->origin = 1 ;

lumi->origin = 1 ;

//显示结果

cvShowImage("lumi",lumi);

cvShowImage("background",pBkImg);

cvShowImage("foreground",pFrImg);

key = cvWaitKey(10);

}

// cvWaitKey(0) ;//窗口的回调函数,必须要的,不然窗口的显示会不正常

//释放窗口内存资源

cvDestroyWindow("lumi");

cvDestroyWindow("background");

cvDestroyWindow("foreground");

//释放图象占用的内存资源

cvReleaseImage(&lumi);

cvReleaseImage(&pBkImg);

cvReleaseImage(&pFrImg);

cvReleaseCapture(&pCapture);

cvReleaseBGStatModel( &bgModel );

}

创建高斯背景模型

cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters )

{

//CvGaussBGModel在cvaux.h中有定义,是一个结构体

CvGaussBGModel* bg_model = 0;



CV_FUNCNAME( "cvCreateGaussianBGModel" );//在cxerror.h定义,定义cvFuncName宏变量

//cvFuncName定义为和函数名称相同cvCreateGaussianBGModel



__BEGIN__;//开始处理(是必须接在这个CV_FUNCNAME之后的)



double var_init;

CvGaussBGStatModelParams params;//定义初始化变量,在cvaux.h中定义的结构体CvGaussBGStatModelParams

int i, j, k, n, m, p;



//init parameters

if( parameters == NULL )

{

params.win_size = CV_BGFG_MOG_WINDOW_SIZE;//CV_BGFG_MOG_WINDOW_SIZE=200,和学习率的关系1/200=0.005

params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD;//CV_BGFG_MOG_BACKGROUND_THRESHOLD=0.7(判断是否为背景点的阈值)

params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD;//CV_BGFG_MOG_STD_THRESHOLD=2.5(标准阈值)

params.weight_init = CV_BGFG_MOG_WEIGHT_INIT;//CV_BGFG_MOG_WEIGHT_INIT=0.05(权值)

params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT;//CV_BGFG_MOG_SIGMA_INIT=30(方差)

params.minArea = CV_BGFG_MOG_MINAREA;//CV_BGFG_MOG_MINAREA=15.f(这个不知道?)

params.n_gauss = CV_BGFG_MOG_NGAUSSIANS;//CV_BGFG_MOG_NGAUSSIANS=5(高斯模型数量)

}

else

{

params = *parameters;

}

//CV_IS_IMAGE在cxtypes.h中定义,在这里估计是判断是否有读入图象帧

//CV_StsBadArg=-5,代表函数有问题,或者输入的参数有问题

if( !CV_IS_IMAGE(first_frame) )

CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );



//CV_CALL在cxerror.h中有定义,这里用来确认一下调用是否正确

CV_CALL( bg_model = (CvGaussBGModel*)cvAlloc( sizeof(*bg_model) ));

memset( bg_model, 0, sizeof(*bg_model) );

bg_model->type = CV_BG_MODEL_MOG;//这个在cvGaussBGModel中定义的CV_BG_STAT_MODEL_FIELDS()函数中都有,存在type,release,update,foreground,background等

bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel;

bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel;



bg_model->params = params;



//分配存储空间

CV_CALL( bg_model->g_point = (CvGaussBGPoint*)cvAlloc(sizeof(CvGaussBGPoint)*

((first_frame->width*first_frame->height) + 256)));//这个是参与的点数,以及存放这些点需要的空间

CV_CALL( bg_model->background = cvCreateImage(cvSize(first_frame->width,

first_frame->height), IPL_DEPTH_8U, first_frame->nChannels));//给背景分配存储空间

CV_CALL( bg_model->foreground = cvCreateImage(cvSize(first_frame->width,

first_frame->height), IPL_DEPTH_8U, 1));//给前景分配存储空间



CV_CALL( bg_model->storage = cvCreateMemStorage());//分配存储空间



//初始化

var_init = 2 * params.std_threshold * params.std_threshold;

CV_CALL( bg_model->g_point[0].g_values =

(CvGaussBGValues*)cvAlloc( sizeof(CvGaussBGValues)*params.n_gauss*

(first_frame->width*first_frame->height + 128)));//这个是给g_value分配足够的存储空间



//程序说明

//g_values[0],g_values[1],g_values[2]存放3个高斯混合模型的变量

//g_values[].weight(权重) g_values[].mean[](均值) g_values[].variance[](方差)

//具体安排是每一个象素点都有3个模型,

//然后每一个象素点的三个模型

//模型0的权重为1,方差为2倍的标准差的平方,均值为当前象素点的值

//模型1的权重为0,方差为2倍的标准差的平方,均值为0

//模型2的权重为0,方差为2倍的标准差的平方,均值为0

//g_point指的是参加高斯背景建模的象素点的个数

for( i = 0, p = 0, n = 0; i < first_frame->height; i++ )

{

for( j = 0; j < first_frame->width; j++, n++ )

{

bg_model->g_point
.g_values =

bg_model->g_point[0].g_values + n*params.n_gauss;

bg_model->g_point
.g_values[0].weight = 1; //the first value seen has weight one

bg_model->g_point
.g_values[0].match_sum = 1;

for( m = 0; m < first_frame->nChannels; m++)

{

bg_model->g_point
.g_values[0].variance[m] = var_init;

bg_model->g_point
.g_values[0].mean[m] = (unsigned char)first_frame->imageData[p + m];

}

for( k = 1; k < params.n_gauss; k++)

{

bg_model->g_point
.g_values[k].weight = 0;

bg_model->g_point
.g_values[k].match_sum = 0;

for( m = 0; m < first_frame->nChannels; m++){

bg_model->g_point
.g_values[k].variance[m] = var_init;

bg_model->g_point
.g_values[k].mean[m] = 0;

}

}

p += first_frame->nChannels;

}

}



bg_model->countFrames = 0;



__END__;



if( cvGetErrStatus() < 0 )

{

CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model;



if( bg_model && bg_model->release )

bg_model->release( &base_ptr );

else

cvFree( &bg_model );

bg_model = 0;

}



return (CvBGStatModel*)bg_model;

}

这整个函数就是对结构体cvGaussBGModel里面的参数:CV_BG_STAT_MODEL_FIELDS(),params,g_point,countFrames赋值,实际上也是可以把其复制过来,自己修改初时的参数。





高斯背景模型

运动检测的一般方法

目前,运动物体检测的问题主要分为两类,摄像机固定和摄像机运动。对于摄像机运动的运动物体检测问题,比较著名的解决方案是光流法,通过求解偏微分方程求的图像序列的光流场,从而预测摄像机的运动状态。对于摄像机固定的情形,当然也可以用光流法,但是由于光流法的复杂性,往往难以实时的计算,所以我采用高斯背景模型。因为,在摄像机固定的情况下,背景的变化是缓慢的,而且大都是光照,风等等的影响,通过对背景建模,对一幅给定图像分离前景和背景,一般来说,前景就是运动物体,从而达到运动物体检测的目的。

单分布高斯背景模型


单分布高斯背景模型认为,对一个背景图像,特定像素亮度的分布满足高斯分布,即对背景图像B,(x,y)点的亮度满足:

IB(x,y) ~ N(u,d)

这样我们的背景模型的每个象素属性包括两个参数:平均值u 和 方差d。

对于一幅给定的图像G,如果 Exp(-(IG(x,y)-u(x,y))^2/(2*d^2)) > T,认为(x,y)是背景点,反之是前景点。

同时,随着时间的变化,背景图像也会发生缓慢的变化,这时我们要不断更新每个象素点的参数

u(t+1,x,y) = a*u(t,x,y) + (1-a)*I(x,y)

这里,a称为更新参数,表示背景变化的速度,一般情况下,我们不更新d(实验中发现更不更新d,效果变化不大)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: