fixed many warnings from GCC 4.6.1
[profile/ivi/opencv.git] / modules / legacy / src / blobtrackingmsfg.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //
12 // Copyright (C) 2000, Intel Corporation, all rights reserved.
13 // Third party copyrights are property of their respective owners.
14 //
15 // Redistribution and use in source and binary forms, with or without modification,
16 // are permitted provided that the following conditions are met:
17 //
18 //   * Redistribution's of source code must retain the above copyright notice,
19 //     this list of conditions and the following disclaimer.
20 //
21 //   * Redistribution's in binary form must reproduce the above copyright notice,
22 //     this list of conditions and the following disclaimer in the documentation
23 //     and/or other materials provided with the distribution.
24 //
25 //   * The name of Intel Corporation may not be used to endorse or promote products
26 //     derived from this software without specific prior written permission.
27 //
28 // This software is provided by the copyright holders and contributors "as is" and
29 // any express or implied warranties, including, but not limited to, the implied
30 // warranties of merchantability and fitness for a particular purpose are disclaimed.
31 // In no event shall the Intel Corporation or contributors be liable for any direct,
32 // indirect, incidental, special, exemplary, or consequential damages
33 // (including, but not limited to, procurement of substitute goods or services;
34 // loss of use, data, or profits; or business interruption) however caused
35 // and on any theory of liability, whether in contract, strict liability,
36 // or tort (including negligence or otherwise) arising in any way out of
37 // the use of this software, even if advised of the possibility of such damage.
38 //
39 //M*/
40
41 #include "precomp.hpp"
42
43 #ifdef _OPENMP
44 #include "omp.h"
45 #endif
46
47 // Uncomment to trade flexibility for speed
48 //#define CONST_HIST_SIZE
49
50 // Uncomment to get some performance stats in stderr
51 //#define REPORT_TICKS
52
53 #ifdef CONST_HIST_SIZE
54 #define m_BinBit 5
55 #define m_ByteShift 3
56 #endif
57
58 typedef float DefHistType;
59 #define DefHistTypeMat CV_32F
60 #define HIST_INDEX(_pData) (((_pData)[0]>>m_ByteShift) + (((_pData)[1]>>(m_ByteShift))<<m_BinBit)+((pImgData[2]>>m_ByteShift)<<(m_BinBit*2)))
61
62 class DefHist
63 {
64 public:
65     CvMat*          m_pHist;
66     DefHistType     m_HistVolume;
67     DefHist(int BinNum=0)
68     {
69         m_pHist = NULL;
70         m_HistVolume = 0;
71         Resize(BinNum);
72     }
73
74     ~DefHist()
75     {
76         if(m_pHist)cvReleaseMat(&m_pHist);
77     }
78
79     void Resize(int BinNum)
80     {
81         if(m_pHist)cvReleaseMat(&m_pHist);
82         if(BinNum>0)
83         {
84             m_pHist = cvCreateMat(1, BinNum, DefHistTypeMat);
85             cvZero(m_pHist);
86         }
87         m_HistVolume = 0;
88     }
89
90     void Update(DefHist* pH, float W)
91     {   /* Update histogram: */
92         double  Vol, WM, WC;
93         Vol = 0.5*(m_HistVolume + pH->m_HistVolume);
94         WM = Vol*(1-W)/m_HistVolume;
95         WC = Vol*(W)/pH->m_HistVolume;
96         cvAddWeighted(m_pHist, WM, pH->m_pHist,WC,0,m_pHist);
97         m_HistVolume = (float)cvSum(m_pHist).val[0];
98     }   /* Update histogram: */
99 };
100
101 class CvBlobTrackerOneMSFG:public CvBlobTrackerOne
102 {
103 protected:
104     int             m_BinNumTotal; /* protected only for parralel MSPF */
105     CvSize          m_ObjSize;
106
107     void ReAllocKernel(int  w, int h)
108     {
109         int     x,y;
110         float   x0 = 0.5f*(w-1);
111         float   y0 = 0.5f*(h-1);
112         assert(w>0);
113         assert(h>0);
114         m_ObjSize = cvSize(w,h);
115
116         if(m_KernelHist) cvReleaseMat(&m_KernelHist);
117         if(m_KernelMeanShift) cvReleaseMat(&m_KernelMeanShift);
118         m_KernelHist = cvCreateMat(h, w, DefHistTypeMat);
119         m_KernelMeanShift = cvCreateMat(h, w, DefHistTypeMat);
120
121         for(y=0; y<h; ++y) for(x=0; x<w; ++x)
122         {
123             double r2 = ((x-x0)*(x-x0)/(x0*x0)+(y-y0)*(y-y0)/(y0*y0));
124 //            double r2 = ((x-x0)*(x-x0)+(y-y0)*(y-y0))/((y0*y0)+(x0*x0));
125             CV_MAT_ELEM(m_KernelHist[0],DefHistType, y, x) = (DefHistType)GetKernelHist(r2);
126             CV_MAT_ELEM(m_KernelMeanShift[0],DefHistType, y, x) = (DefHistType)GetKernelMeanShift(r2);
127         }
128     }
129
130 private:
131     /* Parameters: */
132     int             m_IterNum;
133     float           m_FGWeight;
134     float           m_Alpha;
135     CvMat*          m_KernelHist;
136     CvMat*          m_KernelMeanShift;
137 #ifndef CONST_HIST_SIZE
138     int             m_BinBit;
139     int             m_ByteShift;
140 #endif
141     int             m_BinNum;
142     int             m_Dim;
143     /*
144     CvMat*          m_HistModel;
145     float           m_HistModelVolume;
146     CvMat*          m_HistCandidate;
147     float           m_HistCandidateVolume;
148     CvMat*          m_HistTemp;
149     */
150     DefHist         m_HistModel;
151     DefHist         m_HistCandidate;
152     DefHist         m_HistTemp;
153
154     CvBlob          m_Blob;
155     int             m_Collision;
156
157     void ReAllocHist(int Dim, int BinBit)
158     {
159 #ifndef CONST_HIST_SIZE
160         m_BinBit = BinBit;
161         m_ByteShift = 8-BinBit;
162 #endif
163         m_Dim = Dim;
164         m_BinNum = (1<<BinBit);
165         m_BinNumTotal = cvRound(pow((double)m_BinNum,(double)m_Dim));
166         /*
167         if(m_HistModel) cvReleaseMat(&m_HistModel);
168         if(m_HistCandidate) cvReleaseMat(&m_HistCandidate);
169         if(m_HistTemp) cvReleaseMat(&m_HistTemp);
170         m_HistCandidate = cvCreateMat(1, m_BinNumTotal, DefHistTypeMat);
171         m_HistModel = cvCreateMat(1, m_BinNumTotal, DefHistTypeMat);
172         m_HistTemp = cvCreateMat(1, m_BinNumTotal, DefHistTypeMat);
173         cvZero(m_HistCandidate);
174         cvZero(m_HistModel);
175         m_HistModelVolume = 0.0f;
176         m_HistCandidateVolume = 0.0f;
177         */
178         m_HistCandidate.Resize(m_BinNumTotal);
179         m_HistModel.Resize(m_BinNumTotal);
180         m_HistTemp.Resize(m_BinNumTotal);
181     }
182
183     double GetKernelHist(double r2)
184     {
185         return (r2 < 1) ? 1 -  r2 : 0;
186     }
187
188     double GetKernelMeanShift(double r2)
189     {
190         return (r2<1) ? 1 : 0;
191     }
192
193 //    void CollectHist(IplImage* pImg, IplImage* pMask, CvPoint Center, CvMat* pHist, DefHistType* pHistVolume)
194 //    void CollectHist(IplImage* pImg, IplImage* pMask, CvPoint Center, DefHist* pHist)
195
196     void CollectHist(IplImage* pImg, IplImage* pMask, CvBlob* pBlob, DefHist* pHist)
197     {
198         int UsePrecalculatedKernel = 0;
199         int BW = cvRound(pBlob->w);
200         int BH = cvRound(pBlob->h);
201         DefHistType Volume = 0;
202         int         x0 = cvRound(pBlob->x - BW*0.5);
203         int         y0 = cvRound(pBlob->y - BH*0.5);
204         int         x,y;
205
206         UsePrecalculatedKernel = (BW == m_ObjSize.width && BH == m_ObjSize.height ) ;
207
208         //cvZero(pHist);
209         cvSet(pHist->m_pHist,cvScalar(1.0/m_BinNumTotal)); /* no zero bins, all bins have very small value*/
210         Volume = 1;
211
212         assert(BW < pImg->width);
213         assert(BH < pImg->height);
214         if((x0+BW)>=pImg->width) BW=pImg->width-x0-1;
215         if((y0+BH)>=pImg->height) BH=pImg->height-y0-1;
216         if(x0<0){ x0=0;}
217         if(y0<0){ y0=0;}
218
219         if(m_Dim == 3)
220         {
221             for(y=0; y<BH; ++y)
222             {
223                 unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3);
224                 unsigned char* pMaskData = pMask?(&CV_IMAGE_ELEM(pMask,unsigned char,y+y0,x0)):NULL;
225                 DefHistType* pKernelData = NULL;
226
227                 if(UsePrecalculatedKernel)
228                 {
229                     pKernelData = ((DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelHist[0],y,0,sizeof(DefHistType)));
230                 }
231
232                 for(x=0; x<BW; ++x, pImgData+=3)
233                 {
234                     DefHistType K;
235                     int index = HIST_INDEX(pImgData);
236                     assert(index >= 0 && index < pHist->m_pHist->cols);
237
238                     if(UsePrecalculatedKernel)
239                     {
240                         K = pKernelData[x];
241                     }
242                     else
243                     {
244                         float dx = (x+x0-pBlob->x)/(pBlob->w*0.5f);
245                         float dy = (y+y0-pBlob->y)/(pBlob->h*0.5f);
246                         double r2 = dx*dx+dy*dy;
247                         K = (float)GetKernelHist(r2);
248                     }
249
250                     if(pMaskData)
251                     {
252                         K *= pMaskData[x]*0.003921568627450980392156862745098f;
253                     }
254                     Volume += K;
255                     ((DefHistType*)(pHist->m_pHist->data.ptr))[index] += K;
256
257                 }   /* Next column. */
258             }   /*  Next row. */
259         }   /* if m_Dim == 3. */
260
261         pHist->m_HistVolume = Volume;
262
263     };  /* CollectHist */
264
265     double calcBhattacharyya(DefHist* pHM = NULL, DefHist* pHC = NULL, DefHist* pHT = NULL)
266     {
267         if(pHM==NULL) pHM = &m_HistModel;
268         if(pHC==NULL) pHC = &m_HistCandidate;
269         if(pHT==NULL) pHT = &m_HistTemp;
270         if(pHC->m_HistVolume*pHM->m_HistVolume > 0)
271         {
272 #if 0
273             // Use CV functions:
274             cvMul(pHM->m_pHist,pHC->m_pHist,pHT->m_pHist);
275             cvPow(pHT->m_pHist,pHT->m_pHist,0.5);
276             return cvSum(pHT->m_pHist).val[0] / sqrt(pHC->m_HistVolume*pHM->m_HistVolume);
277 #else
278             // Do computations manually and let autovectorizer do the job:
279             DefHistType* hm=(DefHistType *)(pHM->m_pHist->data.ptr);
280             DefHistType* hc=(DefHistType *)(pHC->m_pHist->data.ptr);
281             //ht=(DefHistType *)(pHT->m_pHist->data.ptr);
282             int size = pHM->m_pHist->width*pHM->m_pHist->height;
283             double sum = 0.;
284             for(int i = 0; i < size; i++ )
285             {
286                 sum += sqrt(hm[i]*hc[i]);
287             }
288             return sum / sqrt(pHC->m_HistVolume*pHM->m_HistVolume);
289 #endif
290         }
291         return 0;
292     }   /* calcBhattacharyyaCoefficient. */
293
294 protected:
295     // double GetBhattacharyya(IplImage* pImg, IplImage* pImgFG, float x, float y, DefHist* pHist=NULL)
296     double GetBhattacharyya(IplImage* pImg, IplImage* pImgFG, CvBlob* pBlob, DefHist* pHist=NULL, int /*thread_number*/ = 0)
297     {
298         if(pHist==NULL)pHist = &m_HistTemp;
299         CollectHist(pImg, pImgFG, pBlob, pHist);
300         return calcBhattacharyya(&m_HistModel, pHist, pHist);
301     }
302
303     void UpdateModelHist(IplImage* pImg, IplImage* pImgFG, CvBlob* pBlob)
304     {
305         if(m_Alpha>0 && !m_Collision)
306         {   /* Update histogram: */
307             CollectHist(pImg, pImgFG, pBlob, &m_HistCandidate);
308             m_HistModel.Update(&m_HistCandidate, m_Alpha);
309         }   /* Update histogram. */
310
311     }   /* UpdateModelHist */
312
313 public:
314     CvBlobTrackerOneMSFG()
315     {
316
317         /* Add several parameters for external use: */
318         m_FGWeight = 2;
319         AddParam("FGWeight", &m_FGWeight);
320         CommentParam("FGWeight","Weight of FG mask using (0 - mask will not be used for tracking)");
321
322         m_Alpha = 0.01f;
323         AddParam("Alpha", &m_Alpha);
324         CommentParam("Alpha","Coefficient for model histogram updating (0 - hist is not upated)");
325
326         m_IterNum = 10;
327         AddParam("IterNum", &m_IterNum);
328         CommentParam("IterNum","Maximal number of iteration in meanshift operation");
329
330         /* Initialize internal data: */
331         m_Collision = 0;
332 //        m_BinBit=0;
333         m_Dim = 0;
334         /*
335         m_HistModel = NULL;
336         m_HistCandidate = NULL;
337         m_HistTemp = NULL;
338         */
339         m_KernelHist = NULL;
340         m_KernelMeanShift = NULL;
341         ReAllocHist(3,5);   /* 3D hist, each dim has 2^5 bins*/
342
343         SetModuleName("MSFG");
344     }
345
346     ~CvBlobTrackerOneMSFG()
347     {
348         /*
349         if(m_HistModel) cvReleaseMat(&m_HistModel);
350         if(m_HistCandidate) cvReleaseMat(&m_HistCandidate);
351         if(m_HistTemp) cvReleaseMat(&m_HistTemp);
352         */
353         if(m_KernelHist) cvReleaseMat(&m_KernelHist);
354         if(m_KernelMeanShift) cvReleaseMat(&m_KernelMeanShift);
355     }
356
357     /* Interface: */
358     virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL)
359     {
360         int w = cvRound(CV_BLOB_WX(pBlobInit));
361         int h = cvRound(CV_BLOB_WY(pBlobInit));
362         if(w<CV_BLOB_MINW)w=CV_BLOB_MINW;
363         if(h<CV_BLOB_MINH)h=CV_BLOB_MINH;
364         if(pImg)
365         {
366             if(w>pImg->width)w=pImg->width;
367             if(h>pImg->height)h=pImg->height;
368         }
369         ReAllocKernel(w,h);
370         if(pImg)
371             CollectHist(pImg, pImgFG, pBlobInit, &m_HistModel);
372         m_Blob = pBlobInit[0];
373     };
374
375     virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL)
376     {
377         int     iter;
378
379         if(pBlobPrev)
380         {
381             m_Blob = pBlobPrev[0];
382         }
383
384         {   /* Check blob size and realloc kernels if it is necessary: */
385             int w = cvRound(m_Blob.w);
386             int h = cvRound(m_Blob.h);
387             if( w != m_ObjSize.width || h!=m_ObjSize.height)
388             {
389                 ReAllocKernel(w,h);
390                 /* after this ( w != m_ObjSize.width || h!=m_ObjSize.height) shoiuld be false */
391             }
392         }   /* Check blob size and realloc kernels if it is necessary: */
393
394
395         for(iter=0; iter<m_IterNum; ++iter)
396         {
397             float   newx=0,newy=0,sum=0;
398             //int     x,y;
399             double  B0;
400
401             //CvPoint Center = cvPoint(cvRound(m_Blob.x),cvRound(m_Blob.y));
402             CollectHist(pImg, NULL, &m_Blob, &m_HistCandidate);
403             B0 = calcBhattacharyya();
404
405             if(m_Wnd)if(CV_BLOB_ID(pBlobPrev)==0 && iter == 0)
406             {   /* Debug: */
407                 IplImage*   pW = cvCloneImage(pImgFG);
408                 IplImage*   pWFG = cvCloneImage(pImgFG);
409                 int         x,y;
410
411                 cvZero(pW);
412                 cvZero(pWFG);
413
414                 assert(m_ObjSize.width < pImg->width);
415                 assert(m_ObjSize.height < pImg->height);
416
417                 /* Calculate shift vector: */
418                 for(y=0; y<pImg->height; ++y)
419                 {
420                     unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y,0);
421                     unsigned char* pMaskData = pImgFG?(&CV_IMAGE_ELEM(pImgFG,unsigned char,y,0)):NULL;
422
423                     for(x=0; x<pImg->width; ++x, pImgData+=3)
424                     {
425                         int         xk = cvRound(x-(m_Blob.x-m_Blob.w*0.5));
426                         int         yk = cvRound(y-(m_Blob.y-m_Blob.h*0.5));
427                         double      HM = 0;
428                         double      HC = 0;
429                         double      K;
430                         int index = HIST_INDEX(pImgData);
431                         assert(index >= 0 && index < m_BinNumTotal);
432
433                         if(fabs(x-m_Blob.x)>m_Blob.w*0.6) continue;
434                         if(fabs(y-m_Blob.y)>m_Blob.h*0.6) continue;
435
436                         if(xk < 0 || xk >= m_KernelMeanShift->cols) continue;
437                         if(yk < 0 || yk >= m_KernelMeanShift->rows) continue;
438
439                         if(m_HistModel.m_HistVolume>0)
440                             HM = ((DefHistType*)m_HistModel.m_pHist->data.ptr)[index]/m_HistModel.m_HistVolume;
441
442                         if(m_HistCandidate.m_HistVolume>0)
443                             HC = ((DefHistType*)m_HistCandidate.m_pHist->data.ptr)[index]/m_HistCandidate.m_HistVolume;
444
445                         K = *(DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelMeanShift[0],yk,xk,sizeof(DefHistType));
446
447                         if(HC>0)
448                         {
449                             double  V = sqrt(HM / HC);
450                             int     Vi = cvRound(V * 64);
451                             if(Vi < 0) Vi = 0;
452                             if(Vi > 255) Vi = 255;
453                             CV_IMAGE_ELEM(pW,uchar,y,x) = (uchar)Vi;
454
455                             V += m_FGWeight*(pMaskData?(pMaskData[x]/255.0f):0);
456                             V*=K;
457                             Vi = cvRound(V * 64);
458                             if(Vi < 0) Vi = 0;
459                             if(Vi > 255) Vi = 255;
460                             CV_IMAGE_ELEM(pWFG,uchar,y,x) = (uchar)Vi;
461                         }
462
463                     }   /* Next column. */
464                 }   /*  Next row. */
465
466                 //cvNamedWindow("MSFG_W",0);
467                 //cvShowImage("MSFG_W",pW);
468                 //cvNamedWindow("MSFG_WFG",0);
469                 //cvShowImage("MSFG_WFG",pWFG);
470                 //cvNamedWindow("MSFG_FG",0);
471                 //cvShowImage("MSFG_FG",pImgFG);
472
473                 //cvSaveImage("MSFG_W.bmp",pW);
474                 //cvSaveImage("MSFG_WFG.bmp",pWFG);
475                 //cvSaveImage("MSFG_FG.bmp",pImgFG);
476
477             }   /* Debug. */
478
479
480             /* Calculate new position by meanshift: */
481
482             /* Calculate new position: */
483             if(m_Dim == 3)
484             {
485                 int         x0 = cvRound(m_Blob.x - m_ObjSize.width*0.5);
486                 int         y0 = cvRound(m_Blob.y - m_ObjSize.height*0.5);
487                 int         x,y;
488
489                 assert(m_ObjSize.width < pImg->width);
490                 assert(m_ObjSize.height < pImg->height);
491
492                 /* Crop blob bounds: */
493                 if((x0+m_ObjSize.width)>=pImg->width) x0=pImg->width-m_ObjSize.width-1;
494                 if((y0+m_ObjSize.height)>=pImg->height) y0=pImg->height-m_ObjSize.height-1;
495                 if(x0<0){ x0=0;}
496                 if(y0<0){ y0=0;}
497
498                 /* Calculate shift vector: */
499                 for(y=0; y<m_ObjSize.height; ++y)
500                 {
501                     unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3);
502                     unsigned char* pMaskData = pImgFG?(&CV_IMAGE_ELEM(pImgFG,unsigned char,y+y0,x0)):NULL;
503                     DefHistType* pKernelData = (DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelMeanShift[0],y,0,sizeof(DefHistType));
504
505                     for(x=0; x<m_ObjSize.width; ++x, pImgData+=3)
506                     {
507                         DefHistType K = pKernelData[x];
508                         double      HM = 0;
509                         double      HC = 0;
510                         int index = HIST_INDEX(pImgData);
511                         assert(index >= 0 && index < m_BinNumTotal);
512
513                         if(m_HistModel.m_HistVolume>0)
514                             HM = ((DefHistType*)m_HistModel.m_pHist->data.ptr)[index]/m_HistModel.m_HistVolume;
515
516                         if(m_HistCandidate.m_HistVolume>0)
517                             HC = ((DefHistType*)m_HistCandidate.m_pHist->data.ptr)[index]/m_HistCandidate.m_HistVolume;
518
519                         if(HC>0)
520                         {
521                             double V = sqrt(HM / HC);
522                             if(!m_Collision && m_FGWeight>0 && pMaskData)
523                             {
524                                 V += m_FGWeight*(pMaskData[x]/255.0f);
525                             }
526                             K *= (float)MIN(V,100000.);
527                         }
528
529                         sum += K;
530                         newx += K*x;
531                         newy += K*y;
532                     }   /* Next column. */
533                 }   /*  Next row. */
534
535                 if(sum > 0)
536                 {
537                     newx /= sum;
538                     newy /= sum;
539                 }
540                 newx += x0;
541                 newy += y0;
542
543             }   /* if m_Dim == 3. */
544
545             /* Calculate new position by meanshift: */
546
547             for(;;)
548             {   /* Iterate using bahattcharrya coefficient: */
549                 double  B1;
550                 CvBlob  B = m_Blob;
551 //                CvPoint NewCenter = cvPoint(cvRound(newx),cvRound(newy));
552                 B.x = newx;
553                 B.y = newy;
554                 CollectHist(pImg, NULL, &B, &m_HistCandidate);
555                 B1 = calcBhattacharyya();
556                 if(B1 > B0) break;
557                 newx = 0.5f*(newx+m_Blob.x);
558                 newy = 0.5f*(newy+m_Blob.y);
559                 if(fabs(newx-m_Blob.x)<0.1 && fabs(newy-m_Blob.y)<0.1) break;
560             }   /* Iterate using bahattcharrya coefficient. */
561
562             if(fabs(newx-m_Blob.x)<0.5 && fabs(newy-m_Blob.y)<0.5) break;
563             m_Blob.x = newx;
564             m_Blob.y = newy;
565         }   /* Next iteration. */
566
567         while(!m_Collision && m_FGWeight>0)
568         {   /* Update size if no collision. */
569             float       Alpha = 0.04f;
570             CvBlob      NewBlob;
571             double      M00,X,Y,XX,YY;
572             CvMoments   m;
573             CvRect      r;
574             CvMat       mat;
575
576             r.width = cvRound(m_Blob.w*1.5+0.5);
577             r.height = cvRound(m_Blob.h*1.5+0.5);
578             r.x = cvRound(m_Blob.x - 0.5*r.width);
579             r.y = cvRound(m_Blob.y - 0.5*r.height);
580             if(r.x < 0) break;
581             if(r.y < 0) break;
582             if(r.x+r.width >= pImgFG->width) break;
583             if(r.y+r.height >= pImgFG->height) break;
584             if(r.height < 5 || r.width < 5) break;
585
586             cvMoments( cvGetSubRect(pImgFG,&mat,r), &m, 0 );
587             M00 = cvGetSpatialMoment( &m, 0, 0 );
588             if(M00 <= 0 ) break;
589             X = cvGetSpatialMoment( &m, 1, 0 )/M00;
590             Y = cvGetSpatialMoment( &m, 0, 1 )/M00;
591             XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X;
592             YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y;
593             NewBlob = cvBlob(r.x+(float)X,r.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY)));
594
595             NewBlob.w = Alpha*NewBlob.w+m_Blob.w*(1-Alpha);
596             NewBlob.h = Alpha*NewBlob.h+m_Blob.h*(1-Alpha);
597
598             m_Blob.w = MAX(NewBlob.w,5);
599             m_Blob.h = MAX(NewBlob.h,5);
600             break;
601
602         }   /* Update size if no collision. */
603
604         return &m_Blob;
605
606     };  /* CvBlobTrackerOneMSFG::Process */
607
608     virtual double GetConfidence(CvBlob* pBlob, IplImage* pImg, IplImage* /*pImgFG*/ = NULL, IplImage* pImgUnusedReg = NULL)
609     {
610         double  S = 0.2;
611         double  B = GetBhattacharyya(pImg, pImgUnusedReg, pBlob, &m_HistTemp);
612         return exp((B-1)/(2*S));
613
614     };  /*CvBlobTrackerOneMSFG::*/
615
616     virtual void Update(CvBlob* pBlob, IplImage* pImg, IplImage* pImgFG = NULL)
617     {   /* Update histogram: */
618         UpdateModelHist(pImg, pImgFG, pBlob?pBlob:&m_Blob);
619     }   /*CvBlobTrackerOneMSFG::*/
620
621     virtual void Release(){delete this;};
622     virtual void SetCollision(int CollisionFlag)
623     {
624         m_Collision = CollisionFlag;
625     }
626     virtual void SaveState(CvFileStorage* fs)
627     {
628         cvWriteStruct(fs, "Blob", &m_Blob, "ffffi");
629         cvWriteInt(fs,"Collision", m_Collision);
630         cvWriteInt(fs,"HistVolume", cvRound(m_HistModel.m_HistVolume));
631         cvWrite(fs,"Hist", m_HistModel.m_pHist);
632     };
633     virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
634     {
635         CvMat* pM;
636         cvReadStructByName(fs, node, "Blob",&m_Blob, "ffffi");
637         m_Collision = cvReadIntByName(fs,node,"Collision",m_Collision);
638         pM = (CvMat*)cvRead(fs,cvGetFileNodeByName(fs,node,"Hist"));
639         if(pM)
640         {
641             m_HistModel.m_pHist = pM;
642             m_HistModel.m_HistVolume = (float)cvSum(pM).val[0];
643         }
644     };
645
646 };  /*CvBlobTrackerOneMSFG*/
647
648 #if 0
649 void CvBlobTrackerOneMSFG::CollectHist(IplImage* pImg, IplImage* pMask, CvBlob* pBlob, DefHist* pHist)
650 {
651     int UsePrecalculatedKernel = 0;
652     int BW = cvRound(pBlob->w);
653     int BH = cvRound(pBlob->h);
654     DefHistType Volume = 0;
655     int         x0 = cvRound(pBlob->x - BW*0.5);
656     int         y0 = cvRound(pBlob->y - BH*0.5);
657     int         x,y;
658
659     UsePrecalculatedKernel = (BW == m_ObjSize.width && BH == m_ObjSize.height ) ;
660
661     //cvZero(pHist);
662     cvSet(pHist->m_pHist,cvScalar(1.0/m_BinNumTotal)); /* no zero bins, all bins have very small value*/
663     Volume = 1;
664
665     assert(BW < pImg->width);
666     assert(BH < pImg->height);
667     if((x0+BW)>=pImg->width) BW=pImg->width-x0-1;
668     if((y0+BH)>=pImg->height) BH=pImg->height-y0-1;
669     if(x0<0){ x0=0;}
670     if(y0<0){ y0=0;}
671
672     if(m_Dim == 3)
673     {
674         for(y=0; y<BH; ++y)
675         {
676             unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3);
677             unsigned char* pMaskData = pMask?(&CV_IMAGE_ELEM(pMask,unsigned char,y+y0,x0)):NULL;
678             DefHistType* pKernelData = NULL;
679
680             if(UsePrecalculatedKernel)
681             {
682                 pKernelData = ((DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelHist[0],y,0,sizeof(DefHistType)));
683             }
684
685             for(x=0; x<BW; ++x, pImgData+=3)
686             {
687                 DefHistType K;
688                 int index = HIST_INDEX(pImgData);
689                 assert(index >= 0 && index < pHist->m_pHist->cols);
690
691                 if(UsePrecalculatedKernel)
692                 {
693                     K = pKernelData[x];
694                 }
695                 else
696                 {
697                     float dx = (x+x0-pBlob->x)/(pBlob->w*0.5);
698                     float dy = (y+y0-pBlob->y)/(pBlob->h*0.5);
699                     double r2 = dx*dx+dy*dy;
700                     K = GetKernelHist(r2);
701                 }
702
703                 if(pMaskData)
704                 {
705                     K *= pMaskData[x]*0.003921568627450980392156862745098;
706                 }
707                 Volume += K;
708                 ((DefHistType*)(pHist->m_pHist->data.ptr))[index] += K;
709
710             }   /* Next column. */
711         }   /*  Next row. */
712     }   /*  if m_Dim == 3. */
713
714     pHist->m_HistVolume = Volume;
715
716 };  /* CollectHist */
717 #endif
718
719 CvBlobTrackerOne* cvCreateBlobTrackerOneMSFG()
720 {
721     return (CvBlobTrackerOne*) new CvBlobTrackerOneMSFG;
722 }
723
724 CvBlobTracker* cvCreateBlobTrackerMSFG()
725 {
726     return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMSFG);
727 }
728
729 /* Create specific tracker without FG
730  * usin - just simple mean-shift tracker: */
731 class CvBlobTrackerOneMS:public CvBlobTrackerOneMSFG
732 {
733 public:
734     CvBlobTrackerOneMS()
735     {
736         SetParam("FGWeight",0);
737         DelParam("FGWeight");
738         SetModuleName("MS");
739     };
740 };
741
742 CvBlobTrackerOne* cvCreateBlobTrackerOneMS()
743 {
744     return (CvBlobTrackerOne*) new CvBlobTrackerOneMS;
745 }
746
747 CvBlobTracker* cvCreateBlobTrackerMS()
748 {
749     return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMS);
750 }
751
752 typedef struct DefParticle
753 {
754     CvBlob  blob;
755     float   Vx,Vy;
756     double  W;
757 } DefParticle;
758
759 class CvBlobTrackerOneMSPF:public CvBlobTrackerOneMS
760 {
761 private:
762     /* parameters */
763     int             m_ParticleNum;
764     float           m_UseVel;
765     float           m_SizeVar;
766     float           m_PosVar;
767
768     CvSize          m_ImgSize;
769     CvBlob          m_Blob;
770     DefParticle*    m_pParticlesPredicted;
771     DefParticle*    m_pParticlesResampled;
772     CvRNG           m_RNG;
773 #ifdef _OPENMP
774     int             m_ThreadNum;
775     DefHist*        m_HistForParalel;
776 #endif
777
778 public:
779     virtual void SaveState(CvFileStorage* fs)
780     {
781         CvBlobTrackerOneMS::SaveState(fs);
782         cvWriteInt(fs,"ParticleNum",m_ParticleNum);
783         cvWriteStruct(fs,"ParticlesPredicted",m_pParticlesPredicted,"ffffiffd",m_ParticleNum);
784         cvWriteStruct(fs,"ParticlesResampled",m_pParticlesResampled,"ffffiffd",m_ParticleNum);
785     };
786
787     virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
788     {
789         //CvMat* pM;
790         CvBlobTrackerOneMS::LoadState(fs,node);
791         m_ParticleNum = cvReadIntByName(fs,node,"ParticleNum",m_ParticleNum);
792         if(m_ParticleNum>0)
793         {
794             Realloc();
795             printf("sizeof(DefParticle) is %d\n", (int)sizeof(DefParticle));
796             cvReadStructByName(fs,node,"ParticlesPredicted",m_pParticlesPredicted,"ffffiffd");
797             cvReadStructByName(fs,node,"ParticlesResampled",m_pParticlesResampled,"ffffiffd");
798         }
799     };
800     CvBlobTrackerOneMSPF()
801     {
802         m_pParticlesPredicted = NULL;
803         m_pParticlesResampled = NULL;
804         m_ParticleNum = 200;
805
806         AddParam("ParticleNum",&m_ParticleNum);
807         CommentParam("ParticleNum","Number of particles");
808         Realloc();
809
810         m_UseVel = 0;
811         AddParam("UseVel",&m_UseVel);
812         CommentParam("UseVel","Percent of particles which use velocity feature");
813
814         m_SizeVar = 0.05f;
815         AddParam("SizeVar",&m_SizeVar);
816         CommentParam("SizeVar","Size variation (in object size)");
817
818         m_PosVar = 0.2f;
819         AddParam("PosVar",&m_PosVar);
820         CommentParam("PosVar","Position variation (in object size)");
821
822         m_RNG = cvRNG(0);
823
824         SetModuleName("MSPF");
825
826 #ifdef _OPENMP
827         {
828             m_ThreadNum = omp_get_num_procs();
829             m_HistForParalel = new DefHist[m_ThreadNum];
830         }
831 #endif
832     }
833
834     ~CvBlobTrackerOneMSPF()
835     {
836         if(m_pParticlesResampled)cvFree(&m_pParticlesResampled);
837         if(m_pParticlesPredicted)cvFree(&m_pParticlesPredicted);
838 #ifdef _OPENMP
839         if(m_HistForParalel) delete[] m_HistForParalel;
840 #endif
841     }
842
843 private:
844     void Realloc()
845     {
846         if(m_pParticlesResampled)cvFree(&m_pParticlesResampled);
847         if(m_pParticlesPredicted)cvFree(&m_pParticlesPredicted);
848         m_pParticlesPredicted = (DefParticle*)cvAlloc(sizeof(DefParticle)*m_ParticleNum);
849         m_pParticlesResampled = (DefParticle*)cvAlloc(sizeof(DefParticle)*m_ParticleNum);
850     };  /* Realloc*/
851
852     void DrawDebug(IplImage* pImg, IplImage* /*pImgFG*/)
853     {
854         int k;
855         for(k=0; k<2; ++k)
856         {
857             DefParticle*    pBP = k?m_pParticlesResampled:m_pParticlesPredicted;
858             //const char*   name = k?"MSPF resampled particle":"MSPF Predicted particle";
859             IplImage*       pI = cvCloneImage(pImg);
860             int             h,hN = m_ParticleNum;
861             CvBlob          C = cvBlob(0,0,0,0);
862             double          WS = 0;
863             for(h=0; h<hN; ++h)
864             {
865                 CvBlob  B = pBP[h].blob;
866                 int     CW = cvRound(255*pBP[h].W);
867                 CvBlob* pB = &B;
868                 int x = cvRound(CV_BLOB_RX(pB)), y = cvRound(CV_BLOB_RY(pB));
869                 CvSize  s = cvSize(MAX(1,x), MAX(1,y));
870                 double  W = pBP[h].W;
871                 C.x += pB->x;
872                 C.y += pB->y;
873                 C.w += pB->w;
874                 C.h += pB->h;
875                 WS+=W;
876
877                 s = cvSize(1,1);
878                 cvEllipse( pI,
879                     cvPointFrom32f(CV_BLOB_CENTER(pB)),
880                     s,
881                     0, 0, 360,
882                     CV_RGB(CW,0,0), 1 );
883
884             }   /* Next hypothesis. */
885
886             C.x /= hN;
887             C.y /= hN;
888             C.w /= hN;
889             C.h /= hN;
890
891             cvEllipse( pI,
892                 cvPointFrom32f(CV_BLOB_CENTER(&C)),
893                 cvSize(cvRound(C.w*0.5),cvRound(C.h*0.5)),
894                 0, 0, 360,
895                 CV_RGB(0,0,255), 1 );
896
897             cvEllipse( pI,
898                 cvPointFrom32f(CV_BLOB_CENTER(&m_Blob)),
899                 cvSize(cvRound(m_Blob.w*0.5),cvRound(m_Blob.h*0.5)),
900                 0, 0, 360,
901                 CV_RGB(0,255,0), 1 );
902
903             //cvNamedWindow(name,0);
904             //cvShowImage(name,pI);
905             cvReleaseImage(&pI);
906         } /*  */
907
908         //printf("Blob %d, point (%.1f,%.1f) size (%.1f,%.1f)\n",m_Blob.ID,m_Blob.x,m_Blob.y,m_Blob.w,m_Blob.h);
909     } /* ::DrawDebug */
910
911 private:
912     void Prediction()
913     {
914         int p;
915         for(p=0; p<m_ParticleNum; ++p)
916         {   /* "Prediction" of particle: */
917             //double  t;
918             float   r[5];
919             CvMat   rm = cvMat(1,5,CV_32F,r);
920             cvRandArr(&m_RNG,&rm,CV_RAND_NORMAL,cvScalar(0),cvScalar(1));
921
922             m_pParticlesPredicted[p] = m_pParticlesResampled[p];
923
924             if(cvRandReal(&m_RNG)<0.5)
925             {   /* Half of particles will predict based on external blob: */
926                 m_pParticlesPredicted[p].blob = m_Blob;
927             }
928
929             if(cvRandReal(&m_RNG)<m_UseVel)
930             {   /* Predict moving particle by usual way by using speed: */
931                 m_pParticlesPredicted[p].blob.x += m_pParticlesPredicted[p].Vx;
932                 m_pParticlesPredicted[p].blob.y += m_pParticlesPredicted[p].Vy;
933             }
934             else
935             {   /* Stop several particles: */
936                 m_pParticlesPredicted[p].Vx = 0;
937                 m_pParticlesPredicted[p].Vy = 0;
938             }
939
940             {   /* Update position: */
941                 float S = (m_Blob.w + m_Blob.h)*0.5f;
942                 m_pParticlesPredicted[p].blob.x += m_PosVar*S*r[0];
943                 m_pParticlesPredicted[p].blob.y += m_PosVar*S*r[1];
944
945                 /* Update velocity: */
946                 m_pParticlesPredicted[p].Vx += (float)(m_PosVar*S*0.1*r[3]);
947                 m_pParticlesPredicted[p].Vy += (float)(m_PosVar*S*0.1*r[4]);
948             }
949
950             /* Update size: */
951             m_pParticlesPredicted[p].blob.w *= (1+m_SizeVar*r[2]);
952             m_pParticlesPredicted[p].blob.h *= (1+m_SizeVar*r[2]);
953
954             /* Truncate size of particle: */
955             if(m_pParticlesPredicted[p].blob.w > m_ImgSize.width*0.5f)
956             {
957                 m_pParticlesPredicted[p].blob.w = m_ImgSize.width*0.5f;
958             }
959
960             if(m_pParticlesPredicted[p].blob.h > m_ImgSize.height*0.5f)
961             {
962                 m_pParticlesPredicted[p].blob.h = m_ImgSize.height*0.5f;
963             }
964
965             if(m_pParticlesPredicted[p].blob.w < 1 )
966             {
967                 m_pParticlesPredicted[p].blob.w = 1;
968             }
969
970             if(m_pParticlesPredicted[p].blob.h < 1)
971             {
972                 m_pParticlesPredicted[p].blob.h = 1;
973             }
974         }   /* "Prediction" of particle. */
975     }   /* Prediction */
976
977     void UpdateWeightsMS(IplImage* pImg, IplImage* /*pImgFG*/)
978     {
979         int p;
980 #ifdef _OPENMP
981         if( m_HistForParalel[0].m_pHist==NULL || m_HistForParalel[0].m_pHist->cols != m_BinNumTotal)
982         {
983             int t;
984             for(t=0; t<m_ThreadNum; ++t)
985                 m_HistForParalel[t].Resize(m_BinNumTotal);
986         }
987 #endif
988
989 #ifdef _OPENMP
990 #pragma omp parallel for num_threads(m_ThreadNum) schedule(runtime)
991 #endif
992         for(p=0;p<m_ParticleNum;++p)
993         {   /* Calculate weights for particles: */
994             double  S = 0.2;
995             double  B = 0;
996 #ifdef _OPENMP
997             assert(omp_get_thread_num()<m_ThreadNum);
998 #endif
999
1000             B = GetBhattacharyya(
1001                 pImg, NULL,
1002                 &(m_pParticlesPredicted[p].blob)
1003 #ifdef _OPENMP
1004                 ,&(m_HistForParalel[omp_get_thread_num()])
1005 #endif
1006                 );
1007             m_pParticlesPredicted[p].W *= exp((B-1)/(2*S));
1008
1009         }   /* Calculate weights for particles. */
1010     }
1011
1012     void UpdateWeightsCC(IplImage* /*pImg*/, IplImage* /*pImgFG*/)
1013     {
1014         int p;
1015 #ifdef _OPENMP
1016 #pragma omp parallel for
1017 #endif
1018         for(p=0; p<m_ParticleNum; ++p)
1019         {   /* Calculate weights for particles: */
1020             double W = 1;
1021             m_pParticlesPredicted[p].W *= W;
1022         }   /* Calculate weights for particles. */
1023     }
1024
1025     void Resample()
1026     {   /* Resample particle: */
1027         int         p;
1028         double      Sum = 0;
1029
1030         for(p=0; p<m_ParticleNum; ++p)
1031         {
1032             Sum += m_pParticlesPredicted[p].W;
1033         }
1034
1035         for(p=0; p<m_ParticleNum; ++p)
1036         {
1037             double  T = Sum * cvRandReal(&m_RNG);   /* Set current random threshold for cululative weight. */
1038             int     p2;
1039             double  Sum2 = 0;
1040
1041             for(p2=0; p2<m_ParticleNum; ++p2)
1042             {
1043                 Sum2 += m_pParticlesPredicted[p2].W;
1044                 if(Sum2 >= T)break;
1045             }
1046
1047             if(p2>=m_ParticleNum)p2=m_ParticleNum-1;
1048             m_pParticlesResampled[p] = m_pParticlesPredicted[p2];
1049             m_pParticlesResampled[p].W = 1;
1050
1051         }   /* Find next particle. */
1052     }   /*  Resample particle. */
1053
1054
1055 public:
1056     virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL)
1057     {
1058         int i;
1059         CvBlobTrackerOneMSFG::Init(pBlobInit, pImg, pImgFG);
1060         DefParticle PP;
1061         PP.W = 1;
1062         PP.Vx = 0;
1063         PP.Vy = 0;
1064         PP.blob = pBlobInit[0];
1065         for(i=0;i<m_ParticleNum;++i)
1066         {
1067             m_pParticlesPredicted[i] = PP;
1068             m_pParticlesResampled[i] = PP;
1069         }
1070         m_Blob = pBlobInit[0];
1071
1072     }   /* CvBlobTrackerOneMSPF::Init*/
1073
1074     virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL)
1075     {
1076         int p;
1077
1078         m_ImgSize.width = pImg->width;
1079         m_ImgSize.height = pImg->height;
1080
1081
1082         m_Blob = pBlobPrev[0];
1083
1084         {   /* Check blob size and realloc kernels if it is necessary: */
1085             int w = cvRound(m_Blob.w);
1086             int h = cvRound(m_Blob.h);
1087             if( w != m_ObjSize.width || h!=m_ObjSize.height)
1088             {
1089                 ReAllocKernel(w,h);
1090                 /* After this ( w != m_ObjSize.width || h!=m_ObjSize.height) should be false. */
1091             }
1092         }   /* Check blob size and realloc kernels if it is necessary. */
1093
1094         Prediction();
1095
1096 #ifdef REPORT_TICKS
1097         int64 ticks = cvGetTickCount();
1098 #endif
1099
1100         UpdateWeightsMS(pImg, pImgFG);
1101
1102 #ifdef REPORT_TICKS
1103         ticks = cvGetTickCount() - ticks;
1104         fprintf(stderr, "PF UpdateWeights, %d ticks\n",  (int)ticks);
1105         ticks = cvGetTickCount();
1106 #endif
1107
1108         Resample();
1109
1110 #ifdef REPORT_TICKS
1111         ticks = cvGetTickCount() - ticks;
1112         fprintf(stderr, "PF Resampling, %d ticks\n",  (int)ticks);
1113 #endif
1114
1115         {   /* Find average result: */
1116             float   x = 0;
1117             float   y = 0;
1118             float   w = 0;
1119             float   h = 0;
1120             float   Sum = 0;
1121
1122             DefParticle* pP = m_pParticlesResampled;
1123
1124             for(p=0; p<m_ParticleNum; ++p)
1125             {
1126                 float W = (float)pP[p].W;
1127                 x += W*pP[p].blob.x;
1128                 y += W*pP[p].blob.y;
1129                 w += W*pP[p].blob.w;
1130                 h += W*pP[p].blob.h;
1131                 Sum += W;
1132             }
1133
1134             if(Sum>0)
1135             {
1136                 m_Blob.x = x / Sum;
1137                 m_Blob.y = y / Sum;
1138                 m_Blob.w = w / Sum;
1139                 m_Blob.h = h / Sum;
1140             }
1141         }   /* Find average result. */
1142
1143         if(m_Wnd)
1144         {
1145             DrawDebug(pImg, pImgFG);
1146         }
1147
1148         return &m_Blob;
1149
1150     }   /* CvBlobTrackerOneMSPF::Process */
1151
1152     virtual void SkipProcess(CvBlob* pBlob, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL)
1153     {
1154         int p;
1155         for(p=0; p<m_ParticleNum; ++p)
1156         {
1157             m_pParticlesResampled[p].blob = pBlob[0];
1158             m_pParticlesResampled[p].Vx = 0;
1159             m_pParticlesResampled[p].Vy = 0;
1160             m_pParticlesResampled[p].W = 1;
1161         }
1162     }
1163
1164     virtual void Release(){delete this;};
1165     virtual void ParamUpdate()
1166     {
1167         Realloc();
1168     }
1169
1170 };  /* CvBlobTrackerOneMSPF */
1171
1172 CvBlobTrackerOne* cvCreateBlobTrackerOneMSPF()
1173 {
1174     return (CvBlobTrackerOne*) new CvBlobTrackerOneMSPF;
1175 }
1176
1177 CvBlobTracker* cvCreateBlobTrackerMSPF()
1178 {
1179     return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMSPF);
1180 }
1181