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
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
42 #include "precomp.hpp"
44 typedef struct DefTrackPoint
54 DefTrackRec(int id = 0,int BlobSize = sizeof(DefTrackPoint))
57 m_pMem = cvCreateMemStorage();
58 m_pSeq = cvCreateSeq(0,sizeof(CvSeq),BlobSize,m_pMem);
62 cvReleaseMemStorage(&m_pMem);
64 inline DefTrackPoint* GetPoint(int PointIndex)
66 return (DefTrackPoint*)cvGetSeqElem(m_pSeq,PointIndex);
68 inline void DelPoint(int PointIndex)
70 cvSeqRemove(m_pSeq,PointIndex);
76 inline void AddPoint(float x, float y, float r)
78 DefTrackPoint p = {x,y,r,0,0,0};
79 int Num = GetPointNum();
83 DefTrackPoint* pPrev = GetPoint(Num-1);
85 float dx = x-pPrev->x;
86 float dy = y-pPrev->y;
87 p.vx = Alpha*dx+(1-Alpha)*pPrev->vx;
88 p.vy = Alpha*dy+(1-Alpha)*pPrev->vy;
89 p.v = Alpha*dx+(1-Alpha)*pPrev->v;
94 inline void AddPoint(DefTrackPoint* pB)
95 { /* Add point and recalculate last velocities: */
103 for(i=MAX(0,Num-wnd-1); i<Num; ++i)
104 { /* Next updating point: */
105 DefTrackPoint* p = GetPoint(i);
114 float dt = (float)(j1-j0);
115 DefTrackPoint* p0 = GetPoint(j0);
116 DefTrackPoint* p1 = GetPoint(j1);
117 p->vx = (p1->x - p0->x) / dt;
118 p->vy = (p1->y - p0->y) / dt;
119 p->v = (float)sqrt(p->vx*p->vx+p->vy*p->vy);
121 } /* Next updating point. */
127 printf("Blob %d: ",ID);
129 for(i=0; i<GetPointNum(); ++i)
131 DefTrackPoint* p = GetPoint(i);
132 printf(",(%.2f,%.2f,%f.2)",p->vx,p->vy,p->v);
138 inline int GetPointNum()
140 return m_pSeq->total;
143 CvMemStorage* m_pMem;
147 /* Fill array pIdxPairs by pair of index of correspondent blobs. */
148 /* Return number of pairs. */
149 /* pIdxPairs must have size not less that 2*(pSeqNum+pSeqTNum) */
150 /* pTmp is pointer to memory which size is pSeqNum*pSeqTNum*16 */
151 typedef struct DefMatch
153 int Idx; /* Previous best blob index. */
154 int IdxT; /* Previous best template blob index. */
155 double D; /* Blob to blob distance sum. */
158 static int cvTrackMatch(DefTrackRec* pSeq, int MaxLen, DefTrackRec* pSeqT, int* pIdxPairs, void* pTmp)
161 DefMatch* pMT = (DefMatch*)pTmp;
162 int Num = pSeq->GetPointNum();
163 int NumT = pSeqT->GetPointNum();
165 int i0=0; /* Last point in the track sequence. */
167 if(MaxLen > 0 && Num > MaxLen)
168 { /* Set new point seq len and new last point in this seq: */
170 i0 = pSeq->GetPointNum() - Num;
174 { /* For each point row: */
175 for(it=0; it<NumT; ++it)
176 { /* For each point template column: */
177 DefTrackPoint* pB = pSeq->GetPoint(i+i0);
178 DefTrackPoint* pBT = pSeqT->GetPoint(it);
179 DefMatch* pMT_cur = pMT + i*NumT + it;
180 double dx = pB->x-pBT->x;
181 double dy = pB->y-pBT->y;
182 double D = dx*dx+dy*dy;
183 int DI[3][2] = {{-1,-1},{-1,0},{0,-1}};
192 for(iDI=0; iDI<3; ++iDI)
194 int i_prev = i+DI[iDI][0];
195 int it_prev = it+DI[iDI][1];
197 if(i_prev >= 0 && it_prev>=0)
199 double D_cur = D+pMT[NumT*i_prev+it_prev].D;
201 if(pMT_cur->D > D_cur || (pMT_cur->Idx<0) )
202 { /* Set new best local way: */
204 pMT_cur->Idx = i_prev;
205 pMT_cur->IdxT = it_prev;
208 } /* Check next direction. */
209 } /* Fill next colum from table. */
210 } /* Fill next row. */
212 { /* Back tracking. */
213 /* Find best end in template: */
215 DefMatch* pMT_best = pMT + (Num-1)*NumT;
216 i = Num-1; /* set current i to last position */
218 for(it=1; it<NumT; ++it)
220 DefMatch* pMT_new = pMT + it + i*NumT;
222 if(pMT_best->D > pMT_new->D)
224 pMT_best->D = pMT_new->D;
227 } /* Find best end template point. */
229 /* Back tracking whole sequence: */
230 for(it = it_best;i>=0 && it>=0;)
232 DefMatch* pMT_new = pMT + it + i*NumT;
233 pIdxPairs[2*NumPair] = i+i0;
234 pIdxPairs[2*NumPair+1] = it;
240 } /* End back tracing. */
243 } /* cvTrackMatch. */
245 typedef struct DefTrackForDist
255 class CvBlobTrackAnalysisTrackDist : public CvBlobTrackAnalysis
257 /*---------------- Internal functions: --------------------*/
259 const char* m_pDebugAVIName; /* For debugging. */
260 //CvVideoWriter* m_pDebugAVI; /* For debugging. */
261 IplImage* m_pDebugImg; /* For debugging. */
263 char m_DataFileName[1024];
265 CvBlobSeq m_TrackDataBase;
270 float m_AbnormalThreshold;
271 float m_PosThreshold;
272 float m_VelThreshold;
273 inline void* ReallocTempData(int Size)
275 if(Size <= m_TempDataSize && m_pTempData) return m_pTempData;
276 cvFree(&m_pTempData);
278 m_pTempData = cvAlloc(Size);
279 if(m_pTempData) m_TempDataSize = Size;
281 } /* ReallocTempData. */
284 CvBlobTrackAnalysisTrackDist():m_Tracks(sizeof(DefTrackForDist)),m_TrackDataBase(sizeof(DefTrackForDist))
292 m_pDebugAVIName = NULL;
293 AddParam("DebugAVI",&m_pDebugAVIName);
294 CommentParam("DebugAVI","Name of AVI file to save images from debug window");
297 AddParam("TraceLen",&m_TraceLen);
298 CommentParam("TraceLen","Length (in frames) of trajectory part that is used for comparison");
300 m_AbnormalThreshold = 0.02f;
301 AddParam("AbnormalThreshold",&m_AbnormalThreshold);
302 CommentParam("AbnormalThreshold","If trajectory is equal with less then <AbnormalThreshold*DataBaseTrackNum> tracks then trajectory is abnormal");
304 m_PosThreshold = 1.25;
305 AddParam("PosThreshold",&m_PosThreshold);
306 CommentParam("PosThreshold","Minimal allowd distance in blob width that is allowed");
308 m_VelThreshold = 0.5;
309 AddParam("VelThreshold",&m_VelThreshold);
310 CommentParam("VelThreshold","Minimal allowed relative difference between blob speed");
312 SetModuleName("TrackDist");
316 ~CvBlobTrackAnalysisTrackDist()
319 for(i=m_Tracks.GetBlobNum(); i>0; --i)
321 DefTrackForDist* pF = (DefTrackForDist*)m_Tracks.GetBlob(i-1);
324 if(m_pDebugImg) cvReleaseImage(&m_pDebugImg);
325 //if(m_pDebugAVI) cvReleaseVideoWriter(&m_pDebugAVI);
328 /*----------------- Interface: --------------------*/
329 virtual void AddBlob(CvBlob* pBlob)
331 DefTrackForDist* pF = (DefTrackForDist*)m_Tracks.GetBlobByID(CV_BLOB_ID(pBlob));
334 { /* Create new TRack record: */
338 F.LastFrame = m_Frame;
339 F.pTrack = new DefTrackRec(CV_BLOB_ID(pBlob));
340 m_Tracks.AddBlob((CvBlob*)&F);
341 pF = (DefTrackForDist*)m_Tracks.GetBlobByID(CV_BLOB_ID(pBlob));
346 pF->pTrack->AddPoint(pBlob->x,pBlob->y,pBlob->w*0.5f);
348 pF->LastFrame = m_Frame;
351 virtual void Process(IplImage* pImg, IplImage* /*pFG*/)
353 double MinTv = pImg->width/1440.0; /* minimal threshold for speed difference */
354 double MinTv2 = MinTv*MinTv;
356 for(int i=m_Tracks.GetBlobNum(); i>0; --i)
358 DefTrackForDist* pF = (DefTrackForDist*)m_Tracks.GetBlob(i-1);
361 if(pF->LastFrame == m_Frame || pF->LastFrame+1 == m_Frame)
362 { /* Process one blob trajectory: */
366 for(it=m_TrackDataBase.GetBlobNum(); it>0; --it)
367 { /* Check template: */
368 DefTrackForDist* pFT = (DefTrackForDist*)m_TrackDataBase.GetBlob(it-1);
369 int Num = pF->pTrack->GetPointNum();
370 int NumT = pFT->pTrack->GetPointNum();
371 int* pPairIdx = (int*)ReallocTempData(sizeof(int)*2*(Num+NumT)+sizeof(DefMatch)*Num*NumT);
372 void* pTmpData = pPairIdx+2*(Num+NumT);
382 PairNum = cvTrackMatch( pF->pTrack, m_TraceLen, pFT->pTrack, pPairIdx, pTmpData );
383 Equal = MAX(1,cvRound(PairNum*0.1));
385 UseVel = 3*pF->pTrack->GetPointNum() > m_TraceLen;
386 UsePos = 10*pF->pTrack->GetPointNum() > m_TraceLen;
388 { /* Check continues: */
390 int DI = pPairIdx[0*2+0]-pPairIdx[(PairNum-1)*2+0];
391 int DIt = pPairIdx[0*2+1]-pPairIdx[(PairNum-1)*2+1];
392 if(UseVel && DI != 0)
394 D = (float)(DI-DIt)/(float)DI;
395 if(fabs(D)>m_VelThreshold)Equal=0;
396 if(fabs(D)>m_VelThreshold*0.5)Equal/=2;
398 } /* Check continues. */
400 for(k=0; Equal>0 && k<PairNum; ++k)
401 { /* Compare with threshold: */
402 int j = pPairIdx[k*2+0];
403 int jt = pPairIdx[k*2+1];
404 DefTrackPoint* pB = pF->pTrack->GetPoint(j);
405 DefTrackPoint* pBT = pFT->pTrack->GetPoint(jt);
406 double dx = pB->x-pBT->x;
407 double dy = pB->y-pBT->y;
408 double dvx = pB->vx - pBT->vx;
409 double dvy = pB->vy - pBT->vy;
410 //double dv = pB->v - pBT->v;
411 double D = dx*dx+dy*dy;
412 double Td = pBT->r*m_PosThreshold;
413 double dv2 = dvx*dvx+dvy*dvy;
414 double Tv2 = (pBT->vx*pBT->vx+pBT->vy*pBT->vy)*m_VelThreshold*m_VelThreshold;
415 double Tvm = pBT->v*m_VelThreshold;
418 if(Tv2 < MinTv2) Tv2 = MinTv2;
419 if(Tvm < MinTv) Tvm = MinTv;
421 /* Check trajectory position: */
422 if(UsePos && D > Td*Td)
427 /* Check trajectory velocity. */
428 /* Don't consider trajectory tail because its unstable for velocity computation. */
429 if(UseVel && j>5 && jt>5 && dv2 > Tv2 )
433 } /* Compare with threshold. */
440 } /* Next template. */
442 { /* Calculate state: */
443 float T = m_TrackDataBase.GetBlobNum() * m_AbnormalThreshold; /* calc threshold */
447 pF->state = (T - NumEq)/(T*0.2f) + 0.5f;
449 if(pF->state<0)pF->state=0;
450 if(pF->state>1)pF->state=1;
452 /*if(0)if(pF->state>0)
454 printf("Abnormal blob(%d) %d < %f, state=%f\n",CV_BLOB_ID(pF),NumEq,T, pF->state);
456 } /* Calculate state. */
457 } /* Process one blob trajectory. */
459 { /* Move track to tracks data base: */
460 m_TrackDataBase.AddBlob((CvBlob*)pF);
461 m_Tracks.DelBlob(i-1);
467 { /* Debug output: */
469 if(m_pDebugImg==NULL)
470 m_pDebugImg = cvCloneImage(pImg);
472 cvCopy(pImg, m_pDebugImg);
474 for(int i=m_TrackDataBase.GetBlobNum(); i>0; --i)
475 { /* Draw all elements in track data base: */
477 DefTrackForDist* pF = (DefTrackForDist*)m_TrackDataBase.GetBlob(i-1);
478 CvScalar color = CV_RGB(0,0,0);
479 if(!pF->close) continue;
482 color = CV_RGB(0,0,255);
486 color = CV_RGB(0,0,128);
489 for(j=pF->pTrack->GetPointNum(); j>0; j--)
491 DefTrackPoint* pB = pF->pTrack->GetPoint(j-1);
492 int r = 0;//MAX(cvRound(pB->r),1);
493 cvCircle(m_pDebugImg, cvPoint(cvRound(pB->x),cvRound(pB->y)), r, color);
496 } /* Draw all elements in track data base. */
498 for(int i=m_Tracks.GetBlobNum(); i>0; --i)
499 { /* Draw all elements for all trajectories: */
500 DefTrackForDist* pF = (DefTrackForDist*)m_Tracks.GetBlob(i-1);
502 int c = cvRound(pF->state*255);
503 CvScalar color = CV_RGB(c,255-c,0);
504 CvPoint p = cvPointFrom32f(CV_BLOB_CENTER(pF));
505 int x = cvRound(CV_BLOB_RX(pF)), y = cvRound(CV_BLOB_RY(pF));
506 CvSize s = cvSize(MAX(1,x), MAX(1,y));
508 cvEllipse( m_pDebugImg,
512 CV_RGB(c,255-c,0), cvRound(1+(0*c)/255) );
514 for(j=pF->pTrack->GetPointNum(); j>0; j--)
516 DefTrackPoint* pB = pF->pTrack->GetPoint(j-1);
517 if(pF->pTrack->GetPointNum()-j > m_TraceLen) break;
518 cvCircle(m_pDebugImg, cvPoint(cvRound(pB->x),cvRound(pB->y)), 0, color);
522 } /* Draw all elements for all trajectories. */
524 //cvNamedWindow("Tracks",0);
525 //cvShowImage("Tracks", m_pDebugImg);
526 } /* Debug output. */
529 if(m_pDebugImg && m_pDebugAVIName)
531 if(m_pDebugAVI==NULL)
532 { /* Create avi file for writing: */
533 m_pDebugAVI = cvCreateVideoWriter(
535 CV_FOURCC('x','v','i','d'),
537 cvSize(m_pDebugImg->width,m_pDebugImg->height));
539 if(m_pDebugAVI == NULL)
541 printf("WARNING!!! Can not create AVI file %s for writing\n",m_pDebugAVIName);
543 } /* Create avi file for writing. */
545 if(m_pDebugAVI)cvWriteFrame( m_pDebugAVI, m_pDebugImg );
546 } /* Write debug window to AVI file. */
550 float GetState(int BlobID)
552 DefTrackForDist* pF = (DefTrackForDist*)m_Tracks.GetBlobByID(BlobID);
553 return pF?pF->state:0.0f;
556 /* Return 0 if trajectory is normal;
557 return >0 if trajectory abnormal. */
558 virtual const char* GetStateDesc(int BlobID)
560 if(GetState(BlobID)>0.5) return "abnormal";
564 virtual void SetFileName(char* DataBaseName)
566 m_DataFileName[0] = m_DataFileName[1000] = 0;
569 strncpy(m_DataFileName,DataBaseName,1000);
570 strcat(m_DataFileName, ".yml");
574 virtual void Release(){ delete this; };
579 CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisTrackDist()
580 {return (CvBlobTrackAnalysis*) new CvBlobTrackAnalysisTrackDist;}