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.

549 lines
20 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, all 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*/
#include "precomp.hpp"
#define PIX_HIST_BIN_NUM_1 3 //number of bins for classification (not used now)
#define PIX_HIST_BIN_NUM_2 5 //number of bins for statistic collection
#define PIX_HIST_ALPHA 0.01f //alpha-coefficient for running avarage procedure
#define PIX_HIST_DELTA 2 //maximal difference between descriptors(RGB)
#define PIX_HIST_COL_QUANTS 64 //quantization level in rgb-space
#define PIX_HIST_DELTA_IN_PIX_VAL (PIX_HIST_DELTA * 256 / PIX_HIST_COL_QUANTS) //allowed difference in rgb-space
// Structures for background statistics estimation:
typedef struct CvPixHistBin{
float bin_val;
uchar cols[3];
} CvPixHistBin;
typedef struct CvPixHist{
CvPixHistBin bins[PIX_HIST_BIN_NUM_2];
} CvPixHist;
// Class for background statistics estimation:
class CvBGEstimPixHist
{
private:
CvPixHist* m_PixHists;
int m_width;
int m_height;
// Function for update color histogram for one pixel:
void update_hist_elem(int x, int y, uchar* cols )
{
// Find closest bin:
int dist = 0, min_dist = 2147483647, indx = -1;
for( int k = 0; k < PIX_HIST_BIN_NUM_2; k++ ){
uchar* hist_cols = m_PixHists[y*m_width+x].bins[k].cols;
m_PixHists[y*m_width+x].bins[k].bin_val *= (1-PIX_HIST_ALPHA);
int l;
for( l = 0; l < 3; l++ ){
int val = abs( hist_cols[l] - cols[l] );
if( val > PIX_HIST_DELTA_IN_PIX_VAL ) break;
dist += val;
}
if( l == 3 && dist < min_dist ){
min_dist = dist;
indx = k;
}
}
if( indx < 0 ){ // N2th elem in the table is replaced by a new feature.
indx = PIX_HIST_BIN_NUM_2 - 1;
m_PixHists[y*m_width+x].bins[indx].bin_val = PIX_HIST_ALPHA;
for(int l = 0; l < 3; l++ ){
m_PixHists[y*m_width+x].bins[indx].cols[l] = cols[l];
}
}
else {
//add vote!
m_PixHists[y*m_width+x].bins[indx].bin_val += PIX_HIST_ALPHA;
}
// Re-sort bins by BIN_VAL:
{
int k;
for(k = 0; k < indx; k++ ){
if( m_PixHists[y*m_width+x].bins[k].bin_val <= m_PixHists[y*m_width+x].bins[indx].bin_val ){
CvPixHistBin tmp1, tmp2 = m_PixHists[y*m_width+x].bins[indx];
// Shift elements:
for(int l = k; l <= indx; l++ ){
tmp1 = m_PixHists[y*m_width+x].bins[l];
m_PixHists[y*m_width+x].bins[l] = tmp2;
tmp2 = tmp1;
}
break;
}
}
}
} // void update_hist(...)
// Function for calculation difference between histograms:
float get_hist_diff(int x1, int y1, int x2, int y2)
{
float dist = 0;
for( int i = 0; i < 3; i++ ){
dist += labs(m_PixHists[y1*m_width+x1].bins[0].cols[i] -
m_PixHists[y2*m_width+x2].bins[0].cols[i]);
}
return dist;
}
public:
IplImage* bg_image;
CvBGEstimPixHist(CvSize img_size)
{
m_PixHists = (CvPixHist*)cvAlloc(img_size.width*img_size.height*sizeof(CvPixHist));
memset( m_PixHists, 0, img_size.width*img_size.height*sizeof(CvPixHist) );
m_width = img_size.width;
m_height = img_size.height;
bg_image = cvCreateImage(img_size, IPL_DEPTH_8U, 3 );
} /* Constructor. */
~CvBGEstimPixHist()
{
cvReleaseImage(&bg_image);
cvFree(&m_PixHists);
} /* Destructor. */
// Function to update histograms and bg_image:
void update_hists( IplImage* pImg )
{
for( int i = 0; i < pImg->height; i++ ){
for( int j = 0; j < pImg->width; j++ ){
update_hist_elem( j, i, ((uchar*)(pImg->imageData))+i*pImg->widthStep+3*j );
((uchar*)(bg_image->imageData))[i*bg_image->widthStep+3*j] = m_PixHists[i*m_width+j].bins[0].cols[0];
((uchar*)(bg_image->imageData))[i*bg_image->widthStep+3*j+1] = m_PixHists[i*m_width+j].bins[0].cols[1];
((uchar*)(bg_image->imageData))[i*bg_image->widthStep+3*j+2] = m_PixHists[i*m_width+j].bins[0].cols[2];
}
}
// cvNamedWindow("RoadMap2",0);
// cvShowImage("RoadMap2", bg_image);
}
}; /* CvBGEstimPixHist */
/*======================= TRACKER LIST SHELL =====================*/
typedef struct DefBlobTrackerL
{
CvBlob blob;
CvBlobTrackerOne* pTracker;
int Frame;
int Collision;
CvBlobTrackPredictor* pPredictor;
CvBlob BlobPredict;
CvBlobSeq* pBlobHyp;
} DefBlobTrackerL;
class CvBlobTrackerList : public CvBlobTracker
{
private:
CvBlobTrackerOne* (*m_Create)();
CvBlobSeq m_BlobTrackerList;
// int m_LastID;
int m_Collision;
int m_ClearHyp;
float m_BGImageUsing;
CvBGEstimPixHist* m_pBGImage;
IplImage* m_pImgFG;
IplImage* m_pImgReg; /* mask for multiblob confidence calculation */
public:
CvBlobTrackerList(CvBlobTrackerOne* (*create)()):m_BlobTrackerList(sizeof(DefBlobTrackerL))
{
//int i;
CvBlobTrackerOne* pM = create();
// m_LastID = 0;
m_Create = create;
m_ClearHyp = 0;
m_pImgFG = 0;
m_pImgReg = NULL;
TransferParamsFromChild(pM,NULL);
pM->Release();
m_Collision = 1; /* if 1 then collistion will be detected and processed */
AddParam("Collision",&m_Collision);
CommentParam("Collision", "if 1 then collision cases are processed in special way");
m_pBGImage = NULL;
m_BGImageUsing = 50;
AddParam("BGImageUsing", &m_BGImageUsing);
CommentParam("BGImageUsing","Weight of using BG image in update hist model (0 - BG dies not use 1 - use)");
SetModuleName("List");
}
~CvBlobTrackerList()
{
int i;
if(m_pBGImage) delete m_pBGImage;
if(m_pImgFG) cvReleaseImage(&m_pImgFG);
if(m_pImgReg) cvReleaseImage(&m_pImgReg);
for(i=m_BlobTrackerList.GetBlobNum();i>0;--i)
{
m_BlobTrackerList.DelBlob(i-1);
}
};
CvBlob* AddBlob(CvBlob* pBlob, IplImage* pImg, IplImage* pImgFG )
{ /* Create new tracker: */
DefBlobTrackerL F;
F.blob = pBlob[0];
// F.blob.ID = m_LastID++;
F.pTracker = m_Create();
F.pPredictor = cvCreateModuleBlobTrackPredictKalman();
F.pBlobHyp = new CvBlobSeq;
F.Frame = 0;
TransferParamsToChild(F.pTracker,NULL);
F.pTracker->Init(pBlob,pImg, pImgFG);
m_BlobTrackerList.AddBlob((CvBlob*)&F);
return m_BlobTrackerList.GetBlob(m_BlobTrackerList.GetBlobNum()-1);
};
void DelBlob(int BlobIndex)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(BlobIndex);
if(pF == NULL) return;
pF->pTracker->Release();
pF->pPredictor->Release();
delete pF->pBlobHyp;
m_BlobTrackerList.DelBlob(BlobIndex);
}
void DelBlobByID(int BlobID)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlobByID(BlobID);
if(pF == NULL) return;
pF->pTracker->Release();
pF->pPredictor->Release();
delete pF->pBlobHyp;
m_BlobTrackerList.DelBlobByID(BlobID);
}
virtual void Process(IplImage* pImg, IplImage* pImgFG = NULL)
{
int i;
if(pImgFG)
{
if(m_pImgFG) cvCopy(pImgFG,m_pImgFG);
else m_pImgFG = cvCloneImage(pImgFG);
}
if(m_pBGImage==NULL && m_BGImageUsing>0)
{
m_pBGImage = new CvBGEstimPixHist(cvSize(pImg->width,pImg->height));
}
if(m_Collision)
for(i=m_BlobTrackerList.GetBlobNum(); i>0; --i)
{ /* Update predictor: */
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(i-1);
pF->pPredictor->Update((CvBlob*)pF);
} /* Update predictor. */
if(m_pBGImage && m_pImgFG)
{ /* Weighting mask mask: */
int x,y,yN=pImg->height,xN=pImg->width;
IplImage* pImgBG = NULL;
m_pBGImage->update_hists(pImg);
pImgBG = m_pBGImage->bg_image;
for(y=0; y<yN; ++y)
{
unsigned char* pI = (unsigned char*)pImg->imageData + y*pImg->widthStep;
unsigned char* pBG = (unsigned char*)pImgBG->imageData + y*pImgBG->widthStep;
unsigned char* pFG = (unsigned char*)m_pImgFG->imageData +y*m_pImgFG->widthStep;
for(x=0; x<xN; ++x)
{
if(pFG[x])
{
int D1 = (int)(pI[3*x+0])-(int)(pBG[3*x+0]);
int D2 = (int)(pI[3*x+1])-(int)(pBG[3*x+1]);
int D3 = (int)(pI[3*x+2])-(int)(pBG[3*x+2]);
int DD = D1*D1+D2*D2+D3*D3;
double D = sqrt((float)DD);
double DW = 25;
double W = 1/(exp(-4*(D-m_BGImageUsing)/DW)+1);
pFG[x] = (uchar)cvRound(W*255);
}
} /* Next mask pixel. */
} /* Next mask line. */
/*if(m_Wnd)
{
cvNamedWindow("BlobList_FGWeight",0);
cvShowImage("BlobList_FGWeight",m_pImgFG);
}*/
} /* Weighting mask mask. */
for(i=m_BlobTrackerList.GetBlobNum(); i>0; --i)
{ /* Predict position. */
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(i-1);
CvBlob* pB = pF->pPredictor->Predict();
if(pB)
{
pF->BlobPredict = pB[0];
pF->BlobPredict.w = pF->blob.w;
pF->BlobPredict.h = pF->blob.h;
}
} /* Predict position. */
if(m_Collision)
for(i=m_BlobTrackerList.GetBlobNum(); i>0; --i)
{ /* Predict collision. */
int Collision = 0;
int j;
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(i-1);
for(j=m_BlobTrackerList.GetBlobNum(); j>0; --j)
{ /* Predict collision. */
CvBlob* pB1;
CvBlob* pB2;
DefBlobTrackerL* pF2 = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(j-1);
if(i==j) continue;
pB1 = &pF->BlobPredict;
pB2 = &pF2->BlobPredict;
if( fabs(pB1->x-pB2->x)<0.5*(pB1->w+pB2->w) &&
fabs(pB1->y-pB2->y)<0.5*(pB1->h+pB2->h) ) Collision = 1;
pB1 = &pF->blob;
pB2 = &pF2->blob;
if( fabs(pB1->x-pB2->x)<0.5*(pB1->w+pB2->w) &&
fabs(pB1->y-pB2->y)<0.5*(pB1->h+pB2->h) ) Collision = 1;
if(Collision) break;
} /* Check next blob to cross current. */
pF->Collision = Collision;
pF->pTracker->SetCollision(Collision);
} /* Predict collision. */
for(i=m_BlobTrackerList.GetBlobNum(); i>0; --i)
{ /* Track each blob. */
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(i-1);
if(pF->pBlobHyp->GetBlobNum()>0)
{ /* Track all hypothesis. */
int h,hN = pF->pBlobHyp->GetBlobNum();
for(h=0;h<hN;++h)
{
CvBlob* pB = pF->pBlobHyp->GetBlob(h);
CvBlob* pNewBlob = pF->pTracker->Process(pB,pImg,m_pImgFG);
int BlobID = CV_BLOB_ID(pB);
if(pNewBlob)
{
pB[0] = pNewBlob[0];
pB->w = MAX(CV_BLOB_MINW,pNewBlob->w);
pB->h = MAX(CV_BLOB_MINH,pNewBlob->h);
CV_BLOB_ID(pB) = BlobID;
}
} /* Next hypothesis. */
} /* Track all hypotheses. */
pF->Frame++;
} /* Next blob. */
#if 0
for(i=m_BlobTrackerList.GetBlobNum(); i>0; --i)
{ /* Update predictor: */
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(i-1);
if((m_Collision && !pF->Collision) || !m_Collision)
{
pF->pPredictor->Update((CvBlob*)pF);
}
else
{ /* pravilnyp putem idete tovarischy!!! */
pF->pPredictor->Update(&(pF->BlobPredict));
}
} /* Update predictor. */
#endif
m_ClearHyp = 1;
};
/* Process on blob (for multi hypothesis tracing) */
virtual void ProcessBlob(int BlobIndex, CvBlob* pBlob, IplImage* pImg, IplImage* /*pImgFG*/ = NULL)
{
int ID = pBlob->ID;
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(BlobIndex);
CvBlob* pNewBlob = pF->pTracker->Process(pBlob?pBlob:&(pF->blob),pImg,m_pImgFG);
if(pNewBlob)
{
pF->blob = pNewBlob[0];
pF->blob.w = MAX(CV_BLOB_MINW,pNewBlob->w);
pF->blob.h = MAX(CV_BLOB_MINH,pNewBlob->h);
pBlob[0] = pF->blob;
}
pBlob->ID = ID;
};
virtual double GetConfidence(int BlobIndex, CvBlob* pBlob, IplImage* pImg, IplImage* pImgFG = NULL)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(BlobIndex);
if(pF==NULL) return 0;
if(pF->pTracker==NULL) return 0;
return pF->pTracker->GetConfidence(pBlob?pBlob:(&pF->blob), pImg, pImgFG, NULL);
};
virtual double GetConfidenceList(CvBlobSeq* pBlobList, IplImage* pImg, IplImage* pImgFG = NULL)
{
double W = 1;
int b,bN = pBlobList->GetBlobNum();
if(m_pImgReg == NULL)
{
m_pImgReg = cvCreateImage(cvSize(pImg->width,pImg->height),IPL_DEPTH_8U,1);
}
assert(pImg);
cvSet(m_pImgReg,cvScalar(255));
for(b=0; b<bN; ++b)
{
CvBlob* pB = pBlobList->GetBlob(b);
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlobByID(pB->ID);
if(pF==NULL || pF->pTracker==NULL) continue;
W *= pF->pTracker->GetConfidence(pB, pImg, pImgFG, m_pImgReg );
cvEllipse(
m_pImgReg,
cvPoint(cvRound(pB->x*256),cvRound(pB->y*256)), cvSize(cvRound(pB->w*128),cvRound(pB->h*128)),
0, 0, 360,
cvScalar(0), CV_FILLED, 8, 8 );
// cvNamedWindow("REG",0);
// cvShowImage("REG",m_pImgReg);
// cvWaitKey(0);
}
return W;
};
virtual void UpdateBlob(int BlobIndex, CvBlob* pBlob, IplImage* pImg, IplImage* /*pImgFG*/ = NULL)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(BlobIndex);
if(pF)
{
pF->pTracker->Update(pBlob?pBlob:&(pF->blob),pImg,m_pImgFG);
}
};
int GetBlobNum(){return m_BlobTrackerList.GetBlobNum();};
CvBlob* GetBlob(int index){return m_BlobTrackerList.GetBlob(index);};
void SetBlob(int BlobIndex, CvBlob* pBlob)
{
CvBlob* pB = m_BlobTrackerList.GetBlob(BlobIndex);
if(pB)
{
pB[0] = pBlob[0];
pB->w = MAX(CV_BLOB_MINW, pBlob->w);
pB->h = MAX(CV_BLOB_MINH, pBlob->h);
}
}
void Release(){delete this;};
/* Additional functionality: */
CvBlob* GetBlobByID(int BlobID){return m_BlobTrackerList.GetBlobByID(BlobID);}
/* =============== MULTI HYPOTHESIS INTERFACE ================== */
/* Return number of position hypotheses of currently tracked blob: */
virtual int GetBlobHypNum(int BlobIdx)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(BlobIdx);
assert(pF->pBlobHyp);
return pF->pBlobHyp->GetBlobNum();
}; /* CvBlobtrackerList::GetBlobHypNum() */
/* Return pointer to specified blob hypothesis by index blob: */
virtual CvBlob* GetBlobHyp(int BlobIndex, int hypothesis)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(BlobIndex);
assert(pF->pBlobHyp);
return pF->pBlobHyp->GetBlob(hypothesis);
}; /* CvBlobtrackerList::GetBlobHyp() */
/* Set new parameters for specified (by index) blob hyp (can be called several times for each hyp )*/
virtual void SetBlobHyp(int BlobIndex, CvBlob* pBlob)
{
if(m_ClearHyp)
{ /* Clear all hypotheses: */
int b, bN = m_BlobTrackerList.GetBlobNum();
for(b=0; b<bN; ++b)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(b);
assert(pF->pBlobHyp);
pF->pBlobHyp->Clear();
}
m_ClearHyp = 0;
}
{ /* Add hypothesis: */
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(BlobIndex);
assert(pF->pBlobHyp);
pF->pBlobHyp->AddBlob(pBlob);
}
}; /* CvBlobtrackerList::SetBlobHyp */
private:
public:
void ParamUpdate()
{
int i;
for(i=m_BlobTrackerList.GetBlobNum(); i>0; --i)
{
DefBlobTrackerL* pF = (DefBlobTrackerL*)m_BlobTrackerList.GetBlob(i-1);
TransferParamsToChild(pF->pTracker);
pF->pTracker->ParamUpdate();
}
}
}; /* CvBlobTrackerList */
CvBlobTracker* cvCreateBlobTrackerList(CvBlobTrackerOne* (*create)())
{
return (CvBlobTracker*) new CvBlobTrackerList(create);
}