[轉]前景檢測算法--ViBe算法


原文:http://blog.csdn.net/zouxy09/article/details/9622285

轉自:http://blog.csdn.net/app_12062011/article/details/51866319

 

因為監控發展的需求,目前前景檢測的研究還是很多的,也出現了很多新的方法和思路。個人了解的大概概括為以下一些:

       幀差、背景減除(GMM、CodeBook、 SOBS、 SACON、 VIBE、 W4、多幀平均……)、光流(稀疏光流、稠密光流)、運動競爭(Motion Competition)、運動模版(運動歷史圖像)、時間熵……等等。如果加上他們的改進版,那就是很大的一個家族了。

      對於上一些方法的一點簡單的對比分析可以參考下:

http://www.cnblogs.com/ronny/archive/2012/04/12/2444053.html

       至於哪個最好,看使用環境吧,各有千秋,有一些適用的情況更多,有一些在某些情況下表現更好。這些都需要針對自己的使用情況作測試確定的。呵呵。

       推薦一個牛逼的庫:http://code.google.com/p/bgslibrary/里面包含了各種背景減除的方法,可以讓自己少做很多力氣活。

       還有王先榮博客上存在不少的分析:

http://www.cnblogs.com/xrwang/archive/2010/02/21/ForegroundDetection.html

       下面的博客上轉載王先榮的上面幾篇,然后加上自己分析了兩篇:

http://blog.csdn.net/stellar0

 

       本文主要關注其中的一種背景減除方法:ViBe。stellar0的博客上對ViBe進行了分析,我這里就不再啰嗦了,具體的理論可以參考:

http://www2.ulg.ac.be/telecom/research/vibe/

http://blog.csdn.net/stellar0/article/details/8777283

http://blog.csdn.net/yongshengsilingsa/article/details/6659859

http://www2.ulg.ac.be/telecom/research/vibe/download.html

http://www.cvchina.info/2011/12/25/vibe/

 

 

ViBe是一種像素級的背景建模、前景檢測算法,該算法主要不同之處是背景模型的更新策略,隨機選擇需要替換的像素的樣本,隨機選擇鄰域像素進行更新。在無法確定像素變化的模型時,隨機的更新策略,在一定程度上可以模擬像素變化的不確定性。

背景模型的初始化

  初始化是建立背景模型的過程,一般的檢測算法需要一定長度的視頻序列學習完成,影響了檢測的實時性,而且當視頻畫面突然變化時,重新學習背景模型需要較長時間。

  ViBe算法主要是利用單幀視頻序列初始化背景模型,對於一個像素點,結合相鄰像素點擁有相近像素值的空間分布特性,隨機的選擇它的鄰域點的像素值作為它的模型樣本值

  優點:不僅減少了背景模型建立的過程,還可以處理背景突然變化的情況,當檢測到背景突然變化明顯時,只需要舍棄原始的模型,重新利用變化后的首幀圖像建立背景模型。

  缺點:由於可能采用了運動物體的像素初始化樣本集,容易引入拖影(Ghost)區域。

前景檢測過程

  背景模型為每個背景點存儲一個樣本集,然后每個新的像素值和樣本集比較判斷是否屬於背景。

  計算新像素值和樣本集中每個樣本值的距離,若距離小於閾值,則近似樣本點數目增加。

  如果近似樣本點數目大於閾值,則認為新的像素點為背景。

  檢測過程主要由三個參數決定:樣本集數目N,閾值#min和距離相近判定的閾值R,一般具體實現,參數設置為N=20,#min=2,R=20。

  

背景模型的更新策略

1).無記憶更新策略

  每次確定需要更新像素點的背景模型時,以新的像素值隨機取代該像素點樣本集的一個樣本值。

2).時間取樣更新策略

  並不是每處理一幀數據,都需要更新處理,而是按一定的更新率更新背景模型。當一個像素點被判定為背景時,它有1/rate的概率更新背景模型。rate是時間采樣因子,一般取值為16。

3).空間鄰域更新策略

  針對需要更新像素點,隨機的選擇一個該像素點鄰域的背景模型,以新的像素點更新被選中的背景模型。

ViBe的改進

  

1).距離計算方法

  以圓椎模型代替原來的幾何距離計算方法

 

  

  以自適應閾值代替原來固定的距離判定閾值,閾值大小與樣本集的方差成正比,樣本集方差越大,說明背景越復雜,判定閾值應該越大。

  

2).分離updating mask和segmentation mask

  引入目標整體的概念,彌補基於像素級前景檢測的不足。針對updating mask和segmentation mask采用不同尺寸的形態學處理方法,提高檢測准確率。

3).抑制鄰域更新

  在updating mask里,計算像素點的梯度,根據梯度大小,確定是否需要更新鄰域。梯度值越大,說明像素值變化越大,說明該像素值可能為前景,不應該更新。

4).檢測閃爍像素點

  引入閃爍程度的概念,當一個像素點的updating label與前一幀的updating label不一樣時,blinking level增加15,否則,減少1,然后根據blinking level的大小判斷該像素點是否為閃爍點。閃爍像素主要出現在背景復雜的場景,如樹葉、水紋等,這些場景會出現像素背景和前景的頻繁變化,因而針對這些閃爍應該單獨處理,可以作為全部作為背景。

5).增加更新因子

  ViBe算法中,默認的更新因子是16,當背景變化很快時,背景模型無法快速的更新,將會導致前景檢測的較多的錯誤。因而,需要根據背景變化快慢程度,調整更新因子的大小,可將更新因子分多個等級,如rate = 16,rate = 5,rate = 1。

 

1)VIBE-A powerful random technique to estimatie the background in video sequences.

2) VIBE-A universal background subtraction algorithms for video sequences

   VIBE的頭文件Vibe.hpp如下:

 1 #pragma once  
 2 #include "stdafx.h"  
 3 #define  WINSIZE 3  
 4   
 5 class Vibe  
 6 {  
 7 public:  
 8     Vibe(void);  
 9     Vibe(IplImage *img);  
10     void SetMinMatch(int nthreshold){g_MinMatch=nthreshold;}  
11     void SetRadius(int radius){g_Radius=radius;}  
12     void SetSampleNum(int num){g_SampleNum=num;}  
13     void SetThreshold(double t){g_threshold=t;}  
14     IplImage* GetForeground(){return g_ForeImg;}  
15     IplImage* GetSegMask(){return g_SegementMask;}  
16     void Detect(IplImage *img);   
17     void ForegroundCombineEdge(); // 結合邊緣信息  
18     void DeleteSmallAreaInForeground(double minArea=20);//刪除小面積區域  
19     // 實現背景更新機制  
20     void Update();  
21     // 實現后處理,主要用形態學算子  
22     void PostProcess();  
23   
24 public:  
25     ~Vibe(void);  
26   
27 private:      
28     void ClearLongLifeForeground(int i_lifeLength=200); // 清除場景中存在時間較長的像素,i_lifeLength用於控制允許存在的最長時間  
29     double AreaDense(IplImage *pFr,int AI,int AJ,int W,int H); //計算(i,j)處鄰域大小為W×H的密度  
30     int GetRandom(int istart,int iend); // 默認istart=0,iend=15  
31     int GetRandom(int random);  
32     int GetRandom();// 產生一個隨機數  
33     // 計算兩個像素之間的歐式距離  
34     double CalcPixelDist(CvScalar bkCs,CvScalar curCs);  
35     // 按照Kim的方法來計算顏色畸變  
36     double CalcuColorDist(CvScalar bkCs,CvScalar curCs);  
37     int g_SampleNum;// Sample number for the models,默認為20  
38     int g_MinMatch; // 當前像素與背景模型匹配的最少個數,默認為2  
39     int g_Height;  
40     int g_Width;  
41     int g_Radius;// 球體的半徑,默認為20  
42     int g_offset; //邊界的寬和高  
43     double g_threshold; // 距離度量的閾值  
44     unsigned char ***g_Model;// 保存背景模型    
45     IplImage *g_ForeImg;// 保存前景圖  
46     IplImage *g_Edge;  
47   
48     IplConvKernel* element;  
49   
50     IplImage *g_SegementMask; //分割掩膜  
51     IplImage *g_UpdateMask; // 更新掩膜  
52     IplImage *g_Gray;  
53     int ** LifeLength; // 記錄前景點的生命長度,如果前景點的生命長度到達一定的閾值,則將其融入背景中去,且要隨機兩次。      
54 };  

對應的實現文件如下Vibe.cpp所示:

  1 #include "StdAfx.h"  
  2 #include "Vibe.h"  
  3   
  4 Vibe::Vibe(void)  
  5 {  
  6     g_Radius=20;  
  7     g_MinMatch=2;     
  8     g_SampleNum=20;  
  9     g_offset=(WINSIZE-1)/2;  
 10   
 11 }  
 12   
 13 Vibe::Vibe(IplImage *img)  
 14 {  
 15     if (!img)  
 16     {  
 17         cout<<" The parameter referenced to NUll Pointer!"<<endl;  
 18         return;  
 19     }  
 20     this->g_Height=img->height;  
 21     this->g_Width=img->width;  
 22   
 23     g_Radius=20;  
 24     g_MinMatch=2;     
 25     g_SampleNum=20;  
 26     g_threshold=50;  
 27     g_offset=(WINSIZE-1)/2;  
 28   
 29     g_ForeImg=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);  
 30     g_Gray=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);  
 31     g_Edge=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);  
 32     g_SegementMask=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);  
 33     g_UpdateMask=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);  
 34   
 35     element=cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL);  
 36   
 37     cvCvtColor(img,g_Gray,CV_BGR2GRAY);  
 38       
 39     // 以上完成相關的初始化操作  
 40     /**********************  以下實現第一幀在每個像素的8鄰域內的采樣功能,建立對應的背景模型*****************************/  
 41       
 42     int i=0,j=0,k=0;  
 43     g_Model=new unsigned char**[g_SampleNum];  
 44     for (k=0;k<g_SampleNum;k++)  
 45     {  
 46         g_Model[k]=new unsigned char *[g_Height];  
 47         for(i=0;i<g_Height;i++)  
 48         {  
 49             g_Model[k][i]=new unsigned char [g_Width];  
 50             for (j=0;j<g_Width;j++)  
 51             {  
 52                 g_Model[k][i][j]=0;  
 53             }  
 54         }  
 55     }  
 56       
 57     // 采樣進行背景建模   
 58     double dVal;  
 59     int ri=0,rj=0; //隨機采樣的值  
 60     for (i=g_offset;i<g_Height-g_offset;i++)  
 61     {  
 62         for (j=g_offset;j<g_Width-g_offset;j++)  
 63         {  
 64             // 周圍3*3的鄰域內進行采樣  
 65             for(k=0;k<g_SampleNum;k++)  
 66             {  
 67                 ri=GetRandom(i);  
 68                 rj=GetRandom(j);  
 69                 dVal=cvGetReal2D(g_Gray,ri,rj);       
 70                 g_Model[k][i][j]=dVal;                            
 71             }  
 72         }  
 73     }  
 74   
 75     // 初始化前景點掩膜的生命長度  
 76     LifeLength=new int *[g_Height];  
 77     for (i=0;i<g_Height;i++)  
 78     {  
 79         LifeLength[i]=new int [g_Width];  
 80         for(j=0;j<g_Width;j++)  
 81         {  
 82             LifeLength[i][j]=0;  
 83         }  
 84     }  
 85 }  
 86   
 87   
 88 void Vibe::Detect(IplImage *img)  
 89 {  
 90     cvZero(g_ForeImg);    
 91     cvCvtColor(img,g_Gray,CV_BGR2GRAY);  
 92     int i=0,j=0,k=0;  
 93     double dModVal,dCurrVal;  
 94     int tmpCount=0;// 距離比較在閾值內的次數  
 95     double tmpDist=0;     
 96     int iR1,iR2;//產生隨機數  
 97     int Ri,Rj; // 產生鄰域內X和Y的隨機數  
 98   
 99     for (i=0;i<g_Height;i++)  
100     {         
101         for (j=0;j<g_Width;j++)  
102         {             
103             if( i < g_offset || j < g_offset || i> g_Height - g_offset || j> g_Width - g_offset )  
104             {  
105                 cvSetReal2D(g_ForeImg,i,j,0);  
106                 continue;  
107             }  
108             else  
109             {  
110                 tmpCount=0;  
111                 dCurrVal=cvGetReal2D(g_Gray,i,j);                 
112                 for (k=0;k<g_SampleNum && tmpCount<g_MinMatch  ;k++)  
113                 {                     
114                     dModVal=g_Model[k][i][j];  
115                     //tmpDist=CalcPixelDist(dCurrVal,dModVal);  
116                     //tmpDist=CalcuColorDist(dCurrVal,dModVal);   
117                     tmpDist=fabs(dModVal-dCurrVal);                                   
118                     if (tmpDist<g_Radius)  
119                     {  
120                         tmpCount++;  
121                     }                     
122                 }  
123   
124                 //判斷是否匹配上  
125                 if (tmpCount>=g_MinMatch)  
126                 {  
127                     cvSetReal2D(g_ForeImg,i,j,0);  
128                     // 背景模型的更新                    
129                     iR1=GetRandom(0,15);  
130                     if (iR1==0)  
131                     {  
132                         iR2=GetRandom();  
133                         g_Model[iR2][i][j]=dCurrVal;                          
134                     }  
135   
136                     //進一步更新鄰域模型  
137                       
138                     iR1=GetRandom(0,15);  
139                     if (iR1==0)  
140                     {  
141                         Ri=GetRandom(i);  
142                         Rj=GetRandom(j);  
143                         iR2=GetRandom();  
144                         g_Model[iR2][Ri][Rj]=dCurrVal;                        
145                     }                         
146                 }  
147                 else  
148                 {  
149                     cvSetReal2D(g_ForeImg,i,j,255);  
150                 }  
151             }  
152         }         
153     }         
154       
155     //ForegroundCombineEdge();  
156     DeleteSmallAreaInForeground(80);  
157     ClearLongLifeForeground();  
158     //PostProcess();  
159 }  
160   
161 double Vibe::AreaDense(IplImage *pFr,int AI,int AJ,int W,int H)  
162 {  
163     if (AI<=2 || AJ<=2 || AJ>=(g_Width-2) || AI>=(g_Height-2))  
164     {  
165         return 0;  
166     }  
167     int Num=0,i=0,j=0;  
168     double dVal=0,dense=0;  
169     int Total=(2*H+1)*(2*W+1);  
170     for (i=AI-H;i<=AI+H;i++)  
171     {  
172         for (j=AJ-W;j<=AJ+W;j++)  
173         {  
174             dVal=cvGetReal2D(pFr,i,j);  
175             if (dVal>200)  
176             {  
177                 Num++;  
178             }  
179         }  
180     }  
181     dense=(double)Num/(double)Total;  
182     return dense;  
183 }  
184   
185 void Vibe::ForegroundCombineEdge()  
186 {     
187     cvZero(g_Edge);  
188     //cvZero(g_SegementMask);  
189     //cvCopy(g_ForeImg,g_SegementMask);  
190     cvCanny(g_Gray,g_Edge,30,200,3);  
191     int i=0,j=0;  
192     double dense;  
193     double dVal;  
194     for (i=g_offset;i<g_Height-g_offset;i++)  
195     {  
196         for (j=g_offset;j<g_Width-g_offset;j++)  
197         {  
198             dense=AreaDense(g_ForeImg,i,j,2,2);  
199             dVal=cvGetReal2D(g_Edge,i,j);  
200             if (dense>0.2 && dVal>200)  
201             {  
202                 cvSetReal2D(g_ForeImg,i,j,255);  
203             }  
204         }  
205     }  
206   
207 }  
208   
209   
210 void Vibe::DeleteSmallAreaInForeground(double minArea/* =20 */)  
211 {  
212     //cvZero(g_SegementMask);  
213     //cvCopy(g_ForeImg,g_SegementMask);  
214     int region_count = 0;  
215     CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;  
216     CvMemStorage*  storage = cvCreateMemStorage();  
217     cvClearMemStorage(storage);  
218     cvFindContours( g_ForeImg, storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );  
219     for( seq = first_seq; seq; seq = seq->h_next )  
220     {  
221         CvContour* cnt = (CvContour*)seq;  
222         if( cnt->rect.width * cnt->rect.height < minArea )  
223         {  
224             prev_seq = seq->h_prev;  
225             if( prev_seq )  
226             {  
227                 prev_seq->h_next = seq->h_next;  
228                 if( seq->h_next ) seq->h_next->h_prev = prev_seq;  
229             }  
230             else  
231             {  
232                 first_seq = seq->h_next;  
233                 if( seq->h_next ) seq->h_next->h_prev = NULL;  
234             }  
235         }  
236         else  
237         {             
238             region_count++;  
239         }  
240     }              
241     cvZero(g_ForeImg);  
242     cvDrawContours(g_ForeImg, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);   
243   
244     /* 
245     CvContourScanner scanner = cvStartFindContours( g_ForeImg, storage,sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) ); 
246     CvSeq *contours=NULL,*c=NULL; 
247     int poly1Hull0=0; 
248     int nContours=0; 
249     double perimScale=100; 
250     while( (c = cvFindNextContour( scanner )) != 0 )  
251     { 
252         double len = cvContourPerimeter( c ); 
253         double q = (g_ForeImg->height + g_ForeImg->width)/perimScale; // calculate perimeter len threshold 
254         if( len < q ) //Get rid of blob if it's perimeter is too small 
255             cvSubstituteContour( scanner, 0 ); 
256         else //Smooth it's edges if it's large enough 
257         { 
258             CvSeq* newC; 
259             if( poly1Hull0 ) //Polygonal approximation of the segmentation  
260                 newC = cvApproxPoly( c, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 2, 0 );  
261             else //Convex Hull of the segmentation 
262                 newC = cvConvexHull2( c, storage, CV_CLOCKWISE, 1 ); 
263             cvSubstituteContour( scanner, newC ); 
264             nContours++; 
265         } 
266     } 
267     contours = cvEndFindContours( &scanner ); 
268     // paint the found regions back into the image 
269     cvZero( g_ForeImg ); 
270     for( c=contours; c != 0; c = c->h_next )  
271         cvDrawContours( g_ForeImg, c, cvScalarAll(255), cvScalarAll(0), -1, CV_FILLED, 8,cvPoint(0,0)); 
272     */  
273   
274     cvReleaseMemStorage(&storage);    
275 }  
276   
277 void Vibe::ClearLongLifeForeground(int i_lifeLength/* =200 */)  
278 {  
279     int i=0,j=0;  
280     double dVal=0;  
281     double dLife=0;  
282     int iR1,iR2=0;  
283     double dCurrVal=0;  
284     for (i=g_offset;i<g_Height-g_offset;i++)  
285     {  
286         for (j=g_offset;j<g_Width-g_offset;j++)  
287         {  
288             dVal=cvGetReal2D(g_ForeImg,i,j);  
289             dLife=LifeLength[i][j];  
290             if (dLife>i_lifeLength)  
291             {  
292                 LifeLength[i][j]=0;  
293                 dCurrVal=cvGetReal2D(g_Gray,i,j);  
294                 // 更新背景模型  
295                 iR1=GetRandom();  
296                 iR2=GetRandom();  
297                 g_Model[iR1][i][j]=dCurrVal;  
298                 g_Model[iR2][i][j]=dCurrVal;  
299             }  
300             else  
301             {  
302                 LifeLength[i][j]=dLife+1;  
303             }  
304   
305         }  
306     }  
307 }  
308   
309 void Vibe::Update()  
310 {  
311     cvZero(g_UpdateMask);     
312   
313 }  
314   
315 void Vibe::PostProcess()  
316 {  
317     cvZero(g_SegementMask);  
318     cvMorphologyEx(g_ForeImg,g_SegementMask,NULL,element,CV_MOP_OPEN,1);  
319   
320 }  
321   
322 //算顏色畸變  
323 double Vibe::CalcuColorDist(CvScalar bkCs,CvScalar curCs)  
324 {  
325     double r,g,b,br,bg,bb;  
326     r=curCs.val[0];  
327     g=curCs.val[1];  
328     b=curCs.val[2];  
329   
330     br=bkCs.val[0];  
331     bg=bkCs.val[1];  
332     bb=bkCs.val[2];  
333   
334     double curDist=r*r+g*g*b*b;   
335     double bkDist=br*br+bg*bg+bb*bb;  
336   
337     double curBK=r*br+g*bg+b*bb;  
338     double curbkDist=curBK*curBK;  
339     double SquareP;  
340     if (bkDist==0.0)  
341     {  
342         SquareP=0;  
343     }  
344     else  
345     {  
346         SquareP=curbkDist/bkDist;  
347     }  
348     double dist=sqrtf(curDist-SquareP);  
349     return dist;      
350 }  
351   
352 double Vibe::CalcPixelDist(CvScalar bkCs,CvScalar curCs)  
353 {  
354     double tmpDist=pow(bkCs.val[0]-curCs.val[0],2)+pow(bkCs.val[1]-curCs.val[1],2)+pow(bkCs.val[2]-curCs.val[2],2);  
355     return sqrtf(tmpDist);  
356 }  
357   
358 int Vibe::GetRandom()  
359 {  
360     int val = g_SampleNum * 1.0 * rand() / RAND_MAX;      
361     if( val == g_SampleNum )  
362         return val - 1;  
363     else  
364         return val;  
365 }  
366   
367 int Vibe::GetRandom(int random)  
368 {  
369     int val=random-g_offset+rand()%(2*g_offset);  
370     if (val<random-g_offset)  
371     {  
372         val=random-g_offset;  
373     }  
374     if (val>random+g_offset)  
375     {  
376         val=random+g_offset;  
377     }     
378     return val;   
379 }  
380   
381 int Vibe::GetRandom(int istart,int iend)  
382 {  
383     int val=istart+rand()%(iend-istart);  
384     return val;  
385 }  
386   
387   
388 Vibe::~Vibe(void)  
389 {  
390     if (g_ForeImg)  
391     {  
392         cvReleaseImage(&g_ForeImg);  
393     }  
394     if (g_SegementMask)  
395     {  
396         cvReleaseImage(&g_SegementMask);  
397     }  
398     if (g_UpdateMask)  
399     {  
400         cvReleaseImage(&g_UpdateMask);  
401     }  
402     if (g_Gray)  
403     {  
404         cvReleaseImage(&g_Gray);  
405     }  
406   
407     if (g_Model!=NULL)  
408     {  
409         delete[]g_Model;  
410         g_Model=NULL;  
411     }  
412 }  

最后附上調用的main函數:

 1 int _tmain(int argc, _TCHAR* argv[])  
 2 {     
 3     CvCapture *capture=NULL;  
 4     IplImage* frame=NULL;  
 5     IplImage* pForeImg=NULL;  
 6     IplImage* segImg=NULL;    
 7   
 8     char *file_path="E:\\testVideo\\VTS_01_4.avi";  // m1  test2 錦帶河  VTS_01_4_2  head rear  VTS_01_6_2  VTS_01_4  
 9     //const char* file_path="E:\\suntektechvideo\\錦帶河.avi";  //test2  
10   
11     capture=cvCreateFileCapture(file_path);  
12     if (!capture)  
13     {  
14         //cout<<"Read Video File Error!"<<endl;  
15         return -1;  
16     }  
17     frame=cvQueryFrame(capture);  
18     frame=cvQueryFrame(capture);  
19   
20     cvNamedWindow("img",1);  
21     cvNamedWindow("foreN",1);  
22     //cvNamedWindow("seg",1);  
23   
24     Vibe* pV=new Vibe(frame);  
25   
26     while(frame=cvQueryFrame(capture))  
27     {  
28         pV->Detect(frame);  
29         pForeImg=pV->GetForeground();  
30         //segImg=pV->GetSegMask();  
31         //frame->origin=1;  
32         //pForeImg->origin=1;  
33         cvShowImage("img",frame);  
34         cvShowImage("foreN",pForeImg);  
35         //cvShowImage("seg",segImg);  
36         cvWaitKey(1);  
37     }  
38   
39     cvReleaseImage(&frame);  
40     cvReleaseImage(&pForeImg);  
41     cvReleaseCapture(&capture);  
42     return 0;     
43 }  

代碼沒做過多的注釋,但現有的注釋應該對於理解代碼足夠了。另外,對於計算機視覺里的任何一種算法都不是萬能的,VIBE也不例外,只能說VIBE相對其他算法有一定的優勢,但是還是有相當的不足,其pixel-wise-based的灰度建模方式解決不了pixel-wise建模算法共有的問題,其他必要輔助信息的融合是必要的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM