背景建模法是一种简单、快速但是背景的多模态(比如光照强度的变化、树叶的摇动等)比较敏感的一种背景建模方法。其基本思想是计算每个像素上的平均值作为基本模型,然后将当前像素值和背景像素值进行比较,当他们之间的差值小于某个特定的阈值TH时,则该像素可以被认为是背景像素,否则被认为是前景目标像素。其中,阈值TH可以自己根据经验设定,也可以采用自适应算法进行确定。可以很容易看出,这种方法对于背景的突发变化很敏感,而且实验证明,它对于和背景颜色相近的前景目标的检测效果也不理想,仅可作为参考。
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace std;
int main()
{
cvNamedWindow("video");
cvNamedWindow("avg");
cvNamedWindow("sub");
cvMoveWindow("video",0,0);
cvMoveWindow("avg",330,0);
cvMoveWindow("sub",660,0);
CvCapture *capture=NULL;
capture=cvCaptureFromFile("video.avi");
IplImage *pFrame=NULL;
IplImage* pFrImg = NULL;
IplImage* pBkImg = NULL;
CvMat* pFrameMat = NULL;
CvMat* pFrMat = NULL;
CvMat* pBkMat = NULL;
int numfrm=0;
while(pFrame=cvQueryFrame(capture))
{
numfrm++;
if(numfrm==1)
{
pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
cvCvtColor(pFrame,pBkImg,CV_BGR2GRAY);
pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
//cvConvert函数用于图像和矩阵之间的相互转换 为什么要用cvConvert 把IplImage转为矩阵? 因为IplImage里的数据,你只能用uchar的形式存放,
//当你需要这些图像数据看作数据矩阵来运算时,0~255的精度显然满足不了要求; 然而CvMat里却可以存放任意通道数、任意格式的数据,
//这个机制方便了研究中的这种需求,转化为矩阵就可以进行更自由的计算。
cvConvert(pBkImg, pFrMat);
cvConvert(pBkImg, pBkMat);
cvRunningAvg(pFrMat,pBkMat,0.005,0);
cvConvert(pBkMat, pBkImg);
cvShowImage("avg",pBkImg);
if(cvWaitKey(20)==27)
return -1;
}
else
{
cvCvtColor(pFrame,pBkImg,CV_BGR2GRAY);
cvConvert(pBkImg, pFrMat);
// cvRunningAvg函数是opencv库中的一个函数。
// 作用:用来更新移动平均。
// 函数形式:
// void cvRunningAvg(const CvArr * image, CvArr* acc, double alpha, const CvArr* mask=NULL)
// 参数说明:
// image:输入图像,1或3通道,8比特或32比特的float型
// acc:累加器,和image一样大小
// alpha:更新时,image所占的权重
// mask:操作符掩码
// if mask(x,y)!= 0 (1-alpha)*acc(x,y)+alpha*image(x,y) =>acc(x,y)
// cvRunningAvg();
cvRunningAvg(pFrMat,pBkMat,0.005,0);
cvConvert(pBkMat, pBkImg);
cvShowImage("avg",pBkImg);
if(cvWaitKey(20)==27)
return -1;
}
}
capture=cvCaptureFromFile("video.avi");
numfrm=0;
while(pFrame=cvQueryFrame(capture))
{
numfrm++;
if(numfrm==1)
{
pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
cvCvtColor(pFrame,pFrImg,CV_BGR2GRAY);
cvConvert(pFrImg,pFrameMat);
cvAbsDiff(pFrameMat,pBkMat,pFrMat);
cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
cvShowImage("video",pFrame);
cvvShowImage("sub",pFrImg);
}
else
{
cvCvtColor(pFrame,pFrImg,CV_BGR2GRAY);
cvConvert(pFrImg,pFrameMat);
cvAbsDiff(pFrameMat,pBkMat,pFrMat);
cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
cvShowImage("video",pFrame);
cvvShowImage("sub",pFrImg);
}
if(cvWaitKey(20)==27)
break;
}
cvReleaseImage(&pFrame);
cvReleaseImage(&pFrImg);
cvReleaseImage(&pBkImg);
cvReleaseMat(&pFrameMat);
cvReleaseMat(&pFrMat);
cvReleaseMat(&pBkMat);
cvReleaseCapture(&capture);
cvDestroyWindow("video");
cvDestroyWindow("avg");
cvDestroyWindow("sub");
return 0;
}
程序运行结果: