目標跟蹤學習筆記_3(particle filter初探2)


  上次已經初步體驗了下particle filter,直接用別人的代碼,見我前面的博文http://www.cnblogs.com/tornadomeet/archive/2012/03/18/2404817.html

   一開始是內存出錯,后面干脆自己學了下particle filter濾波的原理,把代碼認真看了一遍,然后自己從頭敲了遍代碼,雖然運行時不再出現內存溢出等bug,但是沒有跟蹤效果。

  這次的代碼和上次一樣,有跟蹤效果,不過不理想。依舊是參照博主:http://blog.csdn.net/yang_xian521/article/details/6928131 的代碼,但是算法稍微改了3點。

  1.仔細閱讀其代碼發現其代碼有粒子濾波原則性的錯誤,即物體的運動模型,作者本意是將運動模型近視為二階自回歸模型,但是程序中粒子的坐標計算過程中,前一次粒子坐標和當前粒子坐標是完全一樣的。后面把這個bug改后。

  2.最后跟蹤物體的矩形采用權值最大粒子的矩形,而不是才用所以粒子的期望,經過試驗發現采用權值最大的粒子的效果要好些。

  3.計算粒子的權值改為采用的是巴斯距離。

 

  工程環境:opencv2.3.1+vs2010

  程序功能:驅動攝像頭,待程序運行后用鼠標單擊拖動選定需要跟蹤的目標,然后程序會自動跟蹤該目標。

  其程序代碼如下:

  1 // particle_tracking.cpp : 定義控制台應用程序的入口點。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <opencv2/core/core.hpp>
  6 #include "opencv2/imgproc/imgproc.hpp"
  7 #include <opencv2/highgui/highgui.hpp>
  8 #include <stdio.h>
  9 #include <iostream>
 10 
 11 using namespace cv;
 12 using namespace std;
 13 
 14 Rect select;
 15 bool select_flag=false;
 16 bool tracking=false;//跟蹤標志位
 17 bool select_show=false;
 18 Point origin;
 19 Mat frame,hsv;
 20 int after_select_frames=0;//選擇矩形區域完后的幀計數
 21 
 22 /****rgb空間用到的變量****/
 23 //int hist_size[]={16,16,16};//rgb空間各維度的bin個數
 24 //float rrange[]={0,255.0};
 25 //float grange[]={0,255.0};
 26 //float brange[]={0,255.0};
 27 //const float *ranges[] ={rrange,grange,brange};//range相當於一個二維數組指針
 28 
 29 /****hsv空間用到的變量****/
 30 int hist_size[]={16,16,16};
 31 float hrange[]={0,179.0};
 32 float srange[]={0,255.0};
 33 float vrange[]={0,255.0};
 34 
 35 //int hist_size[]={32,32,32};
 36 //float hrange[]={0,359.0.0};
 37 //float srange[]={0,1.0};
 38 //float vrange[]={0,1.0};
 39 const float *ranges[]={hrange,srange,vrange};
 40 
 41 int channels[]={0,1,2};
 42 
 43 /****有關粒子窗口變化用到的相關變量****/
 44 int A1=2;
 45 int A2=-1;
 46 int B0=1;
 47 double sigmax=1.0;
 48 double sigmay=0.5;
 49 double sigmas=0.001;
 50 
 51 /****定義使用粒子數目宏****/
 52 #define PARTICLE_NUMBER 100 //如果這個數設定太大,經測試這個數字超過25就會報錯,則在運行時將會出現錯誤
 53 
 54 /****定義粒子結構體****/
 55 typedef struct particle
 56 {
 57     int orix,oriy;//原始粒子坐標
 58     int x,y;//當前粒子的坐標
 59     double scale;//當前粒子窗口的尺寸
 60     int prex,prey;//上一幀粒子的坐標
 61     double prescale;//上一幀粒子窗口的尺寸
 62     Rect rect;//當前粒子矩形窗口
 63     Mat hist;//當前粒子窗口直方圖特征
 64     double weight;//當前粒子權值
 65 }PARTICLE;
 66 
 67 PARTICLE particles[PARTICLE_NUMBER];
 68 
 69 /************************************************************************************************************************/
 70 /****                            如果采用這個onMouse()函數的話,則可以畫出鼠標拖動矩形框的4種情形                        ****/
 71 /************************************************************************************************************************/
 72 void onMouse(int event,int x,int y,int,void*)
 73 {
 74     //Point origin;//不能在這個地方進行定義,因為這是基於消息響應的函數,執行完后origin就釋放了,所以達不到效果。
 75     if(select_flag)
 76     {
 77         select.x=MIN(origin.x,x);//不一定要等鼠標彈起才計算矩形框,而應該在鼠標按下開始到彈起這段時間實時計算所選矩形框
 78         select.y=MIN(origin.y,y);
 79         select.width=abs(x-origin.x);//算矩形寬度和高度
 80         select.height=abs(y-origin.y);
 81         select&=Rect(0,0,frame.cols,frame.rows);//保證所選矩形框在視頻顯示區域之內
 82 
 83         //        rectangle(frame,select,Scalar(0,0,255),3,8,0);//顯示手動選擇的矩形框
 84     }
 85     if(event==CV_EVENT_LBUTTONDOWN)
 86     {
 87         select_flag=true;//鼠標按下的標志賦真值
 88         tracking=false;
 89         select_show=true;
 90         after_select_frames=0;//還沒開始選擇,或者重新開始選擇,計數為0
 91         origin=Point(x,y);//保存下來單擊是捕捉到的點
 92         select=Rect(x,y,0,0);//這里一定要初始化,因為在opencv中Rect矩形框類內的點是包含左上角那個點的,但是不含右下角那個點。
 93     }
 94     else if(event==CV_EVENT_LBUTTONUP)
 95     {
 96         select_flag=false;
 97         tracking=true;
 98         select_show=false;
 99         after_select_frames=1;//選擇完后的那一幀當做第1幀
100     }
101 }
102 
103 /****粒子權值降序排列函數****/
104 int particle_decrease(const void *p1,const void *p2)
105 {
106     PARTICLE* _p1=(PARTICLE*)p1;
107     PARTICLE* _p2=(PARTICLE*)p2;
108     if(_p1->weight<_p2->weight)
109         return 1;
110     else if(_p1->weight>_p2->weight)
111         return -1;
112     return 0;//相等的情況下返回0
113 }
114 
115 int main(int argc, unsigned char* argv[])
116 {
117     char c;
118     Mat target_img,track_img;
119     Mat target_hist,track_hist;
120     PARTICLE *pParticle;
121 
122     /***打開攝像頭****/
123     VideoCapture cam(0);
124     if (!cam.isOpened())
125         return -1;
126 
127     /****建立窗口****/
128     namedWindow("camera",1);//顯示視頻原圖像的窗口
129 
130     /****捕捉鼠標****/
131     setMouseCallback("camera",onMouse,0);
132 
133     while(1)
134     {
135         /****讀取一幀圖像****/
136         cam>>frame;
137         if(frame.empty())
138             return -1;
139 
140         /****將rgb空間轉換為hsv空間****/
141         cvtColor(frame,hsv,CV_BGR2HSV);
142 
143         if(tracking)
144         {
145 
146             if(1==after_select_frames)//選擇完目標區域后
147             {
148                 /****計算目標模板的直方圖特征****/
149                 target_img=Mat(hsv,select);//在此之前先定義好target_img,然后這樣賦值也行,要學會Mat的這個操作
150                 calcHist(&target_img,1,channels,Mat(),target_hist,3,hist_size,ranges);
151                 normalize(target_hist,target_hist);
152 
153                 /****初始化目標粒子****/
154                 pParticle=particles;//指針初始化指向particles數組
155                 for(int x=0;x<PARTICLE_NUMBER;x++)
156                 {
157                     pParticle->x=cvRound(select.x+0.5*select.width);//選定目標矩形框中心為初始粒子窗口中心
158                     pParticle->y=cvRound(select.y+0.5*select.height);
159                     pParticle->orix=pParticle->x;//粒子的原始坐標為選定矩形框(即目標)的中心
160                     pParticle->oriy=pParticle->y;
161                     pParticle->prex=pParticle->x;//更新上一次的粒子位置
162                     pParticle->prey=pParticle->y;
163                     pParticle->rect=select;
164                     pParticle->prescale=1;
165                     pParticle->scale=1;
166                     pParticle->hist=target_hist;
167                     pParticle->weight=0;
168                     pParticle++;
169                 }
170             }
171             else if(2==after_select_frames)//從第二幀開始就可以開始跟蹤了
172             {
173                 double sum=0.0;
174                 pParticle=particles;
175                 RNG rng;//隨機數產生器
176 
177                 /****更新粒子結構體的大部分參數****/
178                 for(int i=0;i<PARTICLE_NUMBER;i++)
179                 {
180                     int x,y;
181                     int xpre,ypre;
182                     double s,pres;
183 
184                     xpre=pParticle->x;
185                     ypre=pParticle->y;
186                     pres=pParticle->scale;
187 
188                     /****更新粒子的矩形區域即粒子中心****/
189                     x=cvRound(A1*(pParticle->x-pParticle->orix)+A2*(pParticle->prex-pParticle->orix)+
190                         B0*rng.gaussian(sigmax)+pParticle->orix);
191                     pParticle->x=max(0,min(x,frame.cols-1));
192 
193                     y=cvRound(A1*(pParticle->y-pParticle->oriy)+A2*(pParticle->prey-pParticle->oriy)+
194                         B0*rng.gaussian(sigmay)+pParticle->oriy);
195                     pParticle->y=max(0,min(y,frame.rows-1));
196 
197                     s=A1*(pParticle->scale-1)+A2*(pParticle->prescale-1)+B0*(rng.gaussian(sigmas))+1.0;
198                     pParticle->scale=max(1.0,min(s,3.0));
199 
200                     pParticle->prex=xpre;
201                     pParticle->prey=ypre;
202                     pParticle->prescale=pres;
203             //        pParticle->orix=pParticle->orix;
204             //        pParticle->oriy=pParticle->oriy;
205 
206                     //注意在c語言中,x-1.0,如果x是int型,則這句語法有錯誤,但如果前面加了cvRound(x-0.5)則是正確的
207                     pParticle->rect.x=max(0,min(cvRound(pParticle->x-0.5*pParticle->scale*pParticle->rect.width),frame.cols));
208                     pParticle->rect.y=max(0,min(cvRound(pParticle->y-0.5*pParticle->scale*pParticle->rect.height),frame.rows));
209                     pParticle->rect.width=min(cvRound(pParticle->scale*pParticle->rect.width),frame.cols-pParticle->rect.x);
210                     pParticle->rect.height=min(cvRound(pParticle->scale*pParticle->rect.height),frame.rows-pParticle->rect.y);
211 
212                     /****計算粒子區域的新的直方圖特征****/
213                     track_img=Mat(hsv,pParticle->rect);
214                     calcHist(&track_img,1,channels,Mat(),track_hist,3,hist_size,ranges);
215                     normalize(track_hist,track_hist);
216 
217                     /****更新粒子的權值****/
218                     //            pParticle->weight=compareHist(target_hist,track_hist,CV_COMP_INTERSECT);
219                     pParticle->weight=1.0-compareHist(target_hist,track_hist,CV_COMP_BHATTACHARYYA);//采用巴氏系數計算相似度
220 
221                     /****累加粒子權值****/
222                     sum+=pParticle->weight;
223                     pParticle++;
224                 }
225 
226                 /****歸一化粒子權重****/
227                 pParticle=particles;
228                 for(int i=0;i<PARTICLE_NUMBER;i++)
229                 {
230                     pParticle->weight/=sum;
231                     pParticle++;
232                 }
233 
234                 /****根據粒子的權值降序排列****/
235                 pParticle=particles;
236                 qsort(pParticle,PARTICLE_NUMBER,sizeof(PARTICLE),&particle_decrease);
237 
238                 /****根據粒子權重重采樣粒子****/
239                 PARTICLE newParticle[PARTICLE_NUMBER];
240                 int np=0,k=0;
241                 for(int i=0;i<PARTICLE_NUMBER;i++)
242                 {
243                     np=cvRound(pParticle->weight*PARTICLE_NUMBER);
244                     for(int j=0;j<np;j++)
245                     {
246                         newParticle[k++]=particles[i];
247                         if(k==PARTICLE_NUMBER)
248                             goto EXITOUT;
249                     }
250                 }
251                 while(k<PARTICLE_NUMBER)
252                     newParticle[k++]=particles[0];
253 EXITOUT:
254                 for(int i=0;i<PARTICLE_NUMBER;i++)
255                     particles[i]=newParticle[i];
256             }//end else
257 
258             qsort(pParticle,PARTICLE_NUMBER,sizeof(PARTICLE),&particle_decrease);
259 
260             /****計算粒子期望,采用所有粒子位置的期望值做為跟蹤結果****/
261             /*Rect_<double> rectTrackingTemp(0.0,0.0,0.0,0.0);
262             pParticle=particles;
263             for(int i=0;i<PARTICLE_NUMBER;i++)
264             {
265                 rectTrackingTemp.x+=pParticle->rect.x*pParticle->weight;
266                 rectTrackingTemp.y+=pParticle->rect.y*pParticle->weight;
267                 rectTrackingTemp.width+=pParticle->rect.width*pParticle->weight;
268                 rectTrackingTemp.height+=pParticle->rect.height*pParticle->weight;
269                 pParticle++;
270             }*/
271 
272             /****計算最大權重目標的期望位置,作為跟蹤結果****/
273             Rect rectTrackingTemp(0,0,0,0);
274             pParticle=particles;
275             rectTrackingTemp.x=pParticle->x-0.5*pParticle->rect.width;
276             rectTrackingTemp.y=pParticle->y-0.5*pParticle->rect.height;
277             rectTrackingTemp.width=pParticle->rect.width;
278             rectTrackingTemp.height=pParticle->rect.height;
279 
280             /****計算最大權重目標的期望位置,采用權值最大的1/4個粒子數作為跟蹤結果****/
281             /*Rect rectTrackingTemp(0,0,0,0);
282             double weight_temp=0.0;
283             pParticle=particles;
284             for(int i=0;i<PARTICLE_NUMBER/4;i++)
285             {
286                 weight_temp+=pParticle->weight;
287                 pParticle++;
288             }
289             pParticle=particles;
290             for(int i=0;i<PARTICLE_NUMBER/4;i++)
291             {
292                 pParticle->weight/=weight_temp;
293                 pParticle++;
294             }
295             pParticle=particles;
296             for(int i=0;i<PARTICLE_NUMBER/4;i++)
297             {
298                 rectTrackingTemp.x+=pParticle->rect.x*pParticle->weight;
299                 rectTrackingTemp.y+=pParticle->rect.y*pParticle->weight;
300                 rectTrackingTemp.width+=pParticle->rect.width*pParticle->weight;
301                 rectTrackingTemp.height+=pParticle->rect.height*pParticle->weight;
302                 pParticle++;
303             }*/
304 
305 
306             //創建目標矩形區域
307             Rect tracking_rect(rectTrackingTemp);
308 
309             pParticle=particles;
310 
311             /****顯示各粒子運動結果****/
312             for(int m=0;m<PARTICLE_NUMBER;m++)
313             {
314                 rectangle(frame,pParticle->rect,Scalar(255,0,0),1,8,0);
315                 pParticle++;
316             }
317 
318             /****顯示跟蹤結果****/
319             rectangle(frame,tracking_rect,Scalar(0,0,255),3,8,0);
320 
321             after_select_frames++;//總循環每循環一次,計數加1
322             if(after_select_frames>2)//防止跟蹤太長,after_select_frames計數溢出
323                 after_select_frames=2;
324         }
325 
326         if(select_show)
327             rectangle(frame,select,Scalar(0,0,255),3,8,0);//顯示手動選擇的矩形框
328         //顯示視頻圖片到窗口
329         imshow("camera",frame);
330 
331         //    select.zeros();
332         //鍵盤響應
333         c=(char)waitKey(20);
334         if(27==c)//ESC鍵
335             return -1;
336     }
337 
338     return 0;
339 }

 

  但是該程序跟蹤效果不是很好,不是特別穩定,可能跟粒子數目有關。因為程序還有bug,粒子數目設置太大后,編譯通過。當運行時,手動選擇目標區域后就自動退出了,即鼠標一拖動完后就在終端顯示如下:

  

   Debug程序后出現的錯誤提示:

  

  后面試了下,當粒子數目大於等於53時,運行程序,手選目標區域后程序沒有自動退出,而是顯示如下錯誤提示:

  

  因此,程序只有當粒子數目小於53才能正常運行,但是由於粒子數目太少所以效果不是特別的好。

  等以后有時間來調試下內存方面的bug。

 

 

 

 


免責聲明!

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



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