Move the sources to trunk
[opencv] / cvaux / src / vs / blobtrackingauto.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, 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 /*
42 This file contain simple implementation of BlobTrackerAuto virtual interface
43 This module just connected other low level 3 modules 
44 (foreground estimator + BlobDetector + BlobTracker)
45 and some simple code to detect "lost tracking"
46 The track is lost when integral of foreground mask image by blob area has low value 
47 */
48 #include "_cvaux.h"
49 #include <time.h>
50
51 /* list of Blob Detection modules */
52 CvBlobDetector* cvCreateBlobDetectorSimple();
53
54 /* get frequency for each module time working estimation */
55 static double FREQ = 1000*cvGetTickFrequency();
56
57 #if 1
58 #define COUNTNUM 100
59 #define TIME_BEGIN() \
60 {\
61     static double   _TimeSum = 0;\
62     static int      _Count = 0;\
63     static int      _CountBlob = 0;\
64     int64           _TickCount = cvGetTickCount();\
65
66 #define TIME_END(_name_,_BlobNum_)    \
67     _Count++;\
68     _CountBlob+=_BlobNum_;\
69     _TimeSum += (cvGetTickCount()-_TickCount)/FREQ;\
70     if(m_TimesFile)if(_Count%COUNTNUM==0)\
71     { \
72         FILE* out = fopen(m_TimesFile,"at");\
73         if(out)\
74         {\
75             fprintf(out,"ForFrame Frame: %d %s %f on %f blobs\n",_Count,_name_, _TimeSum/COUNTNUM,((float)_CountBlob)/COUNTNUM);\
76             if(_CountBlob>0)fprintf(out,"ForBlob  Frame: %d %s - %f\n",_Count,_name_, _TimeSum/_CountBlob);\
77             fclose(out);\
78         }\
79         _TimeSum = 0;\
80         _CountBlob = 0;\
81     }\
82 }
83 #else
84 #define TIME_BEGIN()
85 #define TIME_END(_name_)
86 #endif
87
88 /* special extended blob structure for auto blob tracking */
89 typedef struct CvBlobTrackAuto
90 {
91     CvBlob  blob;
92     int     BadFrames;
93 }CvBlobTrackAuto;
94
95 class CvBlobTrackerAuto1: public CvBlobTrackerAuto
96 {
97 public:
98     CvBlobTrackerAuto1(CvBlobTrackerAutoParam1* param);
99     ~CvBlobTrackerAuto1();
100     CvBlob* GetBlob(int index){return m_BlobList.GetBlob(index);};
101     CvBlob* GetBlobByID(int ID){return m_BlobList.GetBlobByID(ID);};
102     int     GetBlobNum(){return m_BlobList.GetBlobNum();};
103     virtual IplImage* GetFGMask(){return m_pFGMask;};
104     float   GetState(int BlobID){return m_pBTA?m_pBTA->GetState(BlobID):0;};
105     char*   GetStateDesc(int BlobID){return m_pBTA?m_pBTA->GetStateDesc(BlobID):NULL;};
106     /* return 0 if trajectory is normal 
107        return >0 if trajectory abnormal */
108     void Process(IplImage* pImg, IplImage* pMask = NULL);
109     void Release(){delete this;};
110 private:
111     IplImage*               m_pFGMask;
112     int                     m_FGTrainFrames;
113     CvFGDetector*           m_pFG; /* pointer to foreground mask detector modelu */
114     CvBlobTracker*          m_pBT; /* pointer to Blob tracker module */
115     int                     m_BTDel;
116     int                     m_BTReal;
117     CvBlobDetector*         m_pBD; /* pointer to Blob detector module */
118     int                     m_BDDel;
119     CvBlobTrackGen*         m_pBTGen;
120     CvBlobTrackPostProc*    m_pBTPostProc;
121     int                     m_UsePPData;
122     CvBlobTrackAnalysis*    m_pBTA; /* blob trajectory analyser */
123     CvBlobSeq               m_BlobList;
124     int                     m_FrameCount;
125     int                     m_NextBlobID;
126     char*                   m_TimesFile;
127 public:
128     virtual void SaveState(CvFileStorage* fs)
129     {
130         cvWriteInt(fs,"FrameCount",m_FrameCount);
131         cvWriteInt(fs,"NextBlobID",m_NextBlobID);
132         m_BlobList.Write(fs,"BlobList");
133     };
134     virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
135     {
136         CvFileNode* BlobListNode = cvGetFileNodeByName(fs,node,"BlobList");
137         m_FrameCount = cvReadIntByName(fs,node, "FrameCount", m_FrameCount);
138         m_NextBlobID = cvReadIntByName(fs,node, "NextBlobID", m_NextBlobID);
139         if(BlobListNode)
140         {
141             m_BlobList.Load(fs,BlobListNode);
142         }
143     };
144 };
145
146 /* Auto Blob tracker creater (sole interface function for this file) */
147 CvBlobTrackerAuto* cvCreateBlobTrackerAuto1(CvBlobTrackerAutoParam1* param)
148 {
149     return (CvBlobTrackerAuto*)new CvBlobTrackerAuto1(param);
150 }
151
152 /* Constructor of auto blob tracker*/
153 CvBlobTrackerAuto1::CvBlobTrackerAuto1(CvBlobTrackerAutoParam1* param):m_BlobList(sizeof(CvBlobTrackAuto))
154 {
155     m_BlobList.AddFormat("i");
156     m_TimesFile = NULL;
157     AddParam("TimesFile",&m_TimesFile);
158
159     m_NextBlobID = 0;
160     m_pFGMask = NULL;
161     m_FrameCount = 0;
162
163     m_FGTrainFrames = param?param->FGTrainFrames:0;
164     m_pFG = param?param->pFG:0;
165
166     m_BDDel = 0;
167     m_pBD = param?param->pBD:NULL;
168     m_BTDel = 0;
169     m_pBT = param?param->pBT:NULL;;
170     m_BTReal = m_pBT?m_pBT->IsModuleName("BlobTrackerReal"):0;
171
172     m_pBTGen = param?param->pBTGen:NULL;
173
174     m_pBTA = param?param->pBTA:NULL;
175
176     m_pBTPostProc = param?param->pBTPP:NULL;
177     m_UsePPData = param?param->UsePPData:0;
178
179     /* create default sub modules */
180     if(m_pBD==NULL)
181     {
182         m_pBD = cvCreateBlobDetectorSimple();
183         m_BDDel = 1;
184     }
185     if(m_pBT==NULL)
186     {
187         m_pBT = cvCreateBlobTrackerMS();
188         m_BTDel = 1;
189     }
190
191 }/* CvBlobTrackerAuto1::CvBlobTrackerAuto1 */
192
193 /* Destructor of auto blob tracker */
194 CvBlobTrackerAuto1::~CvBlobTrackerAuto1()
195 {
196     if(m_BDDel)m_pBD->Release();
197     if(m_BTDel)m_pBT->Release();
198 }/* Destructor of auto blob tracker */
199
200 void CvBlobTrackerAuto1::Process(IplImage* pImg, IplImage* pMask)
201 {
202     int         CurBlobNum = 0;
203     int         i;
204     IplImage*   pFG = pMask;
205     
206     /* increase frame counter */
207     m_FrameCount++;
208     
209     if(m_TimesFile)
210     {
211         static int64  TickCount = cvGetTickCount();
212         static double TimeSum = 0;
213         static int Count = 0;
214         Count++;
215         if(Count%100==0)
216         {
217             time_t ltime;
218             time( &ltime );
219             FILE* out = fopen(m_TimesFile,"at");
220             double Time;
221             TickCount = cvGetTickCount()-TickCount;
222             Time = TickCount/FREQ;       
223             if(out){fprintf(out,"- %sFrame: %d ALL_TIME - %f\n",ctime( &ltime ),Count,Time/1000);fclose(out);}
224
225             TimeSum = 0;
226             TickCount = cvGetTickCount();
227         }
228     }
229     
230     /* update BG model */
231     TIME_BEGIN()
232     if(m_pFG)
233     {/* if FG detector is needed */
234         m_pFG->Process(pImg);
235         pFG = m_pFG->GetMask();
236     }/* if FG detector is needed */
237     TIME_END("FGDetector",-1)
238     m_pFGMask = pFG; /* for external use */
239
240     /*if(m_pFG && m_pFG->GetParam("DebugWnd") == 1)
241     {// debug foreground result
242         IplImage *pFG = m_pFG->GetMask();
243         if(pFG)
244         {
245             cvNamedWindow("FG",0);
246             cvShowImage("FG", pFG);
247         }
248     }*/
249
250     /* track blobs */
251     TIME_BEGIN()
252     if(m_pBT)
253     {
254         int i;
255         m_pBT->Process(pImg, pFG);
256         for(i=m_BlobList.GetBlobNum();i>0;--i)
257         {/* update data of tracked blob list */
258             CvBlob* pB = m_BlobList.GetBlob(i-1);
259             int     BlobID = CV_BLOB_ID(pB);
260             int     i = m_pBT->GetBlobIndexByID(BlobID);
261             m_pBT->ProcessBlob(i, pB, pImg, pFG);
262             pB->ID = BlobID;
263         }
264         CurBlobNum = m_pBT->GetBlobNum();
265     }
266     TIME_END("BlobTracker",CurBlobNum)
267
268     /* this part should be removed */
269     if(m_BTReal && m_pBT)
270     {/* update blob list (detect new blob for real blob tracker )*/
271         int i;
272         for(i=m_pBT->GetBlobNum();i>0;--i)
273         {/* update data of tracked blob list */
274             CvBlob* pB = m_pBT->GetBlob(i-1);
275             if(pB && m_BlobList.GetBlobByID(CV_BLOB_ID(pB)) == NULL )
276             {
277                 CvBlobTrackAuto     NewB;
278                 NewB.blob = pB[0];
279                 NewB.BadFrames = 0;
280                 m_BlobList.AddBlob((CvBlob*)&NewB);
281             }
282         }/* next blob */
283         /*delete blobs */
284         for(i=m_BlobList.GetBlobNum();i>0;--i)
285         {/* update data of tracked blob list */
286             CvBlob* pB = m_BlobList.GetBlob(i-1);
287             if(pB && m_pBT->GetBlobByID(CV_BLOB_ID(pB)) == NULL )
288             {
289                 m_BlobList.DelBlob(i-1);
290             }
291         }/* next blob */
292     }/* update blob list */
293
294
295     TIME_BEGIN()
296     if(m_pBTPostProc)
297     {/* post processing module */
298         int i;
299         for(i=m_BlobList.GetBlobNum();i>0;--i)
300         {/* update data of tracked blob list */
301             CvBlob* pB = m_BlobList.GetBlob(i-1);
302             m_pBTPostProc->AddBlob(pB);
303         }
304         m_pBTPostProc->Process();
305
306         for(i=m_BlobList.GetBlobNum();i>0;--i)
307         {/* update data of tracked blob list */
308             CvBlob* pB = m_BlobList.GetBlob(i-1);
309             int     BlobID = CV_BLOB_ID(pB);
310             CvBlob* pBN = m_pBTPostProc->GetBlobByID(BlobID);
311
312             if(pBN && m_UsePPData && pBN->w >= CV_BLOB_MINW && pBN->h >= CV_BLOB_MINH)
313             { /* set new data for tracker */
314                 m_pBT->SetBlobByID(BlobID, pBN );
315             }
316             
317             if(pBN)
318             {/* update blob list by result from postprocessing */
319                 pB[0] = pBN[0];
320             }
321         }
322     }/* post processing module */
323     TIME_END("PostProcessing",CurBlobNum)
324
325     /* Blob deleter (experimental and simple)*/
326     TIME_BEGIN()
327     if(pFG)
328     {/* Blob deleter */
329         int i;
330         if(!m_BTReal)for(i=m_BlobList.GetBlobNum();i>0;--i)
331         {/* check all blobs from list */
332             CvBlobTrackAuto* pB = (CvBlobTrackAuto*)(m_BlobList.GetBlob(i-1));
333             int     Good = 0;
334             int     w=pFG->width;
335             int     h=pFG->height;
336             CvRect  r = CV_BLOB_RECT(pB);
337             CvMat   mat;
338             double  aver = 0;
339             double  area = CV_BLOB_WX(pB)*CV_BLOB_WY(pB);
340             if(r.x < 0){r.width += r.x;r.x = 0;}
341             if(r.y < 0){r.height += r.y;r.y = 0;}
342             if(r.x+r.width>=w){r.width = w-r.x-1;}
343             if(r.y+r.height>=h){r.height = h-r.y-1;}
344
345             if(r.width > 4 && r.height > 4 && r.x < w && r.y < h && 
346                 r.x >=0 && r.y >=0 &&
347                 r.x+r.width < w && r.y+r.height < h && area > 0)
348             {
349                 aver = cvSum(cvGetSubRect(pFG,&mat,r)).val[0] / area;
350                 /* if mask in blob area exists then its blob OK*/
351                 if(aver > 0.1*255)Good = 1;
352             }
353             else
354             {
355                 pB->BadFrames+=2;
356             }
357
358             if(Good)
359             {
360                 pB->BadFrames = 0;
361             }
362             else
363             {
364                 pB->BadFrames++;
365             }
366         }/* next blob */
367         
368         /* check error count */
369         for(i=0;i<m_BlobList.GetBlobNum();++i)
370         {
371             CvBlobTrackAuto* pB = (CvBlobTrackAuto*)m_BlobList.GetBlob(i);
372             if(pB->BadFrames>3)
373             {/* delete such object */
374                 /* from tracker */
375                 m_pBT->DelBlobByID(CV_BLOB_ID(pB));
376                 /* from local list */
377                 m_BlobList.DelBlob(i);
378                 i--;
379             }
380         }/* check error count for next blob */
381     }/* Blob deleter */
382     TIME_END("BlobDeleter",m_BlobList.GetBlobNum())
383     
384     /* Update blobs */
385     TIME_BEGIN()
386     if(m_pBT)
387         m_pBT->Update(pImg, pFG);
388     TIME_END("BlobTrackerUpdate",CurBlobNum)
389
390     /* detect new blob */
391     TIME_BEGIN()
392     if(!m_BTReal && m_pBD && pFG && (m_FrameCount > m_FGTrainFrames) )
393     {/* detect new blob */
394         static CvBlobSeq    NewBlobList;
395         CvBlobTrackAuto     NewB;
396
397         NewBlobList.Clear();
398
399         if(m_pBD->DetectNewBlob(pImg, pFG, &NewBlobList, &m_BlobList))
400         {/* add new blob to tracker and blob list */
401             int i;
402             IplImage* pMask = pFG;
403             
404             /*if(0)if(NewBlobList.GetBlobNum()>0 && pFG )
405             {// erode FG mask (only for FG_0 and MS1||MS2)
406                 pMask = cvCloneImage(pFG);
407                 cvErode(pFG,pMask,NULL,2);
408             }*/
409
410             for(i=0;i<NewBlobList.GetBlobNum();++i)
411             {
412                 CvBlob* pBN = NewBlobList.GetBlob(i);
413                 pBN->ID = m_NextBlobID;
414                 if(pBN && pBN->w >= CV_BLOB_MINW && pBN->h >= CV_BLOB_MINH)
415                 {
416                     CvBlob* pB = m_pBT->AddBlob(pBN, pImg, pMask );
417                     if(pB)
418                     {
419                         NewB.blob = pB[0];
420                         NewB.BadFrames = 0;
421                         m_BlobList.AddBlob((CvBlob*)&NewB);
422                         m_NextBlobID++;
423                     }
424                 }
425             }/* add next blob from list of detected blob */
426
427             if(pMask != pFG) cvReleaseImage(&pMask);
428
429         }/* create and add new blobs and trackers */
430     }/* detect new blob */
431     TIME_END("BlobDetector",-1)
432
433     TIME_BEGIN()
434     if(m_pBTGen)
435     {/* run tracj generator */
436         for(i=m_BlobList.GetBlobNum();i>0;--i)
437         {/* update data of tracked blob list */
438             CvBlob* pB = m_BlobList.GetBlob(i-1);
439             m_pBTGen->AddBlob(pB);
440         }
441         m_pBTGen->Process(pImg, pFG);
442     }/* run tracj generator */
443     TIME_END("TrajectoryGeneration",-1)
444
445     TIME_BEGIN()
446     if(m_pBTA)
447     {/* trajectory analysis module */
448         int i;
449         for(i=m_BlobList.GetBlobNum();i>0;i--)
450             m_pBTA->AddBlob(m_BlobList.GetBlob(i-1));
451         m_pBTA->Process(pImg, pFG);
452     }/* trajectory analysis module */
453     TIME_END("TrackAnalysis",m_BlobList.GetBlobNum())
454
455 }/* CvBlobTrackerAuto1::Process */
456