/*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; yimageData + 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; x0; --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;hpBlobHyp->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; bGetBlob(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; bpBlobHyp); 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); }