基本思路:计算每个像素的平均值和标准差作为它的背景模型,利用已建立的背景模型对图像进行背景差分分割出前景目标。
1 #include "stdafx.h" 2 #include "cv.h" 3 #include "highgui.h" 4 5 IplImage *IavgF,* IdiffF, *IprevF, *IhiF, *IlowF; 6 7 IplImage *Iscratch,*Iscratch2; 8 9 IplImage *Igray1,*Igray2,*Igray3; 10 IplImage *Ilow1,*Ilow2,*Ilow3; 11 IplImage *Ihi1,*Ihi2,*Ihi3; 12 13 IplImage *Imaskt; 14 float Icount; //累积的帧数 15 16 //初始化图像 17 void AllocateImages(CvSize sz) 18 { 19 IavgF=cvCreateImage(sz,IPL_DEPTH_32F,3); 20 IdiffF=cvCreateImage(sz,IPL_DEPTH_32F,3); 21 IprevF=cvCreateImage(sz,IPL_DEPTH_32F,3); 22 IhiF=cvCreateImage(sz,IPL_DEPTH_32F,3); 23 IlowF=cvCreateImage(sz,IPL_DEPTH_32F,3); 24 Ilow1=cvCreateImage(sz,IPL_DEPTH_32F,1); 25 Ilow2=cvCreateImage(sz,IPL_DEPTH_32F,1); 26 Ilow3=cvCreateImage(sz,IPL_DEPTH_32F,1); 27 Ihi1=cvCreateImage(sz,IPL_DEPTH_32F,1); 28 Ihi2=cvCreateImage(sz,IPL_DEPTH_32F,1); 29 Ihi3=cvCreateImage(sz,IPL_DEPTH_32F,1); 30 cvZero(IavgF); 31 cvZero(IdiffF); 32 cvZero(IprevF); 33 cvZero(IhiF); 34 cvZero(IlowF); 35 Icount=0.00001; 36 37 Iscratch=cvCreateImage(sz,IPL_DEPTH_32F,3); 38 Iscratch2=cvCreateImage(sz,IPL_DEPTH_32F,3); 39 Igray1=cvCreateImage(sz,IPL_DEPTH_32F,1); 40 Igray2=cvCreateImage(sz,IPL_DEPTH_32F,1); 41 Igray3=cvCreateImage(sz,IPL_DEPTH_32F,1); 42 Imaskt=cvCreateImage(sz,IPL_DEPTH_8U,1); 43 cvZero(Iscratch); 44 cvZero(Iscratch2); 45 } 46 47 //累积每一帧图像 48 void accumulateBackground(IplImage* I) 49 { 50 static int first=1; 51 cvCvtScale(I,Iscratch,1,0); 52 if(!first) 53 { 54 cvAcc(Iscratch,IavgF); 55 cvAbsDiff(Iscratch,IprevF,Iscratch2); 56 cvAcc(Iscratch2,IdiffF); 57 Icount+=1.0; 58 } 59 first=0; 60 cvCopy(Iscratch,IprevF); 61 } 62 63 //设置阈值,IdiffF*scale+IavgF=IhiF 64 void setHighThreshold(float scale) 65 { 66 cvConvertScale(IdiffF,Iscratch,scale); 67 cvAdd(Iscratch,IavgF,IhiF); 68 cvSplit(IhiF,Ihi1,Ihi2,Ihi3,0); 69 } 70 71 //设置阈值,IavgF-IdiffF*scale=IlowF 72 //位于IlowF和IhiF之间的为背景,其外的为前景 73 void setLowThreshold(float scale) 74 { 75 cvConvertScale(IdiffF,Iscratch,scale); 76 cvSub(IavgF,Iscratch,IlowF); 77 cvSplit(IlowF,Ilow1,Ilow2,Ilow3,0); 78 } 79 80 //计算视频中每个像素的均值和方差 81 void createModelsfromStats() 82 { 83 cvConvertScale(IavgF,IavgF,(double)(1.0/Icount)); 84 cvConvertScale(IdiffF,IdiffF,(double)(1.0/Icount)); 85 86 cvAddS(IdiffF,cvScalar(1.0,1.0,1.0),IdiffF); 87 setHighThreshold(7.0); 88 setLowThreshold(6.0); 89 } 90 91 //根据建立的平均背景模型分割出图像的前景和背景 92 //将分割结果转变成掩模图像Imask,在任何通道上非常大的差别都可认为是前景像素 93 void backgroundDiff(IplImage* I,IplImage* Imask) //Imask为单通道8位图像 94 { 95 cvCvtScale(I,Iscratch,1,0); 96 cvSplit(Iscratch,Igray1,Igray2,Igray3,0); 97 98 cvInRange(Igray1,Ilow1,Ihi1,Imask); 99 100 cvInRange(Igray2,Ilow2,Ihi2,Imask); 101 cvOr(Imask,Imaskt,Imaskt); 102 103 cvInRange(Igray3,Ilow3,Ihi3,Imask); 104 cvOr(Imask,Imaskt,Imaskt); 105 106 cvSubRS(Imask,cvScalar(255),Imask); //白为前景,黑为背景 107 } 108 109 void DeallocateImages() 110 { 111 cvReleaseImage(&IavgF); 112 cvReleaseImage(&IdiffF); 113 cvReleaseImage(&IprevF); 114 cvReleaseImage(&IhiF); 115 cvReleaseImage(&IlowF); 116 cvReleaseImage(&Ilow1); 117 cvReleaseImage(&Ilow2); 118 cvReleaseImage(&Ilow3); 119 cvReleaseImage(&Ihi1); 120 cvReleaseImage(&Ihi2); 121 cvReleaseImage(&Ihi3); 122 cvReleaseImage(&Iscratch); 123 cvReleaseImage(&Iscratch2); 124 cvReleaseImage(&Imaskt); 125 } 126 127 int main() 128 { 129 CvCapture* capture=cvCreateFileCapture("C:/Users/shark/Desktop/eagle.flv"); 130 //CvCapture* capture=cvCreateCameraCapture(0); 131 IplImage* frame=NULL; 132 cvNamedWindow("frame"); 133 cvNamedWindow("Imask"); 134 if(capture) 135 { 136 int width=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH); 137 int height=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT); 138 CvSize size=cvSize(width,height); 139 140 AllocateImages(size); 141 IplImage* Imask=cvCreateImage(size,IPL_DEPTH_8U,1); //要输出的掩模图像 142 frame=cvQueryFrame(capture); //用摄像头获取视频时第一帧为空 143 for(int i=0;;i++) 144 { 145 if(!(frame=cvQueryFrame(capture))) 146 break; 147 cvShowImage("frame",frame); 148 if(i<=30) //对前30帧进行训练 149 { 150 accumulateBackground(frame); //累积图像 151 if(i==30) 152 createModelsfromStats(); //构建平均背景模型 153 } 154 else 155 { 156 backgroundDiff(frame,Imask); //分割图像 157 cvShowImage("Imask",Imask); 158 } 159 if(cvWaitKey(30)==27) 160 break; 161 } 162 163 DeallocateImages(); 164 cvReleaseImage(&Imask); 165 cvDestroyAllWindows(); 166 return 0; 167 } 168 else 169 return -1; 170 }
经实验发现对一般的视频,要调整训练的帧数和阈值等参数才有可能对前景目标实现较好的分割;对摄像头获取的视频分割效果还比较好。光线的变化对分割结果影响较大
下一篇将实现codebook法训练背景模型来分割前景目标,与之作为比较。
原文:http://www.cnblogs.com/luckyboylch/p/5003643.html