mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
485 lines
15 KiB
485 lines
15 KiB
/*M/////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
|
// |
|
// By downloading, copying, installing or using the software you agree to this license. |
|
// If you do not agree to this license, do not download, install, |
|
// copy or use the software. |
|
// |
|
// |
|
// Intel License Agreement |
|
// |
|
// Copyright (C) 2000, Intel Corporation, rights reserved. |
|
// Third party copyrights are property of their respective owners. |
|
// |
|
// Redistribution and use in source and binary forms, with or without modification, |
|
// are permitted provided that the following conditions are met: |
|
// |
|
// * Redistribution's of source code must retain the above copyright notice, |
|
// this list of conditions and the following disclaimer. |
|
// |
|
// * Redistribution's in binary form must reproduce the above copyright notice, |
|
// this list of conditions and the following disclaimer in the documentation |
|
// and/or other materials provided with the distribution. |
|
// |
|
// * The name of Intel Corporation may not be used to endorse or promote products |
|
// derived from this software without specific prior written permission. |
|
// |
|
// This software is provided by the copyright holders and contributors "as is" and |
|
// any express or implied warranties, including, but not limited to, the implied |
|
// warranties of merchantability and fitness for a particular purpose are disclaimed. |
|
// In no event shall the Intel Corporation or contributors be liable for any direct, |
|
// indirect, incidental, special, exemplary, or consequential damages |
|
// (including, but not limited to, procurement of substitute goods or services; |
|
// loss of use, data, or profits; or business interruption) however caused |
|
// and on any theory of liability, whether in contract, strict liability, |
|
// or tort (including negligence or otherwise) arising in any way out of |
|
// the use of this software, even if advised of the possibility of such damage. |
|
// |
|
//M*/ |
|
|
|
/* |
|
This file contain simple implementation of BlobTrackerAuto virtual interface |
|
This module just connected other low level 3 modules |
|
(foreground estimator + BlobDetector + BlobTracker) |
|
and some simple code to detect "lost tracking" |
|
The track is lost when integral of foreground mask image by blob area has low value |
|
*/ |
|
#include "precomp.hpp" |
|
#include <time.h> |
|
|
|
/* list of Blob Detection modules */ |
|
CvBlobDetector* cvCreateBlobDetectorSimple(); |
|
|
|
/* Get frequency for each module time working estimation: */ |
|
static double FREQ = 1000*cvGetTickFrequency(); |
|
|
|
#if 1 |
|
#define COUNTNUM 100 |
|
#define TIME_BEGIN() \ |
|
{\ |
|
static double _TimeSum = 0;\ |
|
static int _Count = 0;\ |
|
static int _CountBlob = 0;\ |
|
int64 _TickCount = cvGetTickCount();\ |
|
|
|
#define TIME_END(_name_,_BlobNum_) \ |
|
_Count++;\ |
|
_CountBlob+=_BlobNum_;\ |
|
_TimeSum += (cvGetTickCount()-_TickCount)/FREQ;\ |
|
if(m_TimesFile)if(_Count%COUNTNUM==0)\ |
|
{ \ |
|
FILE* out = fopen(m_TimesFile,"at");\ |
|
if(out)\ |
|
{\ |
|
fprintf(out,"ForFrame Frame: %d %s %f on %f blobs\n",_Count,_name_, _TimeSum/COUNTNUM,((float)_CountBlob)/COUNTNUM);\ |
|
if(_CountBlob>0)fprintf(out,"ForBlob Frame: %d %s - %f\n",_Count,_name_, _TimeSum/_CountBlob);\ |
|
fclose(out);\ |
|
}\ |
|
_TimeSum = 0;\ |
|
_CountBlob = 0;\ |
|
}\ |
|
} |
|
#else |
|
#define TIME_BEGIN() |
|
#define TIME_END(_name_) |
|
#endif |
|
|
|
/* Special extended blob structure for auto blob tracking: */ |
|
typedef struct CvBlobTrackAuto |
|
{ |
|
CvBlob blob; |
|
int BadFrames; |
|
} CvBlobTrackAuto; |
|
|
|
class CvBlobTrackerAuto1: public CvBlobTrackerAuto |
|
{ |
|
public: |
|
CvBlobTrackerAuto1(CvBlobTrackerAutoParam1* param); |
|
~CvBlobTrackerAuto1(); |
|
CvBlob* GetBlob(int index){return m_BlobList.GetBlob(index);}; |
|
CvBlob* GetBlobByID(int ID){return m_BlobList.GetBlobByID(ID);}; |
|
int GetBlobNum(){return m_BlobList.GetBlobNum();}; |
|
virtual IplImage* GetFGMask(){return m_pFGMask;}; |
|
float GetState(int BlobID){return m_pBTA?m_pBTA->GetState(BlobID):0;}; |
|
const char* GetStateDesc(int BlobID){return m_pBTA?m_pBTA->GetStateDesc(BlobID):NULL;}; |
|
/* Return 0 if trajectory is normal; |
|
return >0 if trajectory abnormal. */ |
|
void Process(IplImage* pImg, IplImage* pMask = NULL); |
|
void Release(){delete this;}; |
|
|
|
private: |
|
IplImage* m_pFGMask; |
|
int m_FGTrainFrames; |
|
CvFGDetector* m_pFG; /* Pointer to foreground mask detector module. */ |
|
CvBlobTracker* m_pBT; /* Pointer to Blob tracker module. */ |
|
int m_BTDel; |
|
int m_BTReal; |
|
CvBlobDetector* m_pBD; /* Pointer to Blob detector module. */ |
|
int m_BDDel; |
|
CvBlobTrackGen* m_pBTGen; |
|
CvBlobTrackPostProc* m_pBTPostProc; |
|
int m_UsePPData; |
|
CvBlobTrackAnalysis* m_pBTA; /* Blob trajectory analyser. */ |
|
CvBlobSeq m_BlobList; |
|
int m_FrameCount; |
|
int m_NextBlobID; |
|
const char* m_TimesFile; |
|
|
|
public: |
|
virtual void SaveState(CvFileStorage* fs) |
|
{ |
|
cvWriteInt(fs,"FrameCount",m_FrameCount); |
|
cvWriteInt(fs,"NextBlobID",m_NextBlobID); |
|
m_BlobList.Write(fs,"BlobList"); |
|
}; |
|
|
|
virtual void LoadState(CvFileStorage* fs, CvFileNode* node) |
|
{ |
|
CvFileNode* BlobListNode = cvGetFileNodeByName(fs,node,"BlobList"); |
|
m_FrameCount = cvReadIntByName(fs,node, "FrameCount", m_FrameCount); |
|
m_NextBlobID = cvReadIntByName(fs,node, "NextBlobID", m_NextBlobID); |
|
if(BlobListNode) |
|
{ |
|
m_BlobList.Load(fs,BlobListNode); |
|
} |
|
}; |
|
}; |
|
|
|
/* Auto Blob tracker creater (sole interface function for this file) */ |
|
CvBlobTrackerAuto* cvCreateBlobTrackerAuto1(CvBlobTrackerAutoParam1* param) |
|
{ |
|
return (CvBlobTrackerAuto*)new CvBlobTrackerAuto1(param); |
|
} |
|
|
|
/* Constructor of auto blob tracker: */ |
|
CvBlobTrackerAuto1::CvBlobTrackerAuto1(CvBlobTrackerAutoParam1* param):m_BlobList(sizeof(CvBlobTrackAuto)) |
|
{ |
|
m_BlobList.AddFormat("i"); |
|
m_TimesFile = NULL; |
|
AddParam("TimesFile",&m_TimesFile); |
|
|
|
m_NextBlobID = 0; |
|
m_pFGMask = NULL; |
|
m_FrameCount = 0; |
|
|
|
m_FGTrainFrames = param?param->FGTrainFrames:0; |
|
m_pFG = param?param->pFG:0; |
|
|
|
m_BDDel = 0; |
|
m_pBD = param?param->pBD:NULL; |
|
m_BTDel = 0; |
|
m_pBT = param?param->pBT:NULL;; |
|
m_BTReal = m_pBT?m_pBT->IsModuleName("BlobTrackerReal"):0; |
|
|
|
m_pBTGen = param?param->pBTGen:NULL; |
|
|
|
m_pBTA = param?param->pBTA:NULL; |
|
|
|
m_pBTPostProc = param?param->pBTPP:NULL; |
|
m_UsePPData = param?param->UsePPData:0; |
|
|
|
/* Create default submodules: */ |
|
if(m_pBD==NULL) |
|
{ |
|
m_pBD = cvCreateBlobDetectorSimple(); |
|
m_BDDel = 1; |
|
} |
|
|
|
if(m_pBT==NULL) |
|
{ |
|
m_pBT = cvCreateBlobTrackerMS(); |
|
m_BTDel = 1; |
|
} |
|
|
|
SetModuleName("Auto1"); |
|
|
|
} /* CvBlobTrackerAuto1::CvBlobTrackerAuto1 */ |
|
|
|
/* Destructor for auto blob tracker: */ |
|
CvBlobTrackerAuto1::~CvBlobTrackerAuto1() |
|
{ |
|
if(m_BDDel)m_pBD->Release(); |
|
if(m_BTDel)m_pBT->Release(); |
|
} |
|
|
|
void CvBlobTrackerAuto1::Process(IplImage* pImg, IplImage* pMask) |
|
{ |
|
int CurBlobNum = 0; |
|
int i; |
|
IplImage* pFG = pMask; |
|
|
|
/* Bump frame counter: */ |
|
m_FrameCount++; |
|
|
|
if(m_TimesFile) |
|
{ |
|
static int64 TickCount = cvGetTickCount(); |
|
static double TimeSum = 0; |
|
static int Count = 0; |
|
Count++; |
|
|
|
if(Count%100==0) |
|
{ |
|
#ifndef WINCE |
|
time_t ltime; |
|
time( <ime ); |
|
char* stime = ctime( <ime ); |
|
#else |
|
/* WINCE does not have above POSIX functions (time,ctime) */ |
|
const char* stime = " wince "; |
|
#endif |
|
FILE* out = fopen(m_TimesFile,"at"); |
|
double Time; |
|
TickCount = cvGetTickCount()-TickCount; |
|
Time = TickCount/FREQ; |
|
if(out){fprintf(out,"- %sFrame: %d ALL_TIME - %f\n",stime,Count,Time/1000);fclose(out);} |
|
|
|
TimeSum = 0; |
|
TickCount = cvGetTickCount(); |
|
} |
|
} |
|
|
|
/* Update BG model: */ |
|
TIME_BEGIN() |
|
|
|
if(m_pFG) |
|
{ /* If FG detector is needed: */ |
|
m_pFG->Process(pImg); |
|
pFG = m_pFG->GetMask(); |
|
} /* If FG detector is needed. */ |
|
|
|
TIME_END("FGDetector",-1) |
|
|
|
m_pFGMask = pFG; /* For external use. */ |
|
|
|
/*if(m_pFG && m_pFG->GetParam("DebugWnd") == 1) |
|
{// debug foreground result |
|
IplImage *pFG = m_pFG->GetMask(); |
|
if(pFG) |
|
{ |
|
cvNamedWindow("FG",0); |
|
cvShowImage("FG", pFG); |
|
} |
|
}*/ |
|
|
|
/* Track blobs: */ |
|
TIME_BEGIN() |
|
if(m_pBT) |
|
{ |
|
int i; |
|
m_pBT->Process(pImg, pFG); |
|
|
|
for(i=m_BlobList.GetBlobNum(); i>0; --i) |
|
{ /* Update data of tracked blob list: */ |
|
CvBlob* pB = m_BlobList.GetBlob(i-1); |
|
int BlobID = CV_BLOB_ID(pB); |
|
int i = m_pBT->GetBlobIndexByID(BlobID); |
|
m_pBT->ProcessBlob(i, pB, pImg, pFG); |
|
pB->ID = BlobID; |
|
} |
|
CurBlobNum = m_pBT->GetBlobNum(); |
|
} |
|
TIME_END("BlobTracker",CurBlobNum) |
|
|
|
/* This part should be removed: */ |
|
if(m_BTReal && m_pBT) |
|
{ /* Update blob list (detect new blob for real blob tracker): */ |
|
int i; |
|
|
|
for(i=m_pBT->GetBlobNum(); i>0; --i) |
|
{ /* Update data of tracked blob list: */ |
|
CvBlob* pB = m_pBT->GetBlob(i-1); |
|
if(pB && m_BlobList.GetBlobByID(CV_BLOB_ID(pB)) == NULL ) |
|
{ |
|
CvBlobTrackAuto NewB; |
|
NewB.blob = pB[0]; |
|
NewB.BadFrames = 0; |
|
m_BlobList.AddBlob((CvBlob*)&NewB); |
|
} |
|
} /* Next blob. */ |
|
|
|
/* Delete blobs: */ |
|
for(i=m_BlobList.GetBlobNum(); i>0; --i) |
|
{ /* Update tracked-blob list: */ |
|
CvBlob* pB = m_BlobList.GetBlob(i-1); |
|
if(pB && m_pBT->GetBlobByID(CV_BLOB_ID(pB)) == NULL ) |
|
{ |
|
m_BlobList.DelBlob(i-1); |
|
} |
|
} /* Next blob. */ |
|
} /* Update bloblist. */ |
|
|
|
|
|
TIME_BEGIN() |
|
if(m_pBTPostProc) |
|
{ /* Post-processing module: */ |
|
int i; |
|
for(i=m_BlobList.GetBlobNum(); i>0; --i) |
|
{ /* Update tracked-blob list: */ |
|
CvBlob* pB = m_BlobList.GetBlob(i-1); |
|
m_pBTPostProc->AddBlob(pB); |
|
} |
|
m_pBTPostProc->Process(); |
|
|
|
for(i=m_BlobList.GetBlobNum(); i>0; --i) |
|
{ /* Update tracked-blob list: */ |
|
CvBlob* pB = m_BlobList.GetBlob(i-1); |
|
int BlobID = CV_BLOB_ID(pB); |
|
CvBlob* pBN = m_pBTPostProc->GetBlobByID(BlobID); |
|
|
|
if(pBN && m_UsePPData && pBN->w >= CV_BLOB_MINW && pBN->h >= CV_BLOB_MINH) |
|
{ /* Set new data for tracker: */ |
|
m_pBT->SetBlobByID(BlobID, pBN ); |
|
} |
|
|
|
if(pBN) |
|
{ /* Update blob list with results from postprocessing: */ |
|
pB[0] = pBN[0]; |
|
} |
|
} |
|
} /* Post-processing module. */ |
|
|
|
TIME_END("PostProcessing",CurBlobNum) |
|
|
|
/* Blob deleter (experimental and simple): */ |
|
TIME_BEGIN() |
|
if(pFG) |
|
{ /* Blob deleter: */ |
|
int i; |
|
if(!m_BTReal)for(i=m_BlobList.GetBlobNum();i>0;--i) |
|
{ /* Check all blobs on list: */ |
|
CvBlobTrackAuto* pB = (CvBlobTrackAuto*)(m_BlobList.GetBlob(i-1)); |
|
int Good = 0; |
|
int w=pFG->width; |
|
int h=pFG->height; |
|
CvRect r = CV_BLOB_RECT(pB); |
|
CvMat mat; |
|
double aver = 0; |
|
double area = CV_BLOB_WX(pB)*CV_BLOB_WY(pB); |
|
if(r.x < 0){r.width += r.x;r.x = 0;} |
|
if(r.y < 0){r.height += r.y;r.y = 0;} |
|
if(r.x+r.width>=w){r.width = w-r.x-1;} |
|
if(r.y+r.height>=h){r.height = h-r.y-1;} |
|
|
|
if(r.width > 4 && r.height > 4 && r.x < w && r.y < h && |
|
r.x >=0 && r.y >=0 && |
|
r.x+r.width < w && r.y+r.height < h && area > 0) |
|
{ |
|
aver = cvSum(cvGetSubRect(pFG,&mat,r)).val[0] / area; |
|
/* if mask in blob area exists then its blob OK*/ |
|
if(aver > 0.1*255)Good = 1; |
|
} |
|
else |
|
{ |
|
pB->BadFrames+=2; |
|
} |
|
|
|
if(Good) |
|
{ |
|
pB->BadFrames = 0; |
|
} |
|
else |
|
{ |
|
pB->BadFrames++; |
|
} |
|
} /* Next blob: */ |
|
|
|
/* Check error count: */ |
|
for(i=0; i<m_BlobList.GetBlobNum(); ++i) |
|
{ |
|
CvBlobTrackAuto* pB = (CvBlobTrackAuto*)m_BlobList.GetBlob(i); |
|
|
|
if(pB->BadFrames>3) |
|
{ /* Delete such objects */ |
|
/* from tracker... */ |
|
m_pBT->DelBlobByID(CV_BLOB_ID(pB)); |
|
|
|
/* ... and from local list: */ |
|
m_BlobList.DelBlob(i); |
|
i--; |
|
} |
|
} /* Check error count for next blob. */ |
|
} /* Blob deleter. */ |
|
|
|
TIME_END("BlobDeleter",m_BlobList.GetBlobNum()) |
|
|
|
/* Update blobs: */ |
|
TIME_BEGIN() |
|
if(m_pBT) |
|
m_pBT->Update(pImg, pFG); |
|
TIME_END("BlobTrackerUpdate",CurBlobNum) |
|
|
|
/* Detect new blob: */ |
|
TIME_BEGIN() |
|
if(!m_BTReal && m_pBD && pFG && (m_FrameCount > m_FGTrainFrames) ) |
|
{ /* Detect new blob: */ |
|
static CvBlobSeq NewBlobList; |
|
CvBlobTrackAuto NewB; |
|
|
|
NewBlobList.Clear(); |
|
|
|
if(m_pBD->DetectNewBlob(pImg, pFG, &NewBlobList, &m_BlobList)) |
|
{ /* Add new blob to tracker and blob list: */ |
|
int i; |
|
IplImage* pMask = pFG; |
|
|
|
/*if(0)if(NewBlobList.GetBlobNum()>0 && pFG ) |
|
{// erode FG mask (only for FG_0 and MS1||MS2) |
|
pMask = cvCloneImage(pFG); |
|
cvErode(pFG,pMask,NULL,2); |
|
}*/ |
|
|
|
for(i=0; i<NewBlobList.GetBlobNum(); ++i) |
|
{ |
|
CvBlob* pBN = NewBlobList.GetBlob(i); |
|
pBN->ID = m_NextBlobID; |
|
|
|
if(pBN && pBN->w >= CV_BLOB_MINW && pBN->h >= CV_BLOB_MINH) |
|
{ |
|
CvBlob* pB = m_pBT->AddBlob(pBN, pImg, pMask ); |
|
if(pB) |
|
{ |
|
NewB.blob = pB[0]; |
|
NewB.BadFrames = 0; |
|
m_BlobList.AddBlob((CvBlob*)&NewB); |
|
m_NextBlobID++; |
|
} |
|
} |
|
} /* Add next blob from list of detected blob. */ |
|
|
|
if(pMask != pFG) cvReleaseImage(&pMask); |
|
|
|
} /* Create and add new blobs and trackers. */ |
|
|
|
} /* Detect new blob. */ |
|
|
|
TIME_END("BlobDetector",-1) |
|
|
|
TIME_BEGIN() |
|
if(m_pBTGen) |
|
{ /* Run track generator: */ |
|
for(i=m_BlobList.GetBlobNum(); i>0; --i) |
|
{ /* Update data of tracked blob list: */ |
|
CvBlob* pB = m_BlobList.GetBlob(i-1); |
|
m_pBTGen->AddBlob(pB); |
|
} |
|
m_pBTGen->Process(pImg, pFG); |
|
} /* Run track generator: */ |
|
TIME_END("TrajectoryGeneration",-1) |
|
|
|
TIME_BEGIN() |
|
if(m_pBTA) |
|
{ /* Trajectory analysis module: */ |
|
int i; |
|
for(i=m_BlobList.GetBlobNum(); i>0; i--) |
|
m_pBTA->AddBlob(m_BlobList.GetBlob(i-1)); |
|
|
|
m_pBTA->Process(pImg, pFG); |
|
|
|
} /* Trajectory analysis module. */ |
|
|
|
TIME_END("TrackAnalysis",m_BlobList.GetBlobNum()) |
|
|
|
} /* CvBlobTrackerAuto1::Process */ |
|
|
|
|