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.
41 #include "precomp.hpp"
47 // Uncomment to trade flexibility for speed
48 //#define CONST_HIST_SIZE
50 // Uncomment to get some performance stats in stderr
51 //#define REPORT_TICKS
53 #ifdef CONST_HIST_SIZE
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)))
66 DefHistType m_HistVolume;
76 if(m_pHist)cvReleaseMat(&m_pHist);
79 void Resize(int BinNum)
81 if(m_pHist)cvReleaseMat(&m_pHist);
84 m_pHist = cvCreateMat(1, BinNum, DefHistTypeMat);
90 void Update(DefHist* pH, float W)
91 { /* Update histogram: */
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: */
101 class CvBlobTrackerOneMSFG:public CvBlobTrackerOne
104 int m_BinNumTotal; /* protected only for parralel MSPF */
107 void ReAllocKernel(int w, int h)
110 float x0 = 0.5f*(w-1);
111 float y0 = 0.5f*(h-1);
114 m_ObjSize = cvSize(w,h);
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);
121 for(y=0; y<h; ++y) for(x=0; x<w; ++x)
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);
136 CvMat* m_KernelMeanShift;
137 #ifndef CONST_HIST_SIZE
145 float m_HistModelVolume;
146 CvMat* m_HistCandidate;
147 float m_HistCandidateVolume;
151 DefHist m_HistCandidate;
157 void ReAllocHist(int Dim, int BinBit)
159 #ifndef CONST_HIST_SIZE
161 m_ByteShift = 8-BinBit;
164 m_BinNum = (1<<BinBit);
165 m_BinNumTotal = cvRound(pow((double)m_BinNum,(double)m_Dim));
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);
175 m_HistModelVolume = 0.0f;
176 m_HistCandidateVolume = 0.0f;
178 m_HistCandidate.Resize(m_BinNumTotal);
179 m_HistModel.Resize(m_BinNumTotal);
180 m_HistTemp.Resize(m_BinNumTotal);
183 double GetKernelHist(double r2)
185 return (r2 < 1) ? 1 - r2 : 0;
188 double GetKernelMeanShift(double r2)
190 return (r2<1) ? 1 : 0;
193 // void CollectHist(IplImage* pImg, IplImage* pMask, CvPoint Center, CvMat* pHist, DefHistType* pHistVolume)
194 // void CollectHist(IplImage* pImg, IplImage* pMask, CvPoint Center, DefHist* pHist)
196 void CollectHist(IplImage* pImg, IplImage* pMask, CvBlob* pBlob, DefHist* pHist)
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);
206 UsePrecalculatedKernel = (BW == m_ObjSize.width && BH == m_ObjSize.height ) ;
209 cvSet(pHist->m_pHist,cvScalar(1.0/m_BinNumTotal)); /* no zero bins, all bins have very small value*/
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;
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;
227 if(UsePrecalculatedKernel)
229 pKernelData = ((DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelHist[0],y,0,sizeof(DefHistType)));
232 for(x=0; x<BW; ++x, pImgData+=3)
235 int index = HIST_INDEX(pImgData);
236 assert(index >= 0 && index < pHist->m_pHist->cols);
238 if(UsePrecalculatedKernel)
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);
252 K *= pMaskData[x]*0.003921568627450980392156862745098f;
255 ((DefHistType*)(pHist->m_pHist->data.ptr))[index] += K;
259 } /* if m_Dim == 3. */
261 pHist->m_HistVolume = Volume;
265 double calcBhattacharyya(DefHist* pHM = NULL, DefHist* pHC = NULL, DefHist* pHT = NULL)
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)
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);
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;
284 for(int i = 0; i < size; i++ )
286 sum += sqrt(hm[i]*hc[i]);
288 return sum / sqrt(pHC->m_HistVolume*pHM->m_HistVolume);
292 } /* calcBhattacharyyaCoefficient. */
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)
298 if(pHist==NULL)pHist = &m_HistTemp;
299 CollectHist(pImg, pImgFG, pBlob, pHist);
300 return calcBhattacharyya(&m_HistModel, pHist, pHist);
303 void UpdateModelHist(IplImage* pImg, IplImage* pImgFG, CvBlob* pBlob)
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. */
311 } /* UpdateModelHist */
314 CvBlobTrackerOneMSFG()
317 /* Add several parameters for external use: */
319 AddParam("FGWeight", &m_FGWeight);
320 CommentParam("FGWeight","Weight of FG mask using (0 - mask will not be used for tracking)");
323 AddParam("Alpha", &m_Alpha);
324 CommentParam("Alpha","Coefficient for model histogram updating (0 - hist is not upated)");
327 AddParam("IterNum", &m_IterNum);
328 CommentParam("IterNum","Maximal number of iteration in meanshift operation");
330 /* Initialize internal data: */
336 m_HistCandidate = NULL;
340 m_KernelMeanShift = NULL;
341 ReAllocHist(3,5); /* 3D hist, each dim has 2^5 bins*/
343 SetModuleName("MSFG");
346 ~CvBlobTrackerOneMSFG()
349 if(m_HistModel) cvReleaseMat(&m_HistModel);
350 if(m_HistCandidate) cvReleaseMat(&m_HistCandidate);
351 if(m_HistTemp) cvReleaseMat(&m_HistTemp);
353 if(m_KernelHist) cvReleaseMat(&m_KernelHist);
354 if(m_KernelMeanShift) cvReleaseMat(&m_KernelMeanShift);
358 virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL)
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;
366 if(w>pImg->width)w=pImg->width;
367 if(h>pImg->height)h=pImg->height;
371 CollectHist(pImg, pImgFG, pBlobInit, &m_HistModel);
372 m_Blob = pBlobInit[0];
375 virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL)
381 m_Blob = pBlobPrev[0];
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)
390 /* after this ( w != m_ObjSize.width || h!=m_ObjSize.height) shoiuld be false */
392 } /* Check blob size and realloc kernels if it is necessary: */
395 for(iter=0; iter<m_IterNum; ++iter)
397 float newx=0,newy=0,sum=0;
401 //CvPoint Center = cvPoint(cvRound(m_Blob.x),cvRound(m_Blob.y));
402 CollectHist(pImg, NULL, &m_Blob, &m_HistCandidate);
403 B0 = calcBhattacharyya();
405 if(m_Wnd)if(CV_BLOB_ID(pBlobPrev)==0 && iter == 0)
407 IplImage* pW = cvCloneImage(pImgFG);
408 IplImage* pWFG = cvCloneImage(pImgFG);
414 assert(m_ObjSize.width < pImg->width);
415 assert(m_ObjSize.height < pImg->height);
417 /* Calculate shift vector: */
418 for(y=0; y<pImg->height; ++y)
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;
423 for(x=0; x<pImg->width; ++x, pImgData+=3)
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));
430 int index = HIST_INDEX(pImgData);
431 assert(index >= 0 && index < m_BinNumTotal);
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;
436 if(xk < 0 || xk >= m_KernelMeanShift->cols) continue;
437 if(yk < 0 || yk >= m_KernelMeanShift->rows) continue;
439 if(m_HistModel.m_HistVolume>0)
440 HM = ((DefHistType*)m_HistModel.m_pHist->data.ptr)[index]/m_HistModel.m_HistVolume;
442 if(m_HistCandidate.m_HistVolume>0)
443 HC = ((DefHistType*)m_HistCandidate.m_pHist->data.ptr)[index]/m_HistCandidate.m_HistVolume;
445 K = *(DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelMeanShift[0],yk,xk,sizeof(DefHistType));
449 double V = sqrt(HM / HC);
450 int Vi = cvRound(V * 64);
452 if(Vi > 255) Vi = 255;
453 CV_IMAGE_ELEM(pW,uchar,y,x) = (uchar)Vi;
455 V += m_FGWeight*(pMaskData?(pMaskData[x]/255.0f):0);
457 Vi = cvRound(V * 64);
459 if(Vi > 255) Vi = 255;
460 CV_IMAGE_ELEM(pWFG,uchar,y,x) = (uchar)Vi;
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);
473 //cvSaveImage("MSFG_W.bmp",pW);
474 //cvSaveImage("MSFG_WFG.bmp",pWFG);
475 //cvSaveImage("MSFG_FG.bmp",pImgFG);
480 /* Calculate new position by meanshift: */
482 /* Calculate new position: */
485 int x0 = cvRound(m_Blob.x - m_ObjSize.width*0.5);
486 int y0 = cvRound(m_Blob.y - m_ObjSize.height*0.5);
489 assert(m_ObjSize.width < pImg->width);
490 assert(m_ObjSize.height < pImg->height);
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;
498 /* Calculate shift vector: */
499 for(y=0; y<m_ObjSize.height; ++y)
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));
505 for(x=0; x<m_ObjSize.width; ++x, pImgData+=3)
507 DefHistType K = pKernelData[x];
510 int index = HIST_INDEX(pImgData);
511 assert(index >= 0 && index < m_BinNumTotal);
513 if(m_HistModel.m_HistVolume>0)
514 HM = ((DefHistType*)m_HistModel.m_pHist->data.ptr)[index]/m_HistModel.m_HistVolume;
516 if(m_HistCandidate.m_HistVolume>0)
517 HC = ((DefHistType*)m_HistCandidate.m_pHist->data.ptr)[index]/m_HistCandidate.m_HistVolume;
521 double V = sqrt(HM / HC);
522 if(!m_Collision && m_FGWeight>0 && pMaskData)
524 V += m_FGWeight*(pMaskData[x]/255.0f);
526 K *= (float)MIN(V,100000.);
543 } /* if m_Dim == 3. */
545 /* Calculate new position by meanshift: */
548 { /* Iterate using bahattcharrya coefficient: */
551 // CvPoint NewCenter = cvPoint(cvRound(newx),cvRound(newy));
554 CollectHist(pImg, NULL, &B, &m_HistCandidate);
555 B1 = calcBhattacharyya();
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. */
562 if(fabs(newx-m_Blob.x)<0.5 && fabs(newy-m_Blob.y)<0.5) break;
565 } /* Next iteration. */
567 while(!m_Collision && m_FGWeight>0)
568 { /* Update size if no collision. */
571 double M00,X,Y,XX,YY;
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);
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;
586 cvMoments( cvGetSubRect(pImgFG,&mat,r), &m, 0 );
587 M00 = cvGetSpatialMoment( &m, 0, 0 );
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)));
595 NewBlob.w = Alpha*NewBlob.w+m_Blob.w*(1-Alpha);
596 NewBlob.h = Alpha*NewBlob.h+m_Blob.h*(1-Alpha);
598 m_Blob.w = MAX(NewBlob.w,5);
599 m_Blob.h = MAX(NewBlob.h,5);
602 } /* Update size if no collision. */
606 }; /* CvBlobTrackerOneMSFG::Process */
608 virtual double GetConfidence(CvBlob* pBlob, IplImage* pImg, IplImage* /*pImgFG*/ = NULL, IplImage* pImgUnusedReg = NULL)
611 double B = GetBhattacharyya(pImg, pImgUnusedReg, pBlob, &m_HistTemp);
612 return exp((B-1)/(2*S));
614 }; /*CvBlobTrackerOneMSFG::*/
616 virtual void Update(CvBlob* pBlob, IplImage* pImg, IplImage* pImgFG = NULL)
617 { /* Update histogram: */
618 UpdateModelHist(pImg, pImgFG, pBlob?pBlob:&m_Blob);
619 } /*CvBlobTrackerOneMSFG::*/
621 virtual void Release(){delete this;};
622 virtual void SetCollision(int CollisionFlag)
624 m_Collision = CollisionFlag;
626 virtual void SaveState(CvFileStorage* fs)
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);
633 virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
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"));
641 m_HistModel.m_pHist = pM;
642 m_HistModel.m_HistVolume = (float)cvSum(pM).val[0];
646 }; /*CvBlobTrackerOneMSFG*/
649 void CvBlobTrackerOneMSFG::CollectHist(IplImage* pImg, IplImage* pMask, CvBlob* pBlob, DefHist* pHist)
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);
659 UsePrecalculatedKernel = (BW == m_ObjSize.width && BH == m_ObjSize.height ) ;
662 cvSet(pHist->m_pHist,cvScalar(1.0/m_BinNumTotal)); /* no zero bins, all bins have very small value*/
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;
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;
680 if(UsePrecalculatedKernel)
682 pKernelData = ((DefHistType*)CV_MAT_ELEM_PTR_FAST(m_KernelHist[0],y,0,sizeof(DefHistType)));
685 for(x=0; x<BW; ++x, pImgData+=3)
688 int index = HIST_INDEX(pImgData);
689 assert(index >= 0 && index < pHist->m_pHist->cols);
691 if(UsePrecalculatedKernel)
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);
705 K *= pMaskData[x]*0.003921568627450980392156862745098;
708 ((DefHistType*)(pHist->m_pHist->data.ptr))[index] += K;
712 } /* if m_Dim == 3. */
714 pHist->m_HistVolume = Volume;
719 CvBlobTrackerOne* cvCreateBlobTrackerOneMSFG()
721 return (CvBlobTrackerOne*) new CvBlobTrackerOneMSFG;
724 CvBlobTracker* cvCreateBlobTrackerMSFG()
726 return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMSFG);
729 /* Create specific tracker without FG
730 * usin - just simple mean-shift tracker: */
731 class CvBlobTrackerOneMS:public CvBlobTrackerOneMSFG
736 SetParam("FGWeight",0);
737 DelParam("FGWeight");
742 CvBlobTrackerOne* cvCreateBlobTrackerOneMS()
744 return (CvBlobTrackerOne*) new CvBlobTrackerOneMS;
747 CvBlobTracker* cvCreateBlobTrackerMS()
749 return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMS);
752 typedef struct DefParticle
759 class CvBlobTrackerOneMSPF:public CvBlobTrackerOneMS
770 DefParticle* m_pParticlesPredicted;
771 DefParticle* m_pParticlesResampled;
775 DefHist* m_HistForParalel;
779 virtual void SaveState(CvFileStorage* fs)
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);
787 virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
790 CvBlobTrackerOneMS::LoadState(fs,node);
791 m_ParticleNum = cvReadIntByName(fs,node,"ParticleNum",m_ParticleNum);
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");
800 CvBlobTrackerOneMSPF()
802 m_pParticlesPredicted = NULL;
803 m_pParticlesResampled = NULL;
806 AddParam("ParticleNum",&m_ParticleNum);
807 CommentParam("ParticleNum","Number of particles");
811 AddParam("UseVel",&m_UseVel);
812 CommentParam("UseVel","Percent of particles which use velocity feature");
815 AddParam("SizeVar",&m_SizeVar);
816 CommentParam("SizeVar","Size variation (in object size)");
819 AddParam("PosVar",&m_PosVar);
820 CommentParam("PosVar","Position variation (in object size)");
824 SetModuleName("MSPF");
828 m_ThreadNum = omp_get_num_procs();
829 m_HistForParalel = new DefHist[m_ThreadNum];
834 ~CvBlobTrackerOneMSPF()
836 if(m_pParticlesResampled)cvFree(&m_pParticlesResampled);
837 if(m_pParticlesPredicted)cvFree(&m_pParticlesPredicted);
839 if(m_HistForParalel) delete[] m_HistForParalel;
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);
852 void DrawDebug(IplImage* pImg, IplImage* /*pImgFG*/)
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);
865 CvBlob B = pBP[h].blob;
866 int CW = cvRound(255*pBP[h].W);
868 int x = cvRound(CV_BLOB_RX(pB)), y = cvRound(CV_BLOB_RY(pB));
869 CvSize s = cvSize(MAX(1,x), MAX(1,y));
879 cvPointFrom32f(CV_BLOB_CENTER(pB)),
884 } /* Next hypothesis. */
892 cvPointFrom32f(CV_BLOB_CENTER(&C)),
893 cvSize(cvRound(C.w*0.5),cvRound(C.h*0.5)),
895 CV_RGB(0,0,255), 1 );
898 cvPointFrom32f(CV_BLOB_CENTER(&m_Blob)),
899 cvSize(cvRound(m_Blob.w*0.5),cvRound(m_Blob.h*0.5)),
901 CV_RGB(0,255,0), 1 );
903 //cvNamedWindow(name,0);
904 //cvShowImage(name,pI);
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);
915 for(p=0; p<m_ParticleNum; ++p)
916 { /* "Prediction" of particle: */
919 CvMat rm = cvMat(1,5,CV_32F,r);
920 cvRandArr(&m_RNG,&rm,CV_RAND_NORMAL,cvScalar(0),cvScalar(1));
922 m_pParticlesPredicted[p] = m_pParticlesResampled[p];
924 if(cvRandReal(&m_RNG)<0.5)
925 { /* Half of particles will predict based on external blob: */
926 m_pParticlesPredicted[p].blob = m_Blob;
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;
935 { /* Stop several particles: */
936 m_pParticlesPredicted[p].Vx = 0;
937 m_pParticlesPredicted[p].Vy = 0;
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];
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]);
951 m_pParticlesPredicted[p].blob.w *= (1+m_SizeVar*r[2]);
952 m_pParticlesPredicted[p].blob.h *= (1+m_SizeVar*r[2]);
954 /* Truncate size of particle: */
955 if(m_pParticlesPredicted[p].blob.w > m_ImgSize.width*0.5f)
957 m_pParticlesPredicted[p].blob.w = m_ImgSize.width*0.5f;
960 if(m_pParticlesPredicted[p].blob.h > m_ImgSize.height*0.5f)
962 m_pParticlesPredicted[p].blob.h = m_ImgSize.height*0.5f;
965 if(m_pParticlesPredicted[p].blob.w < 1 )
967 m_pParticlesPredicted[p].blob.w = 1;
970 if(m_pParticlesPredicted[p].blob.h < 1)
972 m_pParticlesPredicted[p].blob.h = 1;
974 } /* "Prediction" of particle. */
977 void UpdateWeightsMS(IplImage* pImg, IplImage* /*pImgFG*/)
981 if( m_HistForParalel[0].m_pHist==NULL || m_HistForParalel[0].m_pHist->cols != m_BinNumTotal)
984 for(t=0; t<m_ThreadNum; ++t)
985 m_HistForParalel[t].Resize(m_BinNumTotal);
990 #pragma omp parallel for num_threads(m_ThreadNum) schedule(runtime)
992 for(p=0;p<m_ParticleNum;++p)
993 { /* Calculate weights for particles: */
997 assert(omp_get_thread_num()<m_ThreadNum);
1000 B = GetBhattacharyya(
1002 &(m_pParticlesPredicted[p].blob)
1004 ,&(m_HistForParalel[omp_get_thread_num()])
1007 m_pParticlesPredicted[p].W *= exp((B-1)/(2*S));
1009 } /* Calculate weights for particles. */
1012 void UpdateWeightsCC(IplImage* /*pImg*/, IplImage* /*pImgFG*/)
1016 #pragma omp parallel for
1018 for(p=0; p<m_ParticleNum; ++p)
1019 { /* Calculate weights for particles: */
1021 m_pParticlesPredicted[p].W *= W;
1022 } /* Calculate weights for particles. */
1026 { /* Resample particle: */
1030 for(p=0; p<m_ParticleNum; ++p)
1032 Sum += m_pParticlesPredicted[p].W;
1035 for(p=0; p<m_ParticleNum; ++p)
1037 double T = Sum * cvRandReal(&m_RNG); /* Set current random threshold for cululative weight. */
1041 for(p2=0; p2<m_ParticleNum; ++p2)
1043 Sum2 += m_pParticlesPredicted[p2].W;
1047 if(p2>=m_ParticleNum)p2=m_ParticleNum-1;
1048 m_pParticlesResampled[p] = m_pParticlesPredicted[p2];
1049 m_pParticlesResampled[p].W = 1;
1051 } /* Find next particle. */
1052 } /* Resample particle. */
1056 virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL)
1059 CvBlobTrackerOneMSFG::Init(pBlobInit, pImg, pImgFG);
1064 PP.blob = pBlobInit[0];
1065 for(i=0;i<m_ParticleNum;++i)
1067 m_pParticlesPredicted[i] = PP;
1068 m_pParticlesResampled[i] = PP;
1070 m_Blob = pBlobInit[0];
1072 } /* CvBlobTrackerOneMSPF::Init*/
1074 virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL)
1078 m_ImgSize.width = pImg->width;
1079 m_ImgSize.height = pImg->height;
1082 m_Blob = pBlobPrev[0];
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)
1090 /* After this ( w != m_ObjSize.width || h!=m_ObjSize.height) should be false. */
1092 } /* Check blob size and realloc kernels if it is necessary. */
1097 int64 ticks = cvGetTickCount();
1100 UpdateWeightsMS(pImg, pImgFG);
1103 ticks = cvGetTickCount() - ticks;
1104 fprintf(stderr, "PF UpdateWeights, %d ticks\n", (int)ticks);
1105 ticks = cvGetTickCount();
1111 ticks = cvGetTickCount() - ticks;
1112 fprintf(stderr, "PF Resampling, %d ticks\n", (int)ticks);
1115 { /* Find average result: */
1122 DefParticle* pP = m_pParticlesResampled;
1124 for(p=0; p<m_ParticleNum; ++p)
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;
1141 } /* Find average result. */
1145 DrawDebug(pImg, pImgFG);
1150 } /* CvBlobTrackerOneMSPF::Process */
1152 virtual void SkipProcess(CvBlob* pBlob, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL)
1155 for(p=0; p<m_ParticleNum; ++p)
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;
1164 virtual void Release(){delete this;};
1165 virtual void ParamUpdate()
1170 }; /* CvBlobTrackerOneMSPF */
1172 CvBlobTrackerOne* cvCreateBlobTrackerOneMSPF()
1174 return (CvBlobTrackerOne*) new CvBlobTrackerOneMSPF;
1177 CvBlobTracker* cvCreateBlobTrackerMSPF()
1179 return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMSPF);