1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
12 // Copyright (C) 2000, Intel Corporation, all rights reserved.
13 // Third party copyrights are property of their respective owners.
15 // Redistribution and use in source and binary forms, with or without modification,
16 // are permitted provided that the following conditions are met:
18 // * Redistribution's of source code must retain the above copyright notice,
19 // this list of conditions and the following disclaimer.
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.
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.
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.
43 // Uncomment to trade flexibility for speed
44 //#define CONST_HIST_SIZE
46 // Uncomment to get some performance stats in stderr
47 //#define REPORT_TICKS
49 #ifdef CONST_HIST_SIZE
54 typedef float DefHistType;
55 #define DefHistTypeMat CV_32F
56 #define HIST_INDEX(_pData) (((_pData)[0]>>m_ByteShift) + (((_pData)[1]>>(m_ByteShift))<<m_BinBit)+((pImgData[2]>>m_ByteShift)<<(m_BinBit*2)))
62 DefHistType m_HistVolume;
71 if(m_pHist)cvReleaseMat(&m_pHist);
73 void Resize(int BinNum)
75 if(m_pHist)cvReleaseMat(&m_pHist);
78 m_pHist = cvCreateMat(1, BinNum, DefHistTypeMat);
83 void Update(DefHist* pH, float W)
86 Vol = 0.5*(m_HistVolume + pH->m_HistVolume);
87 WM = Vol*(1-W)/m_HistVolume;
88 WC = Vol*(W)/pH->m_HistVolume;
89 cvAddWeighted(m_pHist, WM, pH->m_pHist,WC,0,m_pHist);
90 m_HistVolume = (float)cvSum(m_pHist).val[0];
94 class CvBlobTrackerOneMSFG:public CvBlobTrackerOne
97 int m_BinNumTotal; /* protected only for parralel MSPF */
99 void ReAllocKernel(int w, int h)
102 float x0 = 0.5f*(w-1);
103 float y0 = 0.5f*(h-1);
106 m_ObjSize = cvSize(w,h);
108 if(m_KernelHist) cvReleaseMat(&m_KernelHist);
109 if(m_KernelMeanShift) cvReleaseMat(&m_KernelMeanShift);
110 m_KernelHist = cvCreateMat(h, w, DefHistTypeMat);
111 m_KernelMeanShift = cvCreateMat(h, w, DefHistTypeMat);
112 for(y=0;y<h;++y)for(x=0;x<w;++x)
114 double r2 = ((x-x0)*(x-x0)/(x0*x0)+(y-y0)*(y-y0)/(y0*y0));
115 // double r2 = ((x-x0)*(x-x0)+(y-y0)*(y-y0))/((y0*y0)+(x0*x0));
116 CV_MAT_ELEM(m_KernelHist[0],DefHistType, y, x) = (DefHistType)GetKernelHist(r2);
117 CV_MAT_ELEM(m_KernelMeanShift[0],DefHistType, y, x) = (DefHistType)GetKernelMeanShift(r2);
126 CvMat* m_KernelMeanShift;
127 #ifndef CONST_HIST_SIZE
135 float m_HistModelVolume;
136 CvMat* m_HistCandidate;
137 float m_HistCandidateVolume;
141 DefHist m_HistCandidate;
147 void ReAllocHist(int Dim, int BinBit)
149 #ifndef CONST_HIST_SIZE
151 m_ByteShift = 8-BinBit;
154 m_BinNum = (1<<BinBit);
155 m_BinNumTotal = cvRound(pow((double)m_BinNum,(double)m_Dim));
157 if(m_HistModel) cvReleaseMat(&m_HistModel);
158 if(m_HistCandidate) cvReleaseMat(&m_HistCandidate);
159 if(m_HistTemp) cvReleaseMat(&m_HistTemp);
160 m_HistCandidate = cvCreateMat(1, m_BinNumTotal, DefHistTypeMat);
161 m_HistModel = cvCreateMat(1, m_BinNumTotal, DefHistTypeMat);
162 m_HistTemp = cvCreateMat(1, m_BinNumTotal, DefHistTypeMat);
163 cvZero(m_HistCandidate);
165 m_HistModelVolume = 0.0f;
166 m_HistCandidateVolume = 0.0f;
168 m_HistCandidate.Resize(m_BinNumTotal);
169 m_HistModel.Resize(m_BinNumTotal);
170 m_HistTemp.Resize(m_BinNumTotal);
172 double GetKernelHist(double r2)
174 return (r2 < 1) ? 1 - r2 : 0;
176 double GetKernelMeanShift(double r2)
178 return (r2<1) ? 1 : 0;
180 // void CollectHist(IplImage* pImg, IplImage* pMask, CvPoint Center, CvMat* pHist, DefHistType* pHistVolume)
181 // void CollectHist(IplImage* pImg, IplImage* pMask, CvPoint Center, DefHist* pHist)
182 void CollectHist(IplImage* pImg, IplImage* pMask, CvBlob* pBlob, DefHist* pHist)
184 int UsePrecalculatedKernel = 0;
185 int BW = cvRound(pBlob->w);
186 int BH = cvRound(pBlob->h);
187 DefHistType Volume = 0;
188 int x0 = cvRound(pBlob->x - BW*0.5);
189 int y0 = cvRound(pBlob->y - BH*0.5);
192 UsePrecalculatedKernel = (BW == m_ObjSize.width && BH == m_ObjSize.height ) ;
195 cvSet(pHist->m_pHist,cvScalar(1.0/m_BinNumTotal)); /* no zero bins, all bins have very small value*/
198 assert(BW < pImg->width);
199 assert(BH < pImg->height);
200 if((x0+BW)>=pImg->width) BW=pImg->width-x0-1;
201 if((y0+BH)>=pImg->height) BH=pImg->height-y0-1;
209 unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3);
210 unsigned char* pMaskData = pMask?(&CV_IMAGE_ELEM(pMask,unsigned char,y+y0,x0)):NULL;
211 DefHistType* pKernelData = NULL;
212 if(UsePrecalculatedKernel)
214 pKernelData = ((DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelHist[0],y,0,sizeof(DefHistType)));
216 for(x=0;x<BW;++x,pImgData+=3)
219 int index = HIST_INDEX(pImgData);
220 assert(index >= 0 && index < pHist->m_pHist->cols);
221 if(UsePrecalculatedKernel)
227 float dx = (x+x0-pBlob->x)/(pBlob->w*0.5f);
228 float dy = (y+y0-pBlob->y)/(pBlob->h*0.5f);
229 double r2 = dx*dx+dy*dy;
230 K = (float)GetKernelHist(r2);
235 K *= pMaskData[x]*0.003921568627450980392156862745098f;
238 ((DefHistType*)(pHist->m_pHist->data.ptr))[index] += K;
242 pHist->m_HistVolume = Volume;
244 double calcBhattacharyya(DefHist* pHM = NULL, DefHist* pHC = NULL, DefHist* pHT = NULL)
246 if(pHM==NULL) pHM = &m_HistModel;
247 if(pHC==NULL) pHC = &m_HistCandidate;
248 if(pHT==NULL) pHT = &m_HistTemp;
249 if(pHC->m_HistVolume*pHM->m_HistVolume > 0)
253 cvMul(pHM->m_pHist,pHC->m_pHist,pHT->m_pHist);
254 cvPow(pHT->m_pHist,pHT->m_pHist,0.5);
255 return cvSum(pHT->m_pHist).val[0] / sqrt(pHC->m_HistVolume*pHM->m_HistVolume);
257 // Do computations manually and let autovectorizer do the job
258 DefHistType *hm, *hc, *ht;
261 hm=(DefHistType *)(pHM->m_pHist->data.ptr);
262 hc=(DefHistType *)(pHC->m_pHist->data.ptr);
263 ht=(DefHistType *)(pHT->m_pHist->data.ptr);
264 size = pHM->m_pHist->width*pHM->m_pHist->height;
266 for(int i = 0; i < size; i++ )
268 sum += sqrt(hm[i]*hc[i]);
270 return sum / sqrt(pHC->m_HistVolume*pHM->m_HistVolume);
274 } /* calcBhattacharyyaCoefficient */
276 //double GetBhattacharyya(IplImage* pImg, IplImage* pImgFG, float x, float y, DefHist* pHist=NULL)
277 double GetBhattacharyya(IplImage* pImg, IplImage* pImgFG, CvBlob* pBlob, DefHist* pHist=NULL, int /*thread_number*/ = 0)
279 if(pHist==NULL)pHist = &m_HistTemp;
280 CollectHist(pImg, pImgFG, pBlob, pHist);
281 return calcBhattacharyya(&m_HistModel, pHist, pHist);
283 void UpdateModelHist(IplImage* pImg, IplImage* pImgFG, CvBlob* pBlob)
285 if(m_Alpha>0 && !m_Collision)
287 CollectHist(pImg, pImgFG, pBlob, &m_HistCandidate);
288 m_HistModel.Update(&m_HistCandidate, m_Alpha);
290 }/* UpdateModelHist*/
293 CvBlobTrackerOneMSFG()
296 /* add several parameters for external use */
298 AddParam("FGWeight", &m_FGWeight);
299 CommentParam("FGWeight","Weight of FG mask using (0 - mask will not be used for tracking)");
302 AddParam("Alpha", &m_Alpha);
303 CommentParam("Alpha","Coefficient for model histogramm updating (0 - hist is not upated)");
306 AddParam("IterNum", &m_IterNum);
307 CommentParam("IterNum","Maximal number of iteration in meanshift operation");
309 /* init internal data */
315 m_HistCandidate = NULL;
319 m_KernelMeanShift = NULL;
320 ReAllocHist(3,5); /* 3D hist, each dim has 2^5 bins*/
322 ~CvBlobTrackerOneMSFG()
325 if(m_HistModel) cvReleaseMat(&m_HistModel);
326 if(m_HistCandidate) cvReleaseMat(&m_HistCandidate);
327 if(m_HistTemp) cvReleaseMat(&m_HistTemp);
329 if(m_KernelHist) cvReleaseMat(&m_KernelHist);
330 if(m_KernelMeanShift) cvReleaseMat(&m_KernelMeanShift);
333 virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL)
335 int w = cvRound(CV_BLOB_WX(pBlobInit));
336 int h = cvRound(CV_BLOB_WY(pBlobInit));
337 if(w<CV_BLOB_MINW)w=CV_BLOB_MINW;
338 if(h<CV_BLOB_MINH)h=CV_BLOB_MINH;
341 if(w>pImg->width)w=pImg->width;
342 if(h>pImg->height)h=pImg->height;
346 CollectHist(pImg, pImgFG, pBlobInit, &m_HistModel);
347 m_Blob = pBlobInit[0];
349 virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL)
355 m_Blob = pBlobPrev[0];
358 {/* check blob size and realloc kernels if it is necessary */
359 int w = cvRound(m_Blob.w);
360 int h = cvRound(m_Blob.h);
361 if( w != m_ObjSize.width || h!=m_ObjSize.height)
364 /* after this ( w != m_ObjSize.width || h!=m_ObjSize.height) shoiuld be false */
366 }/* check blob size and realloc kernels if it is necessary */
369 for(iter=0;iter<m_IterNum;++iter)
371 float newx=0,newy=0,sum=0;
375 //CvPoint Center = cvPoint(cvRound(m_Blob.x),cvRound(m_Blob.y));
376 CollectHist(pImg, NULL, &m_Blob, &m_HistCandidate);
377 B0 = calcBhattacharyya();
379 if(m_Wnd)if(CV_BLOB_ID(pBlobPrev)==0 && iter == 0)
381 IplImage* pW = cvCloneImage(pImgFG);
382 IplImage* pWFG = cvCloneImage(pImgFG);
388 assert(m_ObjSize.width < pImg->width);
389 assert(m_ObjSize.height < pImg->height);
390 /*calc shift vector */
391 for(y=0;y<pImg->height;++y)
393 unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y,0);
394 unsigned char* pMaskData = pImgFG?(&CV_IMAGE_ELEM(pImgFG,unsigned char,y,0)):NULL;
395 for(x=0;x<pImg->width;++x,pImgData+=3)
397 int xk = cvRound(x-(m_Blob.x-m_Blob.w*0.5));
398 int yk = cvRound(y-(m_Blob.y-m_Blob.h*0.5));
402 int index = HIST_INDEX(pImgData);
403 assert(index >= 0 && index < m_BinNumTotal);
405 if(fabs(x-m_Blob.x)>m_Blob.w*0.6) continue;
406 if(fabs(y-m_Blob.y)>m_Blob.h*0.6) continue;
408 if(xk < 0 || xk >= m_KernelMeanShift->cols) continue;
409 if(yk < 0 || yk >= m_KernelMeanShift->rows) continue;
411 if(m_HistModel.m_HistVolume>0)
412 HM = ((DefHistType*)m_HistModel.m_pHist->data.ptr)[index]/m_HistModel.m_HistVolume;
413 if(m_HistCandidate.m_HistVolume>0)
414 HC = ((DefHistType*)m_HistCandidate.m_pHist->data.ptr)[index]/m_HistCandidate.m_HistVolume;
415 K = *(DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelMeanShift[0],yk,xk,sizeof(DefHistType));
419 double V = sqrt(HM / HC);
420 int Vi = cvRound(V * 64);
422 if(Vi > 255) Vi = 255;
423 CV_IMAGE_ELEM(pW,uchar,y,x) = (uchar)Vi;
425 V += m_FGWeight*(pMaskData?(pMaskData[x]/255.0f):0);
427 Vi = cvRound(V * 64);
429 if(Vi > 255) Vi = 255;
430 CV_IMAGE_ELEM(pWFG,uchar,y,x) = (uchar)Vi;
435 //cvNamedWindow("MSFG_W",0);
436 //cvShowImage("MSFG_W",pW);
437 //cvNamedWindow("MSFG_WFG",0);
438 //cvShowImage("MSFG_WFG",pWFG);
439 //cvNamedWindow("MSFG_FG",0);
440 //cvShowImage("MSFG_FG",pImgFG);
442 //cvSaveImage("MSFG_W.bmp",pW);
443 //cvSaveImage("MSFG_WFG.bmp",pWFG);
444 //cvSaveImage("MSFG_FG.bmp",pImgFG);
448 /* calc new pos by meanshift */
452 int x0 = cvRound(m_Blob.x - m_ObjSize.width*0.5);
453 int y0 = cvRound(m_Blob.y - m_ObjSize.height*0.5);
456 assert(m_ObjSize.width < pImg->width);
457 assert(m_ObjSize.height < pImg->height);
459 /* crop blob bounds */
460 if((x0+m_ObjSize.width)>=pImg->width) x0=pImg->width-m_ObjSize.width-1;
461 if((y0+m_ObjSize.height)>=pImg->height) y0=pImg->height-m_ObjSize.height-1;
464 /*calc shift vector */
465 for(y=0;y<m_ObjSize.height;++y)
467 unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3);
468 unsigned char* pMaskData = pImgFG?(&CV_IMAGE_ELEM(pImgFG,unsigned char,y+y0,x0)):NULL;
469 DefHistType* pKernelData = (DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelMeanShift[0],y,0,sizeof(DefHistType));
470 for(x=0;x<m_ObjSize.width;++x,pImgData+=3)
472 DefHistType K = pKernelData[x];
475 int index = HIST_INDEX(pImgData);
476 assert(index >= 0 && index < m_BinNumTotal);
478 if(m_HistModel.m_HistVolume>0)
479 HM = ((DefHistType*)m_HistModel.m_pHist->data.ptr)[index]/m_HistModel.m_HistVolume;
480 if(m_HistCandidate.m_HistVolume>0)
481 HC = ((DefHistType*)m_HistCandidate.m_pHist->data.ptr)[index]/m_HistCandidate.m_HistVolume;
485 double V = sqrt(HM / HC);
486 if(!m_Collision && m_FGWeight>0 && pMaskData)
488 V += m_FGWeight*(pMaskData[x]/255.0f);
490 K *= (float)MIN(V,100000.);
508 /* calc new pos be meanshift */
511 {/* iterate using bahattcharrya coefficient */
514 // CvPoint NewCenter = cvPoint(cvRound(newx),cvRound(newy));
517 CollectHist(pImg, NULL, &B, &m_HistCandidate);
518 B1 = calcBhattacharyya();
520 newx = 0.5f*(newx+m_Blob.x);
521 newy = 0.5f*(newy+m_Blob.y);
522 if(fabs(newx-m_Blob.x)<0.1 && fabs(newy-m_Blob.y)<0.1) break;
523 }/* iterate using bahattcharrya coefficient */
525 if(fabs(newx-m_Blob.x)<0.5 && fabs(newy-m_Blob.y)<0.5) break;
528 }/* next iteration */
530 while(!m_Collision && m_FGWeight>0)
531 { /* update size if no collision */
534 double M00,X,Y,XX,YY;
539 r.width = cvRound(m_Blob.w*1.5+0.5);
540 r.height = cvRound(m_Blob.h*1.5+0.5);
541 r.x = cvRound(m_Blob.x - 0.5*r.width);
542 r.y = cvRound(m_Blob.y - 0.5*r.height);
545 if(r.x+r.width >= pImgFG->width) break;
546 if(r.y+r.height >= pImgFG->height) break;
547 if(r.height < 5 || r.width < 5) break;
549 cvMoments( cvGetSubRect(pImgFG,&mat,r), &m, 0 );
550 M00 = cvGetSpatialMoment( &m, 0, 0 );
552 X = cvGetSpatialMoment( &m, 1, 0 )/M00;
553 Y = cvGetSpatialMoment( &m, 0, 1 )/M00;
554 XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X;
555 YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y;
556 NewBlob = cvBlob(r.x+(float)X,r.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY)));
558 NewBlob.w = Alpha*NewBlob.w+m_Blob.w*(1-Alpha);
559 NewBlob.h = Alpha*NewBlob.h+m_Blob.h*(1-Alpha);
561 m_Blob.w = MAX(NewBlob.w,5);
562 m_Blob.h = MAX(NewBlob.h,5);
564 }/* update size if no collision */
567 }; /* CvBlobTrackerOneMSFG::Process */
568 virtual double GetConfidence(CvBlob* pBlob, IplImage* pImg, IplImage* /*pImgFG*/ = NULL, IplImage* pImgUnusedReg = NULL)
571 double B = GetBhattacharyya(pImg, pImgUnusedReg, pBlob, &m_HistTemp);
572 return exp((B-1)/(2*S));
573 };/*CvBlobTrackerOneMSFG::*/
575 virtual void Update(CvBlob* pBlob, IplImage* pImg, IplImage* pImgFG = NULL)
577 UpdateModelHist(pImg, pImgFG, pBlob?pBlob:&m_Blob);
578 }/*CvBlobTrackerOneMSFG::*/
580 virtual void Release(){delete this;};
581 virtual void SetCollision(int CollisionFlag)
583 m_Collision = CollisionFlag;
585 virtual void SaveState(CvFileStorage* fs)
587 cvWriteStruct(fs, "Blob", &m_Blob, "ffffi");
588 cvWriteInt(fs,"Collision", m_Collision);
589 cvWriteInt(fs,"HistVolume", cvRound(m_HistModel.m_HistVolume));
590 cvWrite(fs,"Hist", m_HistModel.m_pHist);
592 virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
595 cvReadStructByName(fs, node, "Blob",&m_Blob, "ffffi");
596 m_Collision = cvReadIntByName(fs,node,"Collision",m_Collision);
597 pM = (CvMat*)cvRead(fs,cvGetFileNodeByName(fs,node,"Hist"));
600 m_HistModel.m_pHist = pM;
601 m_HistModel.m_HistVolume = (float)cvSum(pM).val[0];
605 }; /*CvBlobTrackerOneMSFG*/
608 void CvBlobTrackerOneMSFG::CollectHist(IplImage* pImg, IplImage* pMask, CvBlob* pBlob, DefHist* pHist)
610 int UsePrecalculatedKernel = 0;
611 int BW = cvRound(pBlob->w);
612 int BH = cvRound(pBlob->h);
613 DefHistType Volume = 0;
614 int x0 = cvRound(pBlob->x - BW*0.5);
615 int y0 = cvRound(pBlob->y - BH*0.5);
618 UsePrecalculatedKernel = (BW == m_ObjSize.width && BH == m_ObjSize.height ) ;
621 cvSet(pHist->m_pHist,cvScalar(1.0/m_BinNumTotal)); /* no zero bins, all bins have very small value*/
624 assert(BW < pImg->width);
625 assert(BH < pImg->height);
626 if((x0+BW)>=pImg->width) BW=pImg->width-x0-1;
627 if((y0+BH)>=pImg->height) BH=pImg->height-y0-1;
635 unsigned char* pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3);
636 unsigned char* pMaskData = pMask?(&CV_IMAGE_ELEM(pMask,unsigned char,y+y0,x0)):NULL;
637 DefHistType* pKernelData = NULL;
638 if(UsePrecalculatedKernel)
640 pKernelData = ((DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelHist[0],y,0,sizeof(DefHistType)));
642 for(x=0;x<BW;++x,pImgData+=3)
645 int index = HIST_INDEX(pImgData);
646 assert(index >= 0 && index < pHist->m_pHist->cols);
647 if(UsePrecalculatedKernel)
653 float dx = (x+x0-pBlob->x)/(pBlob->w*0.5);
654 float dy = (y+y0-pBlob->y)/(pBlob->h*0.5);
655 double r2 = dx*dx+dy*dy;
656 K = GetKernelHist(r2);
661 K *= pMaskData[x]*0.003921568627450980392156862745098;
664 ((DefHistType*)(pHist->m_pHist->data.ptr))[index] += K;
668 pHist->m_HistVolume = Volume;
672 CvBlobTrackerOne* cvCreateBlobTrackerOneMSFG()
674 return (CvBlobTrackerOne*) new CvBlobTrackerOneMSFG;
676 CvBlobTracker* cvCreateBlobTrackerMSFG()
678 return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMSFG);
681 /* Create specific tracker without FG usin - just simple mean-shift tracker*/
682 class CvBlobTrackerOneMS:public CvBlobTrackerOneMSFG
687 SetParam("FGWeight",0);
688 DelParam("FGWeight");
692 CvBlobTrackerOne* cvCreateBlobTrackerOneMS()
694 return (CvBlobTrackerOne*) new CvBlobTrackerOneMS;
696 CvBlobTracker* cvCreateBlobTrackerMS()
698 return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMS);
701 typedef struct DefParticle
708 class CvBlobTrackerOneMSPF:public CvBlobTrackerOneMS
719 DefParticle* m_pParticlesPredicted;
720 DefParticle* m_pParticlesResampled;
724 DefHist* m_HistForParalel;
728 virtual void SaveState(CvFileStorage* fs)
730 CvBlobTrackerOneMS::SaveState(fs);
731 cvWriteInt(fs,"ParticleNum",m_ParticleNum);
732 cvWriteStruct(fs,"ParticlesPredicted",m_pParticlesPredicted,"ffffiffd",m_ParticleNum);
733 cvWriteStruct(fs,"ParticlesResampled",m_pParticlesResampled,"ffffiffd",m_ParticleNum);
735 virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
738 CvBlobTrackerOneMS::LoadState(fs,node);
739 m_ParticleNum = cvReadIntByName(fs,node,"ParticleNum",m_ParticleNum);
743 printf("sizeof(DefParticle) is %d\n", sizeof(DefParticle));
744 cvReadStructByName(fs,node,"ParticlesPredicted",m_pParticlesPredicted,"ffffiffd");
745 cvReadStructByName(fs,node,"ParticlesResampled",m_pParticlesResampled,"ffffiffd");
748 CvBlobTrackerOneMSPF()
750 m_pParticlesPredicted = NULL;
751 m_pParticlesResampled = NULL;
754 AddParam("ParticleNum",&m_ParticleNum);
755 CommentParam("ParticleNum","Number of particles");
759 AddParam("UseVel",&m_UseVel);
760 CommentParam("UseVel","Percent of particles which use velocity feature");
763 AddParam("SizeVar",&m_SizeVar);
764 CommentParam("SizeVar","Size variation (in object size)");
767 AddParam("PosVar",&m_PosVar);
768 CommentParam("PosVar","Position variation (in object size)");
773 m_ThreadNum = omp_get_num_procs();
774 m_HistForParalel = new DefHist[m_ThreadNum];
778 ~CvBlobTrackerOneMSPF()
780 if(m_pParticlesResampled)cvFree(&m_pParticlesResampled);
781 if(m_pParticlesPredicted)cvFree(&m_pParticlesPredicted);
783 if(m_HistForParalel) delete[] m_HistForParalel;
789 if(m_pParticlesResampled)cvFree(&m_pParticlesResampled);
790 if(m_pParticlesPredicted)cvFree(&m_pParticlesPredicted);
791 m_pParticlesPredicted = (DefParticle*)cvAlloc(sizeof(DefParticle)*m_ParticleNum);
792 m_pParticlesResampled = (DefParticle*)cvAlloc(sizeof(DefParticle)*m_ParticleNum);
794 void DrawDebug(IplImage* pImg, IplImage* /*pImgFG*/)
799 DefParticle* pBP = k?m_pParticlesResampled:m_pParticlesPredicted;
800 //const char* name = k?"MSPF resampled particle":"MSPF Predicted particle";
801 IplImage* pI = cvCloneImage(pImg);
802 int h,hN = m_ParticleNum;
803 CvBlob C = cvBlob(0,0,0,0);
807 CvBlob B = pBP[h].blob;
808 int CW = cvRound(255*pBP[h].W);
810 int x = cvRound(CV_BLOB_RX(pB)), y = cvRound(CV_BLOB_RY(pB));
811 CvSize s = cvSize(MAX(1,x), MAX(1,y));
821 cvPointFrom32f(CV_BLOB_CENTER(pB)),
825 }/* next hypothetis */
831 cvPointFrom32f(CV_BLOB_CENTER(&C)),
832 cvSize(cvRound(C.w*0.5),cvRound(C.h*0.5)),
834 CV_RGB(0,0,255), 1 );
836 cvPointFrom32f(CV_BLOB_CENTER(&m_Blob)),
837 cvSize(cvRound(m_Blob.w*0.5),cvRound(m_Blob.h*0.5)),
839 CV_RGB(0,255,0), 1 );
840 //cvNamedWindow(name,0);
841 //cvShowImage(name,pI);
845 //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);
851 for(p=0;p<m_ParticleNum;++p)
852 {/* "prediction" of particle */
855 CvMat rm = cvMat(1,5,CV_32F,r);
856 cvRandArr(&m_RNG,&rm,CV_RAND_NORMAL,cvScalar(0),cvScalar(1));
858 m_pParticlesPredicted[p] = m_pParticlesResampled[p];
860 if(cvRandReal(&m_RNG)<0.5)
861 {/* half of particles will predict based on external blob */
862 m_pParticlesPredicted[p].blob = m_Blob;
865 if(cvRandReal(&m_RNG)<m_UseVel)
866 {/* predict moving particle by usual way by using speed */
867 m_pParticlesPredicted[p].blob.x += m_pParticlesPredicted[p].Vx;
868 m_pParticlesPredicted[p].blob.y += m_pParticlesPredicted[p].Vy;
871 {/* stop several particles */
872 m_pParticlesPredicted[p].Vx = 0;
873 m_pParticlesPredicted[p].Vy = 0;
876 {/* update position */
877 float S = (m_Blob.w + m_Blob.h)*0.5f;
878 m_pParticlesPredicted[p].blob.x += m_PosVar*S*r[0];
879 m_pParticlesPredicted[p].blob.y += m_PosVar*S*r[1];
880 /* update velocity */
881 m_pParticlesPredicted[p].Vx += (float)(m_PosVar*S*0.1*r[3]);
882 m_pParticlesPredicted[p].Vy += (float)(m_PosVar*S*0.1*r[4]);
886 m_pParticlesPredicted[p].blob.w *= (1+m_SizeVar*r[2]);
887 m_pParticlesPredicted[p].blob.h *= (1+m_SizeVar*r[2]);
889 /* truncate size of particle */
890 if(m_pParticlesPredicted[p].blob.w > m_ImgSize.width*0.5f)
892 m_pParticlesPredicted[p].blob.w = m_ImgSize.width*0.5f;
894 if(m_pParticlesPredicted[p].blob.h > m_ImgSize.height*0.5f)
896 m_pParticlesPredicted[p].blob.h = m_ImgSize.height*0.5f;
898 if(m_pParticlesPredicted[p].blob.w < 1 )
900 m_pParticlesPredicted[p].blob.w = 1;
902 if(m_pParticlesPredicted[p].blob.h < 1)
904 m_pParticlesPredicted[p].blob.h = 1;
906 }/* "prediction" of particle */
909 void UpdateWeightsMS(IplImage* pImg, IplImage* /*pImgFG*/)
913 if( m_HistForParalel[0].m_pHist==NULL || m_HistForParalel[0].m_pHist->cols != m_BinNumTotal)
916 for(t=0;t<m_ThreadNum;++t)
917 m_HistForParalel[t].Resize(m_BinNumTotal);
922 #pragma omp parallel for num_threads(m_ThreadNum),schedule(runtime)
924 for(p=0;p<m_ParticleNum;++p)
925 {/* calc weights for particles */
929 assert(omp_get_thread_num()<m_ThreadNum);
932 B = GetBhattacharyya(
934 &(m_pParticlesPredicted[p].blob)
936 ,&(m_HistForParalel[omp_get_thread_num()])
939 m_pParticlesPredicted[p].W *= exp((B-1)/(2*S));
940 }/* calc weights for particles */
942 void UpdateWeightsCC(IplImage* /*pImg*/, IplImage* /*pImgFG*/)
946 #pragma omp parallel for
948 for(p=0;p<m_ParticleNum;++p)
949 {/* calc weights for particles */
951 m_pParticlesPredicted[p].W *= W;
952 }/* calc weights for particles */
955 {/* resample particle */
958 for(p=0;p<m_ParticleNum;++p)
960 Sum += m_pParticlesPredicted[p].W;
962 for(p=0;p<m_ParticleNum;++p)
964 double T = Sum * cvRandReal(&m_RNG); /* set current random threshold for cululative weight */
967 for(p2=0;p2<m_ParticleNum;++p2)
969 Sum2 += m_pParticlesPredicted[p2].W;
972 if(p2>=m_ParticleNum)p2=m_ParticleNum-1;
973 m_pParticlesResampled[p] = m_pParticlesPredicted[p2];
974 m_pParticlesResampled[p].W = 1;
975 }/* find next particle */
976 } /* resample particle */
980 virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL)
983 CvBlobTrackerOneMSFG::Init(pBlobInit, pImg, pImgFG);
988 PP.blob = pBlobInit[0];
989 for(i=0;i<m_ParticleNum;++i)
991 m_pParticlesPredicted[i] = PP;
992 m_pParticlesResampled[i] = PP;
994 m_Blob = pBlobInit[0];
995 } /* CvBlobTrackerOneMSPF::Init*/
996 virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL)
1000 m_ImgSize.width = pImg->width;
1001 m_ImgSize.height = pImg->height;
1004 m_Blob = pBlobPrev[0];
1006 {/* check blob size and realloc kernels if it is necessary */
1007 int w = cvRound(m_Blob.w);
1008 int h = cvRound(m_Blob.h);
1009 if( w != m_ObjSize.width || h!=m_ObjSize.height)
1012 /* after this ( w != m_ObjSize.width || h!=m_ObjSize.height) shoiuld be false */
1014 }/* check blob size and realloc kernels if it is necessary */
1019 int64 ticks = cvGetTickCount();
1022 UpdateWeightsMS(pImg, pImgFG);
1025 ticks = cvGetTickCount() - ticks;
1026 fprintf(stderr, "PF UpdateWeights, %d ticks\n", (int)ticks);
1027 ticks = cvGetTickCount();
1033 ticks = cvGetTickCount() - ticks;
1034 fprintf(stderr, "PF Resampling, %d ticks\n", (int)ticks);
1037 {/* find average result */
1043 DefParticle* pP = m_pParticlesResampled;
1044 for(p=0;p<m_ParticleNum;++p)
1046 float W = (float)pP[p].W;
1047 x += W*pP[p].blob.x;
1048 y += W*pP[p].blob.y;
1049 w += W*pP[p].blob.w;
1050 h += W*pP[p].blob.h;
1060 }/* find average result */
1064 DrawDebug(pImg, pImgFG);
1068 }/* CvBlobTrackerOneMSPF::Process */
1069 virtual void SkipProcess(CvBlob* pBlob, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL)
1072 for(p=0;p<m_ParticleNum;++p)
1074 m_pParticlesResampled[p].blob = pBlob[0];
1075 m_pParticlesResampled[p].Vx = 0;
1076 m_pParticlesResampled[p].Vy = 0;
1077 m_pParticlesResampled[p].W = 1;
1081 virtual void Release(){delete this;};
1082 virtual void ParamUpdate()
1086 }; /* CvBlobTrackerOneMSPF */
1088 CvBlobTrackerOne* cvCreateBlobTrackerOneMSPF()
1090 return (CvBlobTrackerOne*) new CvBlobTrackerOneMSPF;
1092 CvBlobTracker* cvCreateBlobTrackerMSPF()
1094 return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMSPF);