背景建模法是一种简单、快速但是背景的多模态(比如光照强度的变化、树叶的摇动等)比较敏感的一种背景建模方法。其基本思想是计算每个像素上的平均值作为基本模型,然后将当前像素值和背景像素值进行比较,当他们之间的差值小于某个特定的阈值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; }
程序运行结果: