Update to 2.0.0 tree from current Fremantle build
[opencv] / src / cvaux / 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     const 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
111 private:
112     IplImage*               m_pFGMask;
113     int                     m_FGTrainFrames;
114     CvFGDetector*           m_pFG; /* Pointer to foreground mask detector module. */
115     CvBlobTracker*          m_pBT; /* Pointer to Blob tracker module. */
116     int                     m_BTDel;
117     int                     m_BTReal;
118     CvBlobDetector*         m_pBD; /* Pointer to Blob detector module. */
119     int                     m_BDDel;
120     CvBlobTrackGen*         m_pBTGen;
121     CvBlobTrackPostProc*    m_pBTPostProc;
122     int                     m_UsePPData;
123     CvBlobTrackAnalysis*    m_pBTA; /* Blob trajectory analyser. */
124     CvBlobSeq               m_BlobList;
125     int                     m_FrameCount;
126     int                     m_NextBlobID;
127     const char*                   m_TimesFile;
128
129 public:
130     virtual void SaveState(CvFileStorage* fs)
131     {
132         cvWriteInt(fs,"FrameCount",m_FrameCount);
133         cvWriteInt(fs,"NextBlobID",m_NextBlobID);
134         m_BlobList.Write(fs,"BlobList");
135     };
136
137     virtual void LoadState(CvFileStorage* fs, CvFileNode* node)
138     {
139         CvFileNode* BlobListNode = cvGetFileNodeByName(fs,node,"BlobList");
140         m_FrameCount = cvReadIntByName(fs,node, "FrameCount", m_FrameCount);
141         m_NextBlobID = cvReadIntByName(fs,node, "NextBlobID", m_NextBlobID);
142         if(BlobListNode)
143         {
144             m_BlobList.Load(fs,BlobListNode);
145         }
146     };
147 };
148
149 /* Auto Blob tracker creater (sole interface function for this file) */
150 CvBlobTrackerAuto* cvCreateBlobTrackerAuto1(CvBlobTrackerAutoParam1* param)
151 {
152     return (CvBlobTrackerAuto*)new CvBlobTrackerAuto1(param);
153 }
154
155 /* Constructor of auto blob tracker: */
156 CvBlobTrackerAuto1::CvBlobTrackerAuto1(CvBlobTrackerAutoParam1* param):m_BlobList(sizeof(CvBlobTrackAuto))
157 {
158     m_BlobList.AddFormat("i");
159     m_TimesFile = NULL;
160     AddParam("TimesFile",&m_TimesFile);
161
162     m_NextBlobID = 0;
163     m_pFGMask = NULL;
164     m_FrameCount = 0;
165
166     m_FGTrainFrames = param?param->FGTrainFrames:0;
167     m_pFG = param?param->pFG:0;
168
169     m_BDDel = 0;
170     m_pBD = param?param->pBD:NULL;
171     m_BTDel = 0;
172     m_pBT = param?param->pBT:NULL;;
173     m_BTReal = m_pBT?m_pBT->IsModuleName("BlobTrackerReal"):0;
174
175     m_pBTGen = param?param->pBTGen:NULL;
176
177     m_pBTA = param?param->pBTA:NULL;
178
179     m_pBTPostProc = param?param->pBTPP:NULL;
180     m_UsePPData = param?param->UsePPData:0;
181
182     /* Create default submodules: */
183     if(m_pBD==NULL)
184     {
185         m_pBD = cvCreateBlobDetectorSimple();
186         m_BDDel = 1;
187     }
188
189     if(m_pBT==NULL)
190     {
191         m_pBT = cvCreateBlobTrackerMS();
192         m_BTDel = 1;
193     }
194
195     SetModuleName("Auto1");
196
197 } /* CvBlobTrackerAuto1::CvBlobTrackerAuto1 */
198
199 /* Destructor for auto blob tracker: */
200 CvBlobTrackerAuto1::~CvBlobTrackerAuto1()
201 {
202     if(m_BDDel)m_pBD->Release();
203     if(m_BTDel)m_pBT->Release();
204 }
205
206 void CvBlobTrackerAuto1::Process(IplImage* pImg, IplImage* pMask)
207 {
208     int         CurBlobNum = 0;
209     int         i;
210     IplImage*   pFG = pMask;
211
212     /* Bump frame counter: */
213     m_FrameCount++;
214
215     if(m_TimesFile)
216     {
217         static int64  TickCount = cvGetTickCount();
218         static double TimeSum = 0;
219         static int Count = 0;
220         Count++;
221
222         if(Count%100==0)
223         {
224 #ifndef WINCE
225             time_t ltime;
226             time( &ltime );
227                         char* stime = ctime( &ltime );
228 #else
229                         /* WINCE does not have above POSIX functions (time,ctime) */
230                         const char* stime = " wince ";
231 #endif
232             FILE* out = fopen(m_TimesFile,"at");
233             double Time;
234             TickCount = cvGetTickCount()-TickCount;
235             Time = TickCount/FREQ;
236             if(out){fprintf(out,"- %sFrame: %d ALL_TIME - %f\n",stime,Count,Time/1000);fclose(out);}
237
238             TimeSum = 0;
239             TickCount = cvGetTickCount();
240         }
241     }
242
243     /* Update BG model: */
244     TIME_BEGIN()
245
246     if(m_pFG)
247     {   /* If FG detector is needed: */
248         m_pFG->Process(pImg);
249         pFG = m_pFG->GetMask();
250     }   /* If FG detector is needed. */
251
252     TIME_END("FGDetector",-1)
253
254     m_pFGMask = pFG; /* For external use. */
255
256     /*if(m_pFG && m_pFG->GetParam("DebugWnd") == 1)
257     {// debug foreground result
258         IplImage *pFG = m_pFG->GetMask();
259         if(pFG)
260         {
261             cvNamedWindow("FG",0);
262             cvShowImage("FG", pFG);
263         }
264     }*/
265
266     /* Track blobs: */
267     TIME_BEGIN()
268     if(m_pBT)
269     {
270         int i;
271         m_pBT->Process(pImg, pFG);
272
273         for(i=m_BlobList.GetBlobNum(); i>0; --i)
274         {   /* Update data of tracked blob list: */
275             CvBlob* pB = m_BlobList.GetBlob(i-1);
276             int     BlobID = CV_BLOB_ID(pB);
277             int     i = m_pBT->GetBlobIndexByID(BlobID);
278             m_pBT->ProcessBlob(i, pB, pImg, pFG);
279             pB->ID = BlobID;
280         }
281         CurBlobNum = m_pBT->GetBlobNum();
282     }
283     TIME_END("BlobTracker",CurBlobNum)
284
285     /* This part should be removed: */
286     if(m_BTReal && m_pBT)
287     {   /* Update blob list (detect new blob for real blob tracker): */
288         int i;
289
290         for(i=m_pBT->GetBlobNum(); i>0; --i)
291         {   /* Update data of tracked blob list: */
292             CvBlob* pB = m_pBT->GetBlob(i-1);
293             if(pB && m_BlobList.GetBlobByID(CV_BLOB_ID(pB)) == NULL )
294             {
295                 CvBlobTrackAuto     NewB;
296                 NewB.blob = pB[0];
297                 NewB.BadFrames = 0;
298                 m_BlobList.AddBlob((CvBlob*)&NewB);
299             }
300         }   /* Next blob. */
301
302         /* Delete blobs: */
303         for(i=m_BlobList.GetBlobNum(); i>0; --i)
304         {   /* Update tracked-blob list: */
305             CvBlob* pB = m_BlobList.GetBlob(i-1);
306             if(pB && m_pBT->GetBlobByID(CV_BLOB_ID(pB)) == NULL )
307             {
308                 m_BlobList.DelBlob(i-1);
309             }
310         }   /* Next blob. */
311     }   /* Update bloblist. */
312
313
314     TIME_BEGIN()
315     if(m_pBTPostProc)
316     {   /* Post-processing module: */
317         int i;
318         for(i=m_BlobList.GetBlobNum(); i>0; --i)
319         {   /* Update tracked-blob list: */
320             CvBlob* pB = m_BlobList.GetBlob(i-1);
321             m_pBTPostProc->AddBlob(pB);
322         }
323         m_pBTPostProc->Process();
324
325         for(i=m_BlobList.GetBlobNum(); i>0; --i)
326         {   /* Update tracked-blob list: */
327             CvBlob* pB = m_BlobList.GetBlob(i-1);
328             int     BlobID = CV_BLOB_ID(pB);
329             CvBlob* pBN = m_pBTPostProc->GetBlobByID(BlobID);
330
331             if(pBN && m_UsePPData && pBN->w >= CV_BLOB_MINW && pBN->h >= CV_BLOB_MINH)
332             {   /* Set new data for tracker: */
333                 m_pBT->SetBlobByID(BlobID, pBN );
334             }
335
336             if(pBN)
337             {   /* Update blob list with results from postprocessing: */
338                 pB[0] = pBN[0];
339             }
340         }
341     }   /* Post-processing module. */
342
343     TIME_END("PostProcessing",CurBlobNum)
344
345     /* Blob deleter (experimental and simple): */
346     TIME_BEGIN()
347     if(pFG)
348     {   /* Blob deleter: */
349         int i;
350         if(!m_BTReal)for(i=m_BlobList.GetBlobNum();i>0;--i)
351         {   /* Check all blobs on list: */
352             CvBlobTrackAuto* pB = (CvBlobTrackAuto*)(m_BlobList.GetBlob(i-1));
353             int     Good = 0;
354             int     w=pFG->width;
355             int     h=pFG->height;
356             CvRect  r = CV_BLOB_RECT(pB);
357             CvMat   mat;
358             double  aver = 0;
359             double  area = CV_BLOB_WX(pB)*CV_BLOB_WY(pB);
360             if(r.x < 0){r.width += r.x;r.x = 0;}
361             if(r.y < 0){r.height += r.y;r.y = 0;}
362             if(r.x+r.width>=w){r.width = w-r.x-1;}
363             if(r.y+r.height>=h){r.height = h-r.y-1;}
364
365             if(r.width > 4 && r.height > 4 && r.x < w && r.y < h &&
366                 r.x >=0 && r.y >=0 &&
367                 r.x+r.width < w && r.y+r.height < h && area > 0)
368             {
369                 aver = cvSum(cvGetSubRect(pFG,&mat,r)).val[0] / area;
370                 /* if mask in blob area exists then its blob OK*/
371                 if(aver > 0.1*255)Good = 1;
372             }
373             else
374             {
375                 pB->BadFrames+=2;
376             }
377
378             if(Good)
379             {
380                 pB->BadFrames = 0;
381             }
382             else
383             {
384                 pB->BadFrames++;
385             }
386         }   /* Next blob: */
387
388         /* Check error count: */
389         for(i=0; i<m_BlobList.GetBlobNum(); ++i)
390         {
391             CvBlobTrackAuto* pB = (CvBlobTrackAuto*)m_BlobList.GetBlob(i);
392
393             if(pB->BadFrames>3)
394             {   /* Delete such objects */
395                 /* from tracker...     */
396                 m_pBT->DelBlobByID(CV_BLOB_ID(pB));
397
398                 /* ... and from local list: */
399                 m_BlobList.DelBlob(i);
400                 i--;
401             }
402         }   /* Check error count for next blob. */
403     }   /*  Blob deleter. */
404
405     TIME_END("BlobDeleter",m_BlobList.GetBlobNum())
406
407     /* Update blobs: */
408     TIME_BEGIN()
409     if(m_pBT)
410         m_pBT->Update(pImg, pFG);
411     TIME_END("BlobTrackerUpdate",CurBlobNum)
412
413     /* Detect new blob: */
414     TIME_BEGIN()
415     if(!m_BTReal && m_pBD && pFG && (m_FrameCount > m_FGTrainFrames) )
416     {   /* Detect new blob: */
417         static CvBlobSeq    NewBlobList;
418         CvBlobTrackAuto     NewB;
419
420         NewBlobList.Clear();
421
422         if(m_pBD->DetectNewBlob(pImg, pFG, &NewBlobList, &m_BlobList))
423         {   /* Add new blob to tracker and blob list: */
424             int i;
425             IplImage* pMask = pFG;
426
427             /*if(0)if(NewBlobList.GetBlobNum()>0 && pFG )
428             {// erode FG mask (only for FG_0 and MS1||MS2)
429                 pMask = cvCloneImage(pFG);
430                 cvErode(pFG,pMask,NULL,2);
431             }*/
432
433             for(i=0; i<NewBlobList.GetBlobNum(); ++i)
434             {
435                 CvBlob* pBN = NewBlobList.GetBlob(i);
436                 pBN->ID = m_NextBlobID;
437
438                 if(pBN && pBN->w >= CV_BLOB_MINW && pBN->h >= CV_BLOB_MINH)
439                 {
440                     CvBlob* pB = m_pBT->AddBlob(pBN, pImg, pMask );
441                     if(pB)
442                     {
443                         NewB.blob = pB[0];
444                         NewB.BadFrames = 0;
445                         m_BlobList.AddBlob((CvBlob*)&NewB);
446                         m_NextBlobID++;
447                     }
448                 }
449             }   /* Add next blob from list of detected blob. */
450
451             if(pMask != pFG) cvReleaseImage(&pMask);
452
453         }   /* Create and add new blobs and trackers. */
454
455     }   /*  Detect new blob. */
456
457     TIME_END("BlobDetector",-1)
458
459     TIME_BEGIN()
460     if(m_pBTGen)
461     {   /* Run track generator: */
462         for(i=m_BlobList.GetBlobNum(); i>0; --i)
463         {   /* Update data of tracked blob list: */
464             CvBlob* pB = m_BlobList.GetBlob(i-1);
465             m_pBTGen->AddBlob(pB);
466         }
467         m_pBTGen->Process(pImg, pFG);
468     }   /* Run track generator: */
469     TIME_END("TrajectoryGeneration",-1)
470
471     TIME_BEGIN()
472     if(m_pBTA)
473     {   /* Trajectory analysis module: */
474         int i;
475         for(i=m_BlobList.GetBlobNum(); i>0; i--)
476             m_pBTA->AddBlob(m_BlobList.GetBlob(i-1));
477
478         m_pBTA->Process(pImg, pFG);
479
480     }   /* Trajectory analysis module. */
481
482     TIME_END("TrackAnalysis",m_BlobList.GetBlobNum())
483
484 } /* CvBlobTrackerAuto1::Process */
485