平均背景法的基本思路是计算每个像素的平均值和标准差作为它的背景模型
四个函数:
1.cvAcc():累积图像
2.cvAbsDiff():计算一定时间内的每帧图像之差
3.cvInRange():将图像分割成前景区域和背景区域
4.cvOr():将不同的彩色通道图像中合成为一个掩模图像
这种方法只能用于背景场景中不包含运动的部分,而且光线保持不变
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
//float 3-channel iamges
IplImage *IavgF,*IdiffF,*IprevF,*IhiF,*IlowF;
IplImage *Iscratch,*Iscratch2;
//float 1-channel iamges
IplImage *Igray1,*Igray2,*Igray3;
IplImage *Ilow1,*Ilow2,*Ilow3;
IplImage *Ihi1,*Ihi2,*Ihi3;
//byte 1-channel image
IplImage *Imaskt;
//counts number of images learned for averaging later
float Icount;
void AllocateImages(IplImage* I);
void accumulateBackground(IplImage* I);
void createModelsfromStats();
void setHighThreshold(float scale);
void setLowThreshold(float scale);
void backgroundDiff(IplImage *I,IplImage * Imask);
void DeallocateImage();
int main(int argc,char** argv)
{
cvNamedWindow("intput",CV_WINDOW_AUTOSIZE); //创建输入显示窗口
cvNamedWindow("output",CV_WINDOW_AUTOSIZE); //创建输出显示窗口
CvCapture* capture = cvCreateFileCapture(argv[1]); //返回一个capture指针,指向视频
IplImage* img = cvQueryFrame(capture); //从视频中取出的图片
IplImage* Imask = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);//创建输出图片,这里不能去掉cvCreateImage(cvGetSize(Img),IPL_DEPTH_8U,1),虽然我看例程里省略了
AllocateImages(img);//给图像分配内存
/*累积图像,只取了前30帧图片*/
while(Icount<30){
accumulateBackground(img); //调用累积图像的函数,循环30次
img = cvQueryFrame(capture); //从视频中取出的图片
cvShowImage("intput",img);
cvWaitKey(20);
}
createModelsfromStats(); //背景建模
while(1)
{
img = cvQueryFrame(capture);
if(!img) break;
backgroundDiff(img,Imask); //根据模型分割前景
cvShowImage("output",Imask); //显示图像,视频是一张一张图片连续播放的结果
cvShowImage("intput",img);
char c = cvWaitKey(33); //当前帧被显示后,等待33ms再读取下一张图片
if(c==27) break; //等待期间按下esc键,ASCII码为27,则循环退出
}
cvReleaseCapture(&capture);
cvDestroyWindow("output");
cvDestroyWindow("intput");
DeallocateImage();
}
//给需要的所有临时图像分配内存
void AllocateImages(IplImage* I){
CvSize sz = cvGetSize(I);
IavgF = cvCreateImage(sz,IPL_DEPTH_32F,3);cvZero(IavgF);
IdiffF = cvCreateImage(sz,IPL_DEPTH_32F,3);cvZero(IdiffF);
IprevF = cvCreateImage(sz,IPL_DEPTH_32F,3);cvZero(IprevF);
IhiF = cvCreateImage(sz,IPL_DEPTH_32F,3);cvZero(IhiF);
IlowF = cvCreateImage(sz,IPL_DEPTH_32F,3);cvZero(IlowF);
Ilow1 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Ilow2 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Ilow3 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Ihi1 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Ihi2 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Ihi3 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Icount = 0.00001;//protect against divide by zero
Iscratch = cvCreateImage(sz,IPL_DEPTH_32F,3);
Iscratch2 = cvCreateImage(sz,IPL_DEPTH_32F,3);
Igray1 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Igray2 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Igray3 = cvCreateImage(sz,IPL_DEPTH_32F,1);
Imaskt = cvCreateImage(sz,IPL_DEPTH_8U,1);
cvZero(Iscratch);
cvZero(Iscratch2);
}
/*积累背景图像和每一帧图像差值的绝对值
/函数调用需要通道为3,深度为8的彩色图像
*/
void accumulateBackground(IplImage* I){
static int first = 1;
cvCvtScale(I,Iscratch,1,0);//convert to float,3-channel
if(!first){
cvAcc(Iscratch,IavgF);
cvAbsDiff(Iscratch,IprevF,Iscratch2);
cvAcc(Iscratch2,IdiffF);
Icount += 1.0;
}
first = 0;
cvCopy(Iscratch,IprevF);
}
//计算每一个像素的均值和方差观测(平均绝对差分)
void createModelsfromStats(){
cvConvertScale(IavgF,IavgF,(double)(1.0/Icount));
cvConvertScale(IdiffF,IdiffF,(double)(1.0/Icount));
//make sure diff is always something
cvAddS(IdiffF,cvScalar(1.0,1.0,1.0),IdiffF);
setHighThreshold(7.0);
setLowThreshold(6.0);
}
void setHighThreshold(float scale){
cvConvertScale(IdiffF,Iscratch,scale);
cvAdd(Iscratch,IavgF,IhiF);
cvSplit(IhiF,Ihi1,Ihi2,Ihi3,0);
}
void setLowThreshold(float scale){
cvConvertScale(IdiffF,Iscratch,scale);
cvAdd(IavgF,Iscratch,IlowF);
cvSplit(IlowF,Ilow1,Ilow2,Ilow3,0);
}
//图像分割
void backgroundDiff(IplImage *I,IplImage *Imask){
cvConvertScale(I,Iscratch,1,0);//to float
cvSplit(Iscratch,Igray1,Igray2,Igray3,0);
//channel-1
cvInRange(Igray1,Ilow1,Ihi1,Imask);
//channel-2
cvInRange(Igray2,Ilow2,Ihi2,Imaskt);
cvOr(Imask,Imaskt,Imask);
//channel-3
cvInRange(Igray3,Ilow3,Ihi3,Imaskt);
cvOr(Imask,Imaskt,Imask);
cvSubRS(Imask,cvScalar(255),Imask);
}
//内存释放
void DeallocateImage(){
cvReleaseImage(&IavgF);
cvReleaseImage(&IdiffF);
cvReleaseImage(&IprevF);
cvReleaseImage(&IhiF);
cvReleaseImage(&IlowF);
cvReleaseImage(&Ilow1);
cvReleaseImage(&Ilow2);
cvReleaseImage(&Ilow3);
cvReleaseImage(&Ihi1);
cvReleaseImage(&Ihi2);
cvReleaseImage(&Ihi3);
cvReleaseImage(&Iscratch);
cvReleaseImage(&Iscratch2);
cvReleaseImage(&Igray1);
cvReleaseImage(&Igray2);
cvReleaseImage(&Igray3);
cvReleaseImage(&Imaskt);
}