/*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 SCALE_BASE 1.1 #define SCALE_RANGE 2 #define SCALE_NUM (2*SCALE_RANGE+1) typedef float DefHistType; #define DefHistTypeMat CV_32F #define HIST_INDEX(_pData) (((_pData)[0]>>m_ByteShift) + (((_pData)[1]>>(m_ByteShift))<>m_ByteShift)<<(m_BinBit*2))) static void calcKernelEpanechnikov(CvMat* pK) { /* Allocate kernel for histogramm creation: */ int x,y; int w = pK->width; int h = pK->height; float x0 = 0.5f*(w-1); float y0 = 0.5f*(h-1); for(y=0; y0); assert(h>0); m_ObjSize = cvSize(w,h); m_KernelMeanShiftSize = cvSize(kernel_width,kernel_height); /* Create kernels for histogram calculation: */ if(m_KernelHistModel) cvReleaseMat(&m_KernelHistModel); m_KernelHistModel = cvCreateMat(h, w, DefHistTypeMat); calcKernelEpanechnikov(m_KernelHistModel); if(m_KernelHistCandidate) cvReleaseMat(&m_KernelHistCandidate); m_KernelHistCandidate = cvCreateMat(kernel_height, kernel_width, DefHistTypeMat); calcKernelEpanechnikov(m_KernelHistCandidate); if(m_Weights) cvReleaseMat(&m_Weights); m_Weights = cvCreateMat(kernel_height, kernel_width, CV_32F); for(s=-SCALE_RANGE; s<=SCALE_RANGE; ++s) { /* Allocate kernel for meanshifts in space and scale: */ int si = s+SCALE_RANGE; double cur_sigma = sigma * pow(SCALE_BASE,s); double cur_sigma2 = cur_sigma*cur_sigma; double x0 = 0.5*(kernel_width-1); double y0 = 0.5*(kernel_height-1); if(m_KernelMeanShiftK[si]) cvReleaseMat(&m_KernelMeanShiftK[si]); if(m_KernelMeanShiftG[si]) cvReleaseMat(&m_KernelMeanShiftG[si]); m_KernelMeanShiftK[si] = cvCreateMat(kernel_height, kernel_width, DefHistTypeMat); m_KernelMeanShiftG[si] = cvCreateMat(kernel_height, kernel_width, DefHistTypeMat); for(y=0; ywidth; int h = pKernel->height; DefHistType Volume = 0; int x0 = Center.x - w/2; int y0 = Center.y - h/2; int x,y; //cvZero(pHist); cvSet(pHist,cvScalar(1.0/m_BinNumTotal)); /* no zero bins, all bins have very small value*/ Volume = 1; if(m_Dim == 3) { for(y=0; y=pImg->height) continue; if((y0+y)<0)continue; pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3); pMaskData = pMask?(&CV_IMAGE_ELEM(pMask,unsigned char,y+y0,x0)):NULL; pKernelData = (DefHistType*)CV_MAT_ELEM_PTR_FAST(pKernel[0],y,0,sizeof(DefHistType)); for(x=0; x=pImg->width) continue; if((x0+x)<0)continue; if(pMaskData==NULL || pMaskData[x]>128) { DefHistType K = pKernelData[x]; int index = HIST_INDEX(pImgData); assert(index >= 0 && index < pHist->cols); Volume += K; ((DefHistType*)(pHist->data.ptr))[index] += K; } /* Only masked pixels. */ } /* Next column. */ } /* Next row. */ } /* if m_Dim == 3. */ if(pHistVolume)pHistVolume[0] = Volume; }; /* calcHist */ double calcBhattacharyya() { cvMul(m_HistCandidate,m_HistModel,m_HistTemp); cvPow(m_HistTemp,m_HistTemp,0.5); return cvSum(m_HistTemp).val[0] / sqrt(m_HistCandidateVolume*m_HistModelVolume); } /* calcBhattacharyyaCoefficient */ void calcWeights(IplImage* pImg, IplImage* pImgFG, CvPoint Center) { cvZero(m_Weights); /* Calculate new position: */ if(m_Dim == 3) { int x0 = Center.x - m_KernelMeanShiftSize.width/2; int y0 = Center.y - m_KernelMeanShiftSize.height/2; int x,y; assert(m_Weights->width == m_KernelMeanShiftSize.width); assert(m_Weights->height == m_KernelMeanShiftSize.height); /* Calcualte shift vector: */ for(y=0; y= pImg->height) continue; pImgData = &CV_IMAGE_ELEM(pImg,unsigned char,y+y0,x0*3); pMaskData = pImgFG?(&CV_IMAGE_ELEM(pImgFG,unsigned char,y+y0,x0)):NULL; pWData = (float*)CV_MAT_ELEM_PTR_FAST(m_Weights[0],y,0,sizeof(float)); for(x=0; x= pImg->width) continue; index = HIST_INDEX(pImgData); assert(index >= 0 && index < m_BinNumTotal); if(m_HistModelVolume>0) HM = ((DefHistType*)m_HistModel->data.ptr)[index]/m_HistModelVolume; if(m_HistCandidateVolume>0) HC = ((DefHistType*)m_HistCandidate->data.ptr)[index]/m_HistCandidateVolume; V = (HC>0)?sqrt(HM / HC):0; V += m_FGWeight*(pMaskData?((pMaskData[x]/255.0f)):0); pWData[x] = (float)MIN(V,100000); } /* Next column. */ } /* Next row. */ } /* if m_Dim == 3. */ } /* calcWeights */ public: CvBlobTrackerOneMSFGS() { int i; m_FGWeight = 0; m_Alpha = 0.0; /* Add several parameters for external use: */ AddParam("FGWeight", &m_FGWeight); CommentParam("FGWeight","Weight of FG mask using (0 - mask will not be used for tracking)"); AddParam("Alpha", &m_Alpha); CommentParam("Alpha","Coefficient for model histogramm updating (0 - hist is not upated)"); m_BinBit=0; m_Dim = 0; m_HistModel = NULL; m_HistCandidate = NULL; m_HistTemp = NULL; m_KernelHistModel = NULL; m_KernelHistCandidate = NULL; m_Weights = NULL; for(i=0; ipImg->width)w=pImg->width; if(h>pImg->height)h=pImg->height; ReAllocKernel(w,h); calcHist(pImg, pImgFG, cvPointFrom32f(CV_BLOB_CENTER(pBlobInit)), m_KernelHistModel, m_HistModel, &m_HistModelVolume); m_Blob = pBlobInit[0]; }; virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL) { int iter; if(pBlobPrev) { m_Blob = pBlobPrev[0]; } for(iter=0; iter<10; ++iter) { // float newx=0,newy=0,sum=0; float dx=0,dy=0,sum=0; int x,y,si; CvPoint Center = cvPoint(cvRound(m_Blob.x),cvRound(m_Blob.y)); CvSize Size = cvSize(cvRound(m_Blob.w),cvRound(m_Blob.h)); if(m_ObjSize.width != Size.width || m_ObjSize.height != Size.height) { /* Reallocate kernels: */ ReAllocKernel(Size.width,Size.height); } /* Reallocate kernels. */ /* Mean shift in coordinate space: */ calcHist(pImg, NULL, Center, m_KernelHistCandidate, m_HistCandidate, &m_HistCandidateVolume); calcWeights(pImg, pImgFG, Center); for(si=1; si<(SCALE_NUM-1); ++si) { CvMat* pKernel = m_KernelMeanShiftK[si]; float sdx = 0, sdy=0, ssum=0; int s = si-SCALE_RANGE; float factor = (1.0f-( float(s)/float(SCALE_RANGE) )*( float(s)/float(SCALE_RANGE) )); for(y=0; y 0) { dx /= sum; dy /= sum; } m_Blob.x += dx; m_Blob.y += dy; { /* Mean shift in scale space: */ float news = 0; float sum1 = 0; float scale; Center = cvPoint(cvRound(m_Blob.x),cvRound(m_Blob.y)); calcHist(pImg, NULL, Center, m_KernelHistCandidate, m_HistCandidate, &m_HistCandidateVolume); calcWeights(pImg, pImgFG, Center); //cvSet(m_Weights,cvScalar(1)); for(si=0; si0) { news /= sum1; } scale = (float)pow((double)SCALE_BASE,(double)news); m_Blob.w *= scale; m_Blob.h *= scale; } /* Mean shift in scale space. */ /* Check fo finish: */ if(fabs(dx)<0.1 && fabs(dy)<0.1) break; } /* Next iteration. */ if(m_Alpha>0) { /* Update histogram: */ double Vol, WM, WC; CvPoint Center = cvPoint(cvRound(m_Blob.x),cvRound(m_Blob.y)); calcHist(pImg, pImgFG, Center, m_KernelHistModel, m_HistCandidate, &m_HistCandidateVolume); Vol = 0.5*(m_HistModelVolume + m_HistCandidateVolume); WM = Vol*(1-m_Alpha)/m_HistModelVolume; WC = Vol*(m_Alpha)/m_HistCandidateVolume; cvAddWeighted(m_HistModel, WM, m_HistCandidate,WC,0,m_HistModel); m_HistModelVolume = (float)cvSum(m_HistModel).val[0]; } /* Update histogram. */ return &m_Blob; }; /* Process */ virtual void Release(){delete this;}; }; /*CvBlobTrackerOneMSFGS*/ static CvBlobTrackerOne* cvCreateBlobTrackerOneMSFGS() { return (CvBlobTrackerOne*) new CvBlobTrackerOneMSFGS; } CvBlobTracker* cvCreateBlobTrackerMSFGS() { return cvCreateBlobTrackerList(cvCreateBlobTrackerOneMSFGS); }