OpenCV实现平均背景法
平均背景法的基本思想是计算每个像素的平均值和标准差作为它的背景模型。
平均背景法使用四个OpenCV函数:
- cvAcc(),累积图像;
- cvAbsDiff(),计算一定时间内的每帧图像只差;
- cvInRange(),将图像分割成前景区域和背景区域;
- cvOr(),将不同的彩色通道图像中合成为一个掩膜图像
代码:
/* 平均背景法 */ #include"highgui.h" #include"cv.h" #include#include //为不同的临时指针图像和统计属性创建指针 //Float,3-channelimages IplImage*IavgF,*IdiffF,*IprevF,*IhiF,*IlowF; IplImage*Iscratch,*Iscratch2; //Float1-channelimages IplImage*Igray1,*Igray2,*Igray3; IplImage*Ilow1,*Ilow2,*Ilow3; IplImage*Ihi1,*Ihi2,*Ihi3; //Byte,1-channelimage IplImage*Imask; IplImage*Imaskt; //Countsnumberofimageslearnedforaveraginglater. floatIcount; //创建一个函数来给需要的所有临时图像分配内存 //为了方便,我们传递一幅图像(来自视频)作为大小参考来分配临时图像 voidAllocateImages(IplImage*I) { CvSizesz=cvGetSize(I); IavgF=cvCreateImage(sz,IPL_DEPTH_32F,3); IdiffF=cvCreateImage(sz,IPL_DEPTH_32F,3); IprevF=cvCreateImage(sz,IPL_DEPTH_32F,3); IhiF=cvCreateImage(sz,IPL_DEPTH_32F,3); IlowF=cvCreateImage(sz,IPL_DEPTH_32F,3); 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); cvZero(IavgF); cvZero(IdiffF); cvZero(IprevF); cvZero(IhiF); cvZero(IlowF); Icount=0.00001; 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); Imask=cvCreateImage(sz,IPL_DEPTH_8U,1); Imaskt=cvCreateImage(sz,IPL_DEPTH_8U,1); cvZero(Iscratch); cvZero(Iscratch2); } //学习累积背景图像和每一帧图像差值的绝对值 //Learnthebackgroundstatisticsforonemoreframe //Iisacolorsampleofthebackground,3-channel,8u voidaccumulateBackground(IplImage*I) { staticintfirst=1; cvCvtScale(I,Iscratch,1,0); if(!first) { cvAcc(Iscratch,IavgF); cvAbsDiff(Iscratch,IprevF,Iscratch2); cvAcc(Iscratch2,IdiffF); Icount+=1.0; } first=0; cvCopy(Iscratch,IprevF); } //setHighThreshold和setLowThreshold都是基于每一帧图像平均绝对差设置阈值的有效函数 voidsetHighThreshold(floatscale) { cvConvertScale(IdiffF,Iscratch,scale); cvAdd(Iscratch,IavgF,IhiF); cvSplit(IhiF,Ihi1,Ihi2,Ihi3,0); } voidsetLowThreshold(floatscale) { cvConvertScale(IdiffF,Iscratch,scale); cvSub(IavgF,Iscratch,IlowF); cvSplit(IlowF,Ilow1,Ilow2,Ilow3,0); } //当积累了足够多的帧图像之后,就将其转化为一个背景的统计模型 //计算每一个像素的均值和方差观测 voidcreateModelsfromStats() { cvConvertScale(IavgF,IavgF,(double)(1.0/Icount)); cvConvertScale(IdiffF,IdiffF,(double)(1.0/Icount)); //Makesurediffisalwayssomething cvAddS(IdiffF,cvScalar(1.0,1.0,1.0),IdiffF); setHighThreshold(7.0); setLowThreshold(6.0); } //有了背景模型,同时给出了高,低阈值,就能用它将图像分割为前景和背景 //Createabinary:0,255maskwhere255meansforegrondpixel //IInputimage,3-channel,8u //Imask voidbackgroundDiff(IplImage*I) { cvCvtScale(I,Iscratch,1,0); cvSplit(Iscratch,Igray1,Igray2,Igray3,0); //Channel1 cvInRange(Igray1,Ilow1,Ihi1,Imask); //Channel2 cvInRange(Igray2,Ilow2,Ihi2,Imaskt); cvOr(Imask,Imaskt,Imask); //Channel3 cvInRange(Igray3,Ilow3,Ihi3,Imaskt); cvOr(Imask,Imaskt,Imask); //Finally,inverttheresult cvSubRS(Imask,cvScalar(255),Imask); } //完成背景建模后,释放内存 voidDeallocateImage() { cvReleaseImage(&IavgF); cvReleaseImage(&IdiffF); cvReleaseImage(&IprevF); cvReleaseImage(&IhiF); cvReleaseImage(&IlowF); cvReleaseImage(&Ilow1); cvReleaseImage(&Ilow2); cvReleaseImage(&Ilow3); cvReleaseImage(&Iscratch); cvReleaseImage(&Iscratch2); cvReleaseImage(&Igray1); cvReleaseImage(&Igray2); cvReleaseImage(&Igray3); cvReleaseImage(&Imaskt); } //主函数 intmain() { CvCapture*capture=cvCreateFileCapture("tree.avi"); if(!capture) { return-1; } cvNamedWindow("win1"); cvNamedWindow("win2"); IplImage*rawImage=cvQueryFrame(capture); cvShowImage("win1",rawImage); AllocateImages(rawImage); inti=0; while(1) { if(i<=30) { accumulateBackground(rawImage); if(i==30) { createModelsfromStats(); } } else { backgroundDiff(rawImage); } cvShowImage("win2",Imask); if(cvWaitKey(33)==27) { break; } if(!(rawImage=cvQueryFrame(capture))) { break; } cvShowImage("win1",rawImage); if(i==56||i==63) cvWaitKey(); i=i+1; } DeallocateImage(); return0; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。