Update to 2.0.0 tree from current Fremantle build
[opencv] / src / cvaux / vs / blobtrackingcc.cpp
diff --git a/src/cvaux/vs/blobtrackingcc.cpp b/src/cvaux/vs/blobtrackingcc.cpp
new file mode 100644 (file)
index 0000000..8dd36de
--- /dev/null
@@ -0,0 +1,556 @@
+/*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 "_cvaux.h"
+
+static float CalcAverageMask(CvBlob* pBlob, IplImage* pImgFG )
+{   /* Calculate sum of mask: */
+    double  Area, Aver = 0;
+    CvRect  r;
+    CvMat   mat;
+
+    if(pImgFG==NULL) return 0;
+
+    r.x = cvRound(pBlob->x - pBlob->w*0.5);
+    r.y = cvRound(pBlob->y - pBlob->h*0.5);
+    r.width = cvRound(pBlob->w);
+    r.height = cvRound(pBlob->h);
+    Area = r.width*r.height;
+    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)>=pImgFG->width){r.width=pImgFG->width-r.x-1;}
+    if((r.y+r.height)>=pImgFG->height){r.height=pImgFG->height-r.y-1;}
+
+    if(r.width>0 && r.height>0)
+    {
+        double Sum = cvSum(cvGetSubRect(pImgFG,&mat,r)).val[0]/255.0;
+        assert(Area>0);
+        Aver = Sum/Area;
+    }
+    return (float)Aver;
+}   /* Calculate sum of mask. */
+
+
+/*============== BLOB TRACKERCC CLASS DECLARATION =============== */
+typedef struct DefBlobTracker
+{
+    CvBlob                      blob;
+    CvBlobTrackPredictor*       pPredictor;
+    CvBlob                      BlobPredict;
+    int                         Collision;
+    CvBlobSeq*                  pBlobHyp;
+    float                       AverFG;
+} DefBlobTracker;
+
+void cvFindBlobsByCCClasters(IplImage* pFG, CvBlobSeq* pBlobs, CvMemStorage* storage);
+
+class CvBlobTrackerCC : public CvBlobTracker
+{
+private:
+    float           m_AlphaSize;
+    float           m_AlphaPos;
+    float           m_Alpha;
+    int             m_Collision;
+    int             m_ConfidenceType;
+    const char*           m_ConfidenceTypeStr;
+    CvBlobSeq       m_BlobList;
+    CvBlobSeq       m_BlobListNew;
+//  int             m_LastID;
+    CvMemStorage*   m_pMem;
+    int             m_ClearHyp;
+    IplImage*       m_pImg;
+    IplImage*       m_pImgFG;
+public:
+    CvBlobTrackerCC():m_BlobList(sizeof(DefBlobTracker))
+    {
+//      m_LastID = 0;
+        m_ClearHyp = 0;
+        m_pMem = cvCreateMemStorage();
+        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_AlphaSize = 0.02f;
+        AddParam("AlphaSize",&m_AlphaSize);
+        CommentParam("AlphaSize", "Size update speed (0..1)");
+
+        m_AlphaPos = 1.0f;
+        AddParam("AlphaPos",&m_AlphaPos);
+        CommentParam("AlphaPos", "Position update speed (0..1)");
+
+        m_Alpha = 0.001f;
+        AddParam("Alpha", &m_Alpha);
+        CommentParam("Alpha","Coefficient for model histogram updating (0 - hist is not updated)");
+
+        m_ConfidenceType=0;
+        m_ConfidenceTypeStr = "NearestBlob";
+        AddParam("ConfidenceType", &m_ConfidenceTypeStr);
+        CommentParam("ConfidenceType","Type of calculated Confidence (NearestBlob, AverFG, BC)");
+
+        SetModuleName("CC");
+    };
+
+    ~CvBlobTrackerCC()
+    {
+        if(m_pMem)cvReleaseMemStorage(&m_pMem);
+    };
+
+    /* Blob functions: */
+    virtual int     GetBlobNum() {return m_BlobList.GetBlobNum();};
+    virtual CvBlob* GetBlob(int BlobIndex){return m_BlobList.GetBlob(BlobIndex);};
+    virtual void    SetBlob(int BlobIndex, CvBlob* pBlob)
+    {
+        CvBlob* pB = m_BlobList.GetBlob(BlobIndex);
+        if(pB) pB[0] = pBlob[0];
+    };
+
+    virtual CvBlob* GetBlobByID(int BlobID){return m_BlobList.GetBlobByID(BlobID);};
+    virtual void    DelBlob(int BlobIndex)
+    {
+        DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
+        if(pBT==NULL) return;
+        if(pBT->pPredictor)
+        {
+            pBT->pPredictor->Release();
+        }
+        else
+        {
+            printf("WARNING!!! Invalid Predictor in CC tracker");
+        }
+        delete pBT->pBlobHyp;
+        m_BlobList.DelBlob(BlobIndex);
+    };
+#if 0
+    virtual void    DelBlobByID(int BlobID)
+    {
+        DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlobByID(BlobID);
+        pBT->pPredictor->Release();
+        delete pBT->pBlobHyp;
+        m_BlobList.DelBlobByID(BlobID);
+    };
+#endif
+    virtual void    Release(){delete this;};
+
+    /* Add new blob to track it and assign to this blob personal ID */
+    /* pBlob - pinter to structure with blob parameters (ID is ignored)*/
+    /* pImg - current image */
+    /* pImgFG - current foreground mask */
+    /* return pointer to new added blob */
+    virtual CvBlob* AddBlob(CvBlob* pB, IplImage* /*pImg*/, IplImage* pImgFG = NULL )
+    {
+        assert(pImgFG); /* This tracker uses only foreground mask. */
+        DefBlobTracker NewB;
+        NewB.blob = pB[0];
+//        CV_BLOB_ID(&NewB) = m_LastID;
+        NewB.pBlobHyp = new CvBlobSeq;
+        NewB.pPredictor = cvCreateModuleBlobTrackPredictKalman(); /* Module for position prediction. */
+        NewB.pPredictor->Update(pB);
+        NewB.AverFG = pImgFG?CalcAverageMask(pB,pImgFG):0;
+        m_BlobList.AddBlob((CvBlob*)&NewB);
+        return m_BlobList.GetBlob(m_BlobList.GetBlobNum()-1);
+    };
+
+    virtual void    Process(IplImage* pImg, IplImage* pImgFG = NULL)
+    {
+        CvSeq*      cnts;
+        CvSeq*      cnt;
+        int i;
+
+        m_pImg = pImg;
+        m_pImgFG = pImgFG;
+
+        if(m_BlobList.GetBlobNum() <= 0 ) return;
+
+        /* Clear bloblist for new blobs: */
+        m_BlobListNew.Clear();
+
+        assert(m_pMem);
+        cvClearMemStorage(m_pMem);
+        assert(pImgFG);
+
+
+        /* Find CC: */
+#if 0
+        {   // By contour clustering:
+            cvFindBlobsByCCClasters(pImgFG, &m_BlobListNew, m_pMem);
+        }
+#else
+        {   /* One contour - one blob: */
+            IplImage* pBin = cvCloneImage(pImgFG);
+            assert(pBin);
+            cvThreshold(pBin,pBin,128,255,CV_THRESH_BINARY);
+            cvFindContours(pBin, m_pMem, &cnts, sizeof(CvContour), CV_RETR_EXTERNAL);
+
+            /* Process each contour: */
+            for(cnt = cnts; cnt; cnt=cnt->h_next)
+            {
+                CvBlob  NewBlob;
+
+                /* Image moments: */
+                double      M00,X,Y,XX,YY;
+                CvMoments   m;
+                CvRect      r = ((CvContour*)cnt)->rect;
+                CvMat       mat;
+                if(r.height < 3 || r.width < 3) continue;
+                cvMoments( cvGetSubRect(pImgFG,&mat,r), &m, 0 );
+                M00 = cvGetSpatialMoment( &m, 0, 0 );
+                if(M00 <= 0 ) continue;
+                X = cvGetSpatialMoment( &m, 1, 0 )/M00;
+                Y = cvGetSpatialMoment( &m, 0, 1 )/M00;
+                XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X;
+                YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y;
+                NewBlob = cvBlob(r.x+(float)X,r.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY)));
+                m_BlobListNew.AddBlob(&NewBlob);
+            }   /* Next contour. */
+
+            cvReleaseImage(&pBin);
+        }
+#endif
+        for(i=m_BlobList.GetBlobNum(); i>0; --i)
+        {   /* Predict new blob position: */
+            CvBlob*         pB=NULL;
+            DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(i-1);
+
+            /* Update predictor by previous value of blob: */
+            pBT->pPredictor->Update(&(pBT->blob));
+
+            /* Predict current position: */
+            pB = pBT->pPredictor->Predict();
+
+            if(pB)
+            {
+                pBT->BlobPredict = pB[0];
+            }
+            else
+            {
+                pBT->BlobPredict = pBT->blob;
+            }
+        }   /* Predict new blob position. */
+
+        if(m_Collision)
+        for(i=m_BlobList.GetBlobNum(); i>0; --i)
+        {   /* Predict collision. */
+            int             Collision = 0;
+            int             j;
+            DefBlobTracker* pF = (DefBlobTracker*)m_BlobList.GetBlob(i-1);
+
+            for(j=m_BlobList.GetBlobNum(); j>0; --j)
+            {   /* Predict collision: */
+                CvBlob* pB1;
+                CvBlob* pB2;
+                DefBlobTracker* pF2 = (DefBlobTracker*)m_BlobList.GetBlob(j-1);
+                if(i==j) continue;
+                pB1 = &pF->BlobPredict;
+                pB2 = &pF2->BlobPredict;
+
+                if( fabs(pB1->x-pB2->x)<0.6*(pB1->w+pB2->w) &&
+                    fabs(pB1->y-pB2->y)<0.6*(pB1->h+pB2->h) ) Collision = 1;
+
+                pB1 = &pF->blob;
+                pB2 = &pF2->blob;
+
+                if( fabs(pB1->x-pB2->x)<0.6*(pB1->w+pB2->w) &&
+                    fabs(pB1->y-pB2->y)<0.6*(pB1->h+pB2->h) ) Collision = 1;
+
+                if(Collision) break;
+
+            }   /* Check next blob to cross current. */
+
+            pF->Collision = Collision;
+
+        }   /* Predict collision. */
+
+        for(i=m_BlobList.GetBlobNum(); i>0; --i)
+        {   /* Find a neighbour on current frame
+             * for each blob from previous frame:
+             */
+            CvBlob*         pB = m_BlobList.GetBlob(i-1);
+            DefBlobTracker* pBT = (DefBlobTracker*)pB;
+            //int             BlobID = CV_BLOB_ID(pB);
+            //CvBlob*         pBBest = NULL;
+            //double          DistBest = -1;
+            //int j;
+
+            if(pBT->pBlobHyp->GetBlobNum()>0)
+            {   /* Track all hypotheses: */
+                int h,hN = pBT->pBlobHyp->GetBlobNum();
+                for(h=0; h<hN; ++h)
+                {
+                    int         j, jN = m_BlobListNew.GetBlobNum();
+                    CvBlob*     pB = pBT->pBlobHyp->GetBlob(h);
+                    int         BlobID = CV_BLOB_ID(pB);
+                    CvBlob*     pBBest = NULL;
+                    double      DistBest = -1;
+                    for(j=0; j<jN; j++)
+                    {   /* Find best CC: */
+                        double  Dist = -1;
+                        CvBlob* pBNew = m_BlobListNew.GetBlob(j);
+                        double  dx = fabs(CV_BLOB_X(pB)-CV_BLOB_X(pBNew));
+                        double  dy = fabs(CV_BLOB_Y(pB)-CV_BLOB_Y(pBNew));
+                        if(dx > 2*CV_BLOB_WX(pB) || dy > 2*CV_BLOB_WY(pB)) continue;
+
+                        Dist = sqrt(dx*dx+dy*dy);
+                        if(Dist < DistBest || pBBest == NULL)
+                        {
+                            DistBest = Dist;
+                            pBBest = pBNew;
+                        }
+                    }   /* Find best CC. */
+
+                    if(pBBest)
+                    {
+                        pB[0] = pBBest[0];
+                        CV_BLOB_ID(pB) = BlobID;
+                    }
+                    else
+                    {   /* Delete this hypothesis. */
+                        pBT->pBlobHyp->DelBlob(h);
+                        h--;
+                        hN--;
+                    }
+                }   /* Next hypothysis. */
+            }   /*  Track all hypotheses. */
+        }   /*  Track next blob. */
+
+        m_ClearHyp = 1;
+
+    } /* Process. */
+
+    virtual void ProcessBlob(int BlobIndex, CvBlob* pBlob, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL)
+    {
+        int             ID = pBlob->ID;
+        CvBlob*         pB = m_BlobList.GetBlob(BlobIndex);
+        DefBlobTracker* pBT = (DefBlobTracker*)pB;
+        //CvBlob*         pBBest = NULL;
+        //double          DistBest = -1;
+        int             BlobID;
+
+        if(pB==NULL) return;
+
+        BlobID = pB->ID;
+
+        if(m_Collision && pBT->Collision)
+        {   /* Tracking in collision: */
+            pB[0]=pBT->BlobPredict;
+            CV_BLOB_ID(pB)=BlobID;
+        }   /* Tracking in collision. */
+        else
+        {   /* Non-collision tracking: */
+            CvBlob* pBBest = GetNearestBlob(pB);
+            if(pBBest)
+            {
+                float   w = pBlob->w*(1-m_AlphaSize)+m_AlphaSize*pBBest->w;
+                float   h = pBlob->h*(1-m_AlphaSize)+m_AlphaSize*pBBest->h;
+                float   x = pBlob->x*(1-m_AlphaPos)+m_AlphaPos*pBBest->x;
+                float   y = pBlob->y*(1-m_AlphaPos)+m_AlphaPos*pBBest->y;
+                pB->w = w;
+                pB->h = h;
+                pB->x = x;
+                pB->y = y;
+                CV_BLOB_ID(pB) = BlobID;
+            }
+        }   /* Non-collision tracking. */
+
+        pBlob[0] = pB[0];
+        pBlob->ID = ID;
+    };
+
+    virtual double  GetConfidence(int BlobIndex, CvBlob* pBlob, IplImage* /*pImg*/, IplImage* pImgFG = NULL)
+    {
+        /* Define coefficients in exp by exp(-XT*K)=VT: */
+        static double _KS = -log(0.1)/pow(0.5,2); /* XT = 1, VT = 0.1 - when size is Larger in 2 times Confidence is smoller in 10 times */
+        static double _KP = -log(0.1)/pow(m_pImg->width*0.02,2); /* XT = 0.02*ImgWidth, VT = 0.1*/
+        DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
+        float   dx,dy,dw,dh;
+        float   dp2,ds2;
+        double  W = 1;
+        CvBlob* pBC = GetNearestBlob(pBlob);
+        if(pBC == NULL ) return 0;
+
+        dx = pBC->x-pBlob->x;
+        dy = pBC->y-pBlob->y;
+        dw = (pBC->w-pBlob->w)/pBC->w;
+        dh = (pBC->h-pBlob->h)/pBC->h;
+
+        dp2 = dx*dx+dy*dy;
+        ds2 = dw*dw+dh*dh;
+
+        if(!pBT->Collision)
+        {   /* Confidence for size by nearest blob: */
+            W*=exp(-_KS*ds2);
+        }
+
+        if(m_ConfidenceType==0 && !pBT->Collision)
+        {   /* Confidence by nearest blob: */
+            W*=exp(-_KP*dp2);
+        }
+
+        if(m_ConfidenceType==1 && pBT->AverFG>0)
+        {   /* Calculate sum of mask: */
+            float   Aver = CalcAverageMask(pBlob, pImgFG );
+            if(Aver < pBT->AverFG)
+            {
+                float diff = 1+0.9f*(Aver-pBT->AverFG)/pBT->AverFG;
+                if(diff < 0.1f) diff = 0.1f;
+                W *= diff;
+            }
+        }   /* Calculate sum of mask. */
+
+        if(m_ConfidenceType==2)
+        {   /* Calculate BCoeff: */
+            float   S = 0.2f;
+            float   Aver = CalcAverageMask(pBlob, pImgFG );
+            double B = sqrt(Aver*pBT->AverFG)+sqrt((1-Aver)*(1-pBT->AverFG));
+
+            W *= exp((B-1)/(2*S));
+        }   /* Calculate sum of mask. */
+
+        return W;
+    };
+
+    virtual void UpdateBlob(int BlobIndex, CvBlob* /*pBlob*/, IplImage* /*pImg*/, IplImage* pImgFG = NULL)
+    {
+        DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
+
+        if(pImgFG==NULL || pBT==NULL) return;
+
+        if(!pBT->Collision)
+        {
+        //pBT->AverFG = pBT->AverFG * (1-m_Alpha) + m_Alpha * CalcAverageMask(pBlob,pImgFG);
+        }
+    };
+
+    virtual void ParamUpdate()
+    {
+        const char*   pCT[3] = {"NearestBlob","AverFG","BC"};
+        int     i;
+
+        CvBlobTracker::ParamUpdate();
+
+        for(i=0; i<3; ++i)
+        {
+            if(cv_stricmp(m_ConfidenceTypeStr,pCT[i])==0)
+            {
+                m_ConfidenceType = i;
+            }
+        }
+        SetParamStr("ConfidenceType",pCT[m_ConfidenceType]);
+    }
+
+    /* ===============  MULTI HYPOTHESIS INTERFACE ================== */
+    /* Return number of position hypotheses of currently tracked blob: */
+    virtual int     GetBlobHypNum(int BlobIdx)
+    {
+        DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIdx);
+        assert(pBT->pBlobHyp);
+        return pBT->pBlobHyp->GetBlobNum();
+    };  /* CvBlobtrackerList::GetBlobHypNum() */
+
+    /* Return pointer to specified blob hypothesis by index blob: */
+    virtual CvBlob* GetBlobHyp(int BlobIndex, int hypothesis)
+    {
+        DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
+        assert(pBT->pBlobHyp);
+        return pBT->pBlobHyp->GetBlob(hypothesis);
+    };  /* CvBlobtrackerList::GetBlobHyp() */
+
+    /* Set new parameters for specified (by index) blob hypothesis
+     * (can be called several times for each hypothesis):
+     */
+    virtual void    SetBlobHyp(int BlobIndex, CvBlob* pBlob)
+    {
+        if(m_ClearHyp)
+        {   /* Clear all hypotheses: */
+            int b, bN = m_BlobList.GetBlobNum();
+            for(b=0; b<bN; ++b)
+            {
+                DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(b);
+                assert(pBT->pBlobHyp);
+                pBT->pBlobHyp->Clear();
+            }
+            m_ClearHyp = 0;
+        }
+        {   /* Add hypothesis: */
+            DefBlobTracker* pBT = (DefBlobTracker*)m_BlobList.GetBlob(BlobIndex);
+            assert(pBT->pBlobHyp);
+            pBT->pBlobHyp->AddBlob(pBlob);
+        }
+    };
+
+private:
+    CvBlob* GetNearestBlob(CvBlob* pB)
+    {
+        //DefBlobTracker* pBT = (DefBlobTracker*)pB;
+        CvBlob*         pBBest = NULL;
+        double          DistBest = -1;
+        int             j,BlobID;
+
+        if(pB==NULL) return NULL;
+
+        BlobID = pB->ID;
+
+        for(j=m_BlobListNew.GetBlobNum(); j>0; --j)
+        {   /* Find best CC: */
+            double  Dist = -1;
+            CvBlob* pBNew = m_BlobListNew.GetBlob(j-1);
+            double  dx = fabs(CV_BLOB_X(pB)-CV_BLOB_X(pBNew));
+            double  dy = fabs(CV_BLOB_Y(pB)-CV_BLOB_Y(pBNew));
+            if(dx > 2*CV_BLOB_WX(pB) || dy > 2*CV_BLOB_WY(pB)) continue;
+
+            Dist = sqrt(dx*dx+dy*dy);
+            if(Dist < DistBest || pBBest == NULL)
+            {
+                DistBest = Dist;
+                pBBest = pBNew;
+            }
+
+        }   /* Find best CC. */
+
+        return pBBest;
+
+    }; /* GetNearestBlob */
+
+};
+
+CvBlobTracker* cvCreateBlobTrackerCC()
+{
+    return (CvBlobTracker*) new CvBlobTrackerCC;
+}
+/*============== BLOB TRACKERCC CLASS DECLARATION =============== */