平均场景法分割前景目标

基本思路:计算每个像素的平均值和标准差作为它的背景模型,利用已建立的背景模型对图像进行背景差分分割出前景目标。

  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法训练背景模型来分割前景目标,与之作为比较。

原文地址:https://www.cnblogs.com/luckyboylch/p/5003643.html