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"
43 static float CalcAverageMask(CvBlob* pBlob, IplImage* pImgFG )
44 { /* Calculate sum of mask: */
45 double Area, Aver = 0;
49 if(pImgFG==NULL) return 0;
51 r.x = cvRound(pBlob->x - pBlob->w*0.5);
52 r.y = cvRound(pBlob->y - pBlob->h*0.5);
53 r.width = cvRound(pBlob->w);
54 r.height = cvRound(pBlob->h);
55 Area = r.width*r.height;
56 if(r.x<0){r.width += r.x;r.x = 0;}
57 if(r.y<0){r.height += r.y;r.y = 0;}
58 if((r.x+r.width)>=pImgFG->width){r.width=pImgFG->width-r.x-1;}
59 if((r.y+r.height)>=pImgFG->height){r.height=pImgFG->height-r.y-1;}
61 if(r.width>0 && r.height>0)
63 double Sum = cvSum(cvGetSubRect(pImgFG,&mat,r)).val[0]/255.0;
68 } /* Calculate sum of mask. */
71 /*============== BLOB TRACKERCC CLASS DECLARATION =============== */
72 typedef struct DefBlobTracker
75 CvBlobTrackPredictor* pPredictor;
82 void cvFindBlobsByCCClasters(IplImage* pFG, CvBlobSeq* pBlobs, CvMemStorage* storage);
84 class CvBlobTrackerCC : public CvBlobTracker
92 const char* m_ConfidenceTypeStr;
94 CvBlobSeq m_BlobListNew;
101 CvBlobTrackerCC():m_BlobList(sizeof(DefBlobTracker))
105 m_pMem = cvCreateMemStorage();
106 m_Collision = 1; /* if 1 then collistion will be detected and processed */
107 AddParam("Collision",&m_Collision);
108 CommentParam("Collision", "If 1 then collision cases are processed in special way");
111 AddParam("AlphaSize",&m_AlphaSize);
112 CommentParam("AlphaSize", "Size update speed (0..1)");
115 AddParam("AlphaPos",&m_AlphaPos);
116 CommentParam("AlphaPos", "Position update speed (0..1)");
119 AddParam("Alpha", &m_Alpha);
120 CommentParam("Alpha","Coefficient for model histogram updating (0 - hist is not updated)");
123 m_ConfidenceTypeStr = "NearestBlob";
124 AddParam("ConfidenceType", &m_ConfidenceTypeStr);
125 CommentParam("ConfidenceType","Type of calculated Confidence (NearestBlob, AverFG, BC)");
132 if(m_pMem)cvReleaseMemStorage(&m_pMem);
135 /* Blob functions: */
136 virtual int GetBlobNum() {return m_BlobList.GetBlobNum();};
137 virtual CvBlob* GetBlob(int BlobIndex){return m_BlobList.GetBlob(BlobIndex);};
138 virtual void SetBlob(int BlobIndex, CvBlob* pBlob)
140 CvBlob* pB = m_BlobList.GetBlob(BlobIndex);
141 if(pB) pB[0] = pBlob[0];
144 virtual CvBlob* GetBlobByID(int BlobID){return m_BlobList.GetBlobByID(BlobID);};
145 virtual void DelBlob(int BlobIndex)
147 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
148 if(pBT==NULL) return;
151 pBT->pPredictor->Release();
155 printf("WARNING!!! Invalid Predictor in CC tracker");
157 delete pBT->pBlobHyp;
158 m_BlobList.DelBlob(BlobIndex);
161 virtual void DelBlobByID(int BlobID)
163 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlobByID(BlobID);
164 pBT->pPredictor->Release();
165 delete pBT->pBlobHyp;
166 m_BlobList.DelBlobByID(BlobID);
169 virtual void Release(){delete this;};
171 /* Add new blob to track it and assign to this blob personal ID */
172 /* pBlob - pinter to structure with blob parameters (ID is ignored)*/
173 /* pImg - current image */
174 /* pImgFG - current foreground mask */
175 /* return pointer to new added blob */
176 virtual CvBlob* AddBlob(CvBlob* pB, IplImage* /*pImg*/, IplImage* pImgFG = NULL )
178 assert(pImgFG); /* This tracker uses only foreground mask. */
181 // CV_BLOB_ID(&NewB) = m_LastID;
182 NewB.pBlobHyp = new CvBlobSeq;
183 NewB.pPredictor = cvCreateModuleBlobTrackPredictKalman(); /* Module for position prediction. */
184 NewB.pPredictor->Update(pB);
185 NewB.AverFG = pImgFG?CalcAverageMask(pB,pImgFG):0;
186 m_BlobList.AddBlob((CvBlob*)&NewB);
187 return m_BlobList.GetBlob(m_BlobList.GetBlobNum()-1);
190 virtual void Process(IplImage* pImg, IplImage* pImgFG = NULL)
199 if(m_BlobList.GetBlobNum() <= 0 ) return;
201 /* Clear bloblist for new blobs: */
202 m_BlobListNew.Clear();
205 cvClearMemStorage(m_pMem);
211 { // By contour clustering:
212 cvFindBlobsByCCClasters(pImgFG, &m_BlobListNew, m_pMem);
215 { /* One contour - one blob: */
216 IplImage* pBin = cvCloneImage(pImgFG);
218 cvThreshold(pBin,pBin,128,255,CV_THRESH_BINARY);
219 cvFindContours(pBin, m_pMem, &cnts, sizeof(CvContour), CV_RETR_EXTERNAL);
221 /* Process each contour: */
222 for(cnt = cnts; cnt; cnt=cnt->h_next)
227 double M00,X,Y,XX,YY;
229 CvRect r = ((CvContour*)cnt)->rect;
231 if(r.height < 3 || r.width < 3) continue;
232 cvMoments( cvGetSubRect(pImgFG,&mat,r), &m, 0 );
233 M00 = cvGetSpatialMoment( &m, 0, 0 );
234 if(M00 <= 0 ) continue;
235 X = cvGetSpatialMoment( &m, 1, 0 )/M00;
236 Y = cvGetSpatialMoment( &m, 0, 1 )/M00;
237 XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X;
238 YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y;
239 NewBlob = cvBlob(r.x+(float)X,r.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY)));
240 m_BlobListNew.AddBlob(&NewBlob);
241 } /* Next contour. */
243 cvReleaseImage(&pBin);
246 for(i=m_BlobList.GetBlobNum(); i>0; --i)
247 { /* Predict new blob position: */
249 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(i-1);
251 /* Update predictor by previous value of blob: */
252 pBT->pPredictor->Update(&(pBT->blob));
254 /* Predict current position: */
255 pB = pBT->pPredictor->Predict();
259 pBT->BlobPredict = pB[0];
263 pBT->BlobPredict = pBT->blob;
265 } /* Predict new blob position. */
268 for(i=m_BlobList.GetBlobNum(); i>0; --i)
269 { /* Predict collision. */
272 DefBlobTracker* pF = (DefBlobTracker*)m_BlobList.GetBlob(i-1);
274 for(j=m_BlobList.GetBlobNum(); j>0; --j)
275 { /* Predict collision: */
278 DefBlobTracker* pF2 = (DefBlobTracker*)m_BlobList.GetBlob(j-1);
280 pB1 = &pF->BlobPredict;
281 pB2 = &pF2->BlobPredict;
283 if( fabs(pB1->x-pB2->x)<0.6*(pB1->w+pB2->w) &&
284 fabs(pB1->y-pB2->y)<0.6*(pB1->h+pB2->h) ) Collision = 1;
289 if( fabs(pB1->x-pB2->x)<0.6*(pB1->w+pB2->w) &&
290 fabs(pB1->y-pB2->y)<0.6*(pB1->h+pB2->h) ) Collision = 1;
294 } /* Check next blob to cross current. */
296 pF->Collision = Collision;
298 } /* Predict collision. */
300 for(i=m_BlobList.GetBlobNum(); i>0; --i)
301 { /* Find a neighbour on current frame
302 * for each blob from previous frame:
304 CvBlob* pB = m_BlobList.GetBlob(i-1);
305 DefBlobTracker* pBT = (DefBlobTracker*)pB;
306 //int BlobID = CV_BLOB_ID(pB);
307 //CvBlob* pBBest = NULL;
308 //double DistBest = -1;
311 if(pBT->pBlobHyp->GetBlobNum()>0)
312 { /* Track all hypotheses: */
313 int h,hN = pBT->pBlobHyp->GetBlobNum();
316 int j, jN = m_BlobListNew.GetBlobNum();
317 CvBlob* pB = pBT->pBlobHyp->GetBlob(h);
318 int BlobID = CV_BLOB_ID(pB);
319 CvBlob* pBBest = NULL;
320 double DistBest = -1;
322 { /* Find best CC: */
324 CvBlob* pBNew = m_BlobListNew.GetBlob(j);
325 double dx = fabs(CV_BLOB_X(pB)-CV_BLOB_X(pBNew));
326 double dy = fabs(CV_BLOB_Y(pB)-CV_BLOB_Y(pBNew));
327 if(dx > 2*CV_BLOB_WX(pB) || dy > 2*CV_BLOB_WY(pB)) continue;
329 Dist = sqrt(dx*dx+dy*dy);
330 if(Dist < DistBest || pBBest == NULL)
335 } /* Find best CC. */
340 CV_BLOB_ID(pB) = BlobID;
343 { /* Delete this hypothesis. */
344 pBT->pBlobHyp->DelBlob(h);
348 } /* Next hypothysis. */
349 } /* Track all hypotheses. */
350 } /* Track next blob. */
356 virtual void ProcessBlob(int BlobIndex, CvBlob* pBlob, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL)
359 CvBlob* pB = m_BlobList.GetBlob(BlobIndex);
360 DefBlobTracker* pBT = (DefBlobTracker*)pB;
361 //CvBlob* pBBest = NULL;
362 //double DistBest = -1;
369 if(m_Collision && pBT->Collision)
370 { /* Tracking in collision: */
371 pB[0]=pBT->BlobPredict;
372 CV_BLOB_ID(pB)=BlobID;
373 } /* Tracking in collision. */
375 { /* Non-collision tracking: */
376 CvBlob* pBBest = GetNearestBlob(pB);
379 float w = pBlob->w*(1-m_AlphaSize)+m_AlphaSize*pBBest->w;
380 float h = pBlob->h*(1-m_AlphaSize)+m_AlphaSize*pBBest->h;
381 float x = pBlob->x*(1-m_AlphaPos)+m_AlphaPos*pBBest->x;
382 float y = pBlob->y*(1-m_AlphaPos)+m_AlphaPos*pBBest->y;
387 CV_BLOB_ID(pB) = BlobID;
389 } /* Non-collision tracking. */
395 virtual double GetConfidence(int BlobIndex, CvBlob* pBlob, IplImage* /*pImg*/, IplImage* pImgFG = NULL)
397 /* Define coefficients in exp by exp(-XT*K)=VT: */
398 static double _KS = -log(0.1)/pow(0.5,2); /* XT = 1, VT = 0.1 - when size is Larger in 2 times Confidence is smoller in 10 times */
399 static double _KP = -log(0.1)/pow(m_pImg->width*0.02,2); /* XT = 0.02*ImgWidth, VT = 0.1*/
400 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
404 CvBlob* pBC = GetNearestBlob(pBlob);
405 if(pBC == NULL ) return 0;
407 dx = pBC->x-pBlob->x;
408 dy = pBC->y-pBlob->y;
409 dw = (pBC->w-pBlob->w)/pBC->w;
410 dh = (pBC->h-pBlob->h)/pBC->h;
416 { /* Confidence for size by nearest blob: */
420 if(m_ConfidenceType==0 && !pBT->Collision)
421 { /* Confidence by nearest blob: */
425 if(m_ConfidenceType==1 && pBT->AverFG>0)
426 { /* Calculate sum of mask: */
427 float Aver = CalcAverageMask(pBlob, pImgFG );
428 if(Aver < pBT->AverFG)
430 float diff = 1+0.9f*(Aver-pBT->AverFG)/pBT->AverFG;
431 if(diff < 0.1f) diff = 0.1f;
434 } /* Calculate sum of mask. */
436 if(m_ConfidenceType==2)
437 { /* Calculate BCoeff: */
439 float Aver = CalcAverageMask(pBlob, pImgFG );
440 double B = sqrt(Aver*pBT->AverFG)+sqrt((1-Aver)*(1-pBT->AverFG));
442 W *= exp((B-1)/(2*S));
443 } /* Calculate sum of mask. */
448 virtual void UpdateBlob(int BlobIndex, CvBlob* /*pBlob*/, IplImage* /*pImg*/, IplImage* pImgFG = NULL)
450 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
452 if(pImgFG==NULL || pBT==NULL) return;
456 //pBT->AverFG = pBT->AverFG * (1-m_Alpha) + m_Alpha * CalcAverageMask(pBlob,pImgFG);
460 virtual void ParamUpdate()
462 const char* pCT[3] = {"NearestBlob","AverFG","BC"};
465 CvBlobTracker::ParamUpdate();
469 if(cv_stricmp(m_ConfidenceTypeStr,pCT[i])==0)
471 m_ConfidenceType = i;
474 SetParamStr("ConfidenceType",pCT[m_ConfidenceType]);
477 /* =============== MULTI HYPOTHESIS INTERFACE ================== */
478 /* Return number of position hypotheses of currently tracked blob: */
479 virtual int GetBlobHypNum(int BlobIdx)
481 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIdx);
482 assert(pBT->pBlobHyp);
483 return pBT->pBlobHyp->GetBlobNum();
484 }; /* CvBlobtrackerList::GetBlobHypNum() */
486 /* Return pointer to specified blob hypothesis by index blob: */
487 virtual CvBlob* GetBlobHyp(int BlobIndex, int hypothesis)
489 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
490 assert(pBT->pBlobHyp);
491 return pBT->pBlobHyp->GetBlob(hypothesis);
492 }; /* CvBlobtrackerList::GetBlobHyp() */
494 /* Set new parameters for specified (by index) blob hypothesis
495 * (can be called several times for each hypothesis):
497 virtual void SetBlobHyp(int BlobIndex, CvBlob* pBlob)
500 { /* Clear all hypotheses: */
501 int b, bN = m_BlobList.GetBlobNum();
504 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(b);
505 assert(pBT->pBlobHyp);
506 pBT->pBlobHyp->Clear();
510 { /* Add hypothesis: */
511 DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
512 assert(pBT->pBlobHyp);
513 pBT->pBlobHyp->AddBlob(pBlob);
518 CvBlob* GetNearestBlob(CvBlob* pB)
520 //DefBlobTracker* pBT = (DefBlobTracker*)pB;
521 CvBlob* pBBest = NULL;
522 double DistBest = -1;
524 if(pB==NULL) return NULL;
526 for(int j=m_BlobListNew.GetBlobNum(); j>0; --j)
527 { /* Find best CC: */
529 CvBlob* pBNew = m_BlobListNew.GetBlob(j-1);
530 double dx = fabs(CV_BLOB_X(pB)-CV_BLOB_X(pBNew));
531 double dy = fabs(CV_BLOB_Y(pB)-CV_BLOB_Y(pBNew));
532 if(dx > 2*CV_BLOB_WX(pB) || dy > 2*CV_BLOB_WY(pB)) continue;
534 Dist = sqrt(dx*dx+dy*dy);
535 if(Dist < DistBest || pBBest == NULL)
541 } /* Find best CC. */
545 }; /* GetNearestBlob */
549 CvBlobTracker* cvCreateBlobTrackerCC()
551 return (CvBlobTracker*) new CvBlobTrackerCC;
553 /*============== BLOB TRACKERCC CLASS DECLARATION =============== */