typedef struct _TARGETHIST
{
float fHist[NBINS];
IVT_POINT pPonitMean[NBINS]; //均值
double dCov[4][NBINS]; //协方差
}TargetHist,*pTargetHist;
typedef struct Object
{
IVT_RECT pTrackWindow;
TargetHist sHist;
IVT_POINT nCenter;
}Object,*pObject;
class ObjectTracking
{
public:
ObjectTracking(void);
~ObjectTracking(void);
void <span style="white-space:pre"> </span>Init(int m_nWidth, int m_nHeight);
int m_nWidth;
int m_nHeight;
float <span style="white-space:pre"> </span> GaussHist(TargetHist* pHist1, TargetHist* pHist2);
int m_nThresh;
void <span style="white-space:pre"> </span>CreateHist(int* pSource, IVT_RECT* pBlob ,TargetHist *pHist);
void<span style="white-space:pre"> </span> MatrixInvert(float* pMatrix, float* pMatrixIn);
float <span style="white-space:pre"> </span>MeanshiftTracking(int *pFrame,Object *pTarget,IVT_RECT *pSearch);
float <span style="white-space:pre"> </span>FindLocation(int* pImg,TargetHist *pBlob, TargetHist *pSearch,IVT_RECT pSearchRect,int &X, int &Y,int nHalfWidth, int nHalfHeight);
void evalKernel (float*** kArray,int*** nDevi,int nWidth,int nHeight);
void <span style="white-space:pre"> </span>ReleseObject(void);
};
/************************************************************************/
/* 计算直方图相似度 */
/************************************************************************/
float ObjectTracking::GaussHist(TargetHist* pHist1, TargetHist* pHist2)
{
float pCov1_Invert[4], pCov2_Invert[4], fTemp1[2],pCovAdd[4], fTemp2[2], fTemp3, fTemp4,fSum=0, fTemp5;
float pCov1_Temp[4],pCov2_Temp[4];
int pMeanSub[2],i,j;
for (i=0; i<20; i++)
{
pMeanSub[0] = pHist1->pPonitMean[i].x - pHist2->pPonitMean[i].x;
pMeanSub[1] = pHist1->pPonitMean[i].y - pHist2->pPonitMean[i].y;
for (j=0; j<4; j++)
{
pCov1_Temp[j] = pHist1->dCov[j][i];
pCov2_Temp[j] = pHist2->dCov[j][i];
}
MatrixInvert(pCov1_Temp, pCov1_Invert);
MatrixInvert(pCov2_Temp, pCov2_Invert);
pCovAdd[0] = pCov1_Invert[0] + pCov2_Invert[0];
pCovAdd[1] = pCov1_Invert[1] + pCov2_Invert[1];
pCovAdd[2] = pCov1_Invert[2] + pCov2_Invert[2];
pCovAdd[3] = pCov1_Invert[3] + pCov2_Invert[3];
fTemp2[0] = pMeanSub[0]*pCovAdd[0] + pMeanSub[1]*pCovAdd[2];
fTemp2[1] = pMeanSub[0]*pCovAdd[1] + pMeanSub[1]*pCovAdd[3];
fTemp3 = fTemp2[0]*pMeanSub[0]+fTemp2[1]*pMeanSub[1];
fTemp4 = exp((-0.5)*fTemp3);
fTemp5 = sqrt((float)(pHist1->fHist[i]*pHist2->fHist[i]));
fSum += fTemp4*fTemp5;
}
return fSum;
}
/************************************************************************/
/* 创建直方图 */
/************************************************************************/
void ObjectTracking::CreateHist(int* pSource, IVT_RECT* pBlob, TargetHist *pHist)
{
int i,j,ntemp,nSub,nHistCount[NBINS],*nBlobImg,nWidth,nHeight,n,m;
double dRange,dTemp;
float fTotal = 0.0;
float **pWeight = NULL;
int **pArry = NULL;
int nMax=0, nMin=65535;
for (i=pBlob->nTop; i<pBlob->nBottom; i++)
{
for (j=pBlob->nLeft; j<pBlob->nRight; j++)
{
nMax = nMax>pSource[i*m_nWidth+j]?nMax:pSource[i*m_nWidth+j];
nMin = nMin<pSource[i*m_nWidth+j]?nMin:pSource[i*m_nWidth+j];
}
}
//dRange = (double)(MAXBIN-MINBIN) / NBINS;
dRange = (double)(nMax-nMin) / NBINS;
nWidth = pBlob->nRight - pBlob->nLeft;
nHeight = pBlob->nBottom - pBlob->nTop;
memset(pHist->fHist, 0, sizeof(float)*NBINS);
memset(pHist->dCov, 0, sizeof(double)*NBINS*4);
memset(pHist->pPonitMean,0, sizeof(IVT_POINT)*NBINS);
memset(nHistCount, 0, sizeof(int)*NBINS);
pWeight = new float*[nWidth];
ZeroMemory(pWeight, nWidth * sizeof(float*));
for (i=0; i<nWidth; i++)
{
pWeight[i] = new float[nHeight];
ZeroMemory(pWeight[i], nHeight* sizeof(float));
}
pArry = new int*[nWidth];
ZeroMemory(pArry, nWidth * sizeof(int*));
for (i=0; i<nWidth; i++)
{
pArry[i] = new int[nHeight];
ZeroMemory(pArry[i], nHeight* sizeof(int));
}
nBlobImg = (int*)malloc(nWidth*nHeight*sizeof(int));
evalKernel(&pWeight,&pArry,nWidth, nHeight);
for (i=pBlob->nTop,n=0; i<pBlob->nBottom; i++,n++)
{
for (j=pBlob->nLeft,m=0; j<pBlob->nRight; j++,m++)
{
nSub = pSource[i*m_nWidth+j] - nMin;
if (nSub<=0)
{
ntemp = 0;
}
else
{
ntemp = ceil((double)nSub / dRange);
if (ntemp>NBINS-1)
{
ntemp = NBINS-1;
}
}
pHist->fHist[ntemp] += pWeight[m][n];;
pHist->pPonitMean[ntemp].x += (j-pBlob->nLeft)*pArry[m][n];
pHist->pPonitMean[ntemp].y += (i-pBlob->nTop)*pArry[m][n];
nHistCount[ntemp] += 1*pArry[m][n];
nBlobImg[(i-pBlob->nTop)*nWidth+j-pBlob->nLeft]=ntemp;
fTotal += pWeight[m][n];
}
}
for(i=0; i<NBINS; i++)
{
if (fTotal != 0)
{
pHist->fHist[i] = pHist->fHist[i]/fTotal;
}
if (nHistCount[i]!=0)
{
pHist->pPonitMean[i].x = pHist->pPonitMean[i].x / nHistCount[i];
pHist->pPonitMean[i].y = pHist->pPonitMean[i].y / nHistCount[i];
}
}
for (i=0; i<nHeight; i++)
{
for (j=0; j<nWidth; j++)
{
ntemp = nBlobImg[i*nWidth+j];
pHist->dCov[0][ntemp] += (j-pHist->pPonitMean[ntemp].x)
*(j-pHist->pPonitMean[ntemp].x) * pArry[j][i];
pHist->dCov[1][ntemp] += (j-pHist->pPonitMean[ntemp].x)
*(i-pHist->pPonitMean[ntemp].y) * pArry[j][i];
pHist->dCov[2][ntemp] += (j-pHist->pPonitMean[ntemp].x)
*(i-pHist->pPonitMean[ntemp].y) * pArry[j][i];
pHist->dCov[3][ntemp] += (i-pHist->pPonitMean[ntemp].y)
*(i-pHist->pPonitMean[ntemp].y) * pArry[j][i];
}
}
for(i=0; i<NBINS; i++)
{
if (nHistCount[i]!=0)
{
pHist->dCov[0][i] = pHist->dCov[0][i] / nHistCount[i];
pHist->dCov[1][i] = pHist->dCov[1][i] / nHistCount[i];;
pHist->dCov[2][i] = pHist->dCov[2][i] / nHistCount[i];
pHist->dCov[3][i] = pHist->dCov[3][i] / nHistCount[i];
}
}
free(nBlobImg);
for (i=0; i<nWidth; i++)
delete[] pWeight[i];
delete [] pWeight;
pWeight = NULL;
for (i=0; i<nWidth; i++)
delete[] pArry[i];
delete []pArry;
pArry = NULL;
}
/************************************************************************/
/* 求逆矩阵2*2 */
/************************************************************************/
void ObjectTracking::MatrixInvert(float* pMatrix, float* pMatrixIn)
{
float fTemp;
fTemp = pMatrix[0]*pMatrix[3] - pMatrix[1]*pMatrix[2];
if (fTemp<10e-6 && fTemp>-10e-6)
{
fTemp = 0.0;
}
else
{
fTemp = 1.0 / fTemp;
}
pMatrixIn[0] = pMatrix[3] * fTemp;
pMatrixIn[1] = -pMatrix[1] * fTemp;
pMatrixIn[2] = -pMatrix[2] * fTemp;
pMatrixIn[3] = pMatrix[0] * fTemp;
}
/************************************************************************/
/* meanshift跟踪 */
/************************************************************************/
float ObjectTracking::MeanshiftTracking(int *pFrame,Object *pTarget,IVT_RECT *pBlob)
{
float fCOMHist=0.0,fDis;
int i,j,nWidth=pTarget->pTrackWindow.nRight-pTarget->pTrackWindow.nLeft;
int nHeight = pTarget->pTrackWindow.nBottom - pTarget->pTrackWindow.nTop;
int v_x,v_y,nCenter_x,nCenter_y,nHalfWidth, nHalfHeight;
TargetHist *pSearchHist;
IVT_RECT pSearchRect;
pSearchHist = (TargetHist*)malloc(sizeof(TargetHist));
nCenter_x = (pBlob->nRight+pBlob->nLeft)>>1;
nCenter_y = (pBlob->nTop+pBlob->nBottom)>>1;
nHalfHeight = nHeight>>1;
nHalfWidth = nWidth>>1;
pSearchRect.nLeft = nCenter_x - nHalfWidth;
pSearchRect.nTop = nCenter_y - nHalfHeight;
pSearchRect.nBottom = nCenter_y + nHalfHeight;
pSearchRect.nRight = nCenter_x + nHalfWidth;
for (i=0; i<MEANSHIFT_ITARATION_NO; i++)
{
CreateHist(pFrame,&pSearchRect, pSearchHist);
FindLocation(pFrame,&pTarget->sHist, pSearchHist,pSearchRect,v_x, v_y,nHalfWidth,nHalfHeight);
pSearchRect.nTop = v_y+pSearchRect.nTop;
pSearchRect.nBottom = pSearchRect.nBottom+v_y;
pSearchRect.nLeft = v_x+pSearchRect.nLeft;
pSearchRect.nRight = pSearchRect.nRight+v_x;
nCenter_x = nCenter_x+v_x;
nCenter_y = nCenter_y+v_y;
fDis = v_x*v_x +v_y*v_y;
if (fDis<2)
{
break;
}
}
nHalfWidth = (pBlob->nRight - pBlob->nLeft)>>1;
nHalfHeight = (pBlob->nBottom - pBlob->nTop)>>1;
pTarget->nCenter.x = nCenter_x;
pTarget->nCenter.y = nCenter_y;
pTarget->pTrackWindow.nTop = nCenter_y - nHalfHeight;
pTarget->pTrackWindow.nBottom = nCenter_y + nHalfHeight;
pTarget->pTrackWindow.nLeft = nCenter_x - nHalfWidth;
pTarget->pTrackWindow.nRight = nCenter_x + nHalfWidth;
CreateHist(pFrame, &pTarget->pTrackWindow, &pTarget->sHist);
free(pSearchHist);
return fCOMHist;
}
/************************************************************************/
/* 目标定位 */
/************************************************************************/
float ObjectTracking::FindLocation(int* pImg,TargetHist *pBlob, TargetHist *pSearch,IVT_RECT pSearchRect,int &X, int &Y,int nHalfWidth, int nHalfHeight)
{
float pCov1_Invert[4], pCov2_Invert[4], fTemp1[2],pCovAdd[4], fTemp2[2], fTemp3, fTemp4,fSum=0;
float pTemp5[4],fV_b[2],fTemp6[2],fTemp7, fAI_b,fArf[HISTOGRAM_LENGTH];
float pCov1_Temp[4],pCov2_Temp[4];
int pMeanSub[2],i,j,nWidth,nHeight;
int nMin=65535,nMax = 0;
memset(fV_b, 0, sizeof(float)*2);
memset(fArf, 0, sizeof(float)*HISTOGRAM_LENGTH);
for (i=0; i<NBINS; i++)
{
pMeanSub[0] = pBlob->pPonitMean[i].x - pSearch->pPonitMean[i].x;
pMeanSub[1] = pBlob->pPonitMean[i].y - pSearch->pPonitMean[i].y;
for (j=0; j<4; j++)
{
pCov1_Temp[j] = pBlob->dCov[j][i];
pCov2_Temp[j] = pSearch->dCov[j][i];
}
MatrixInvert(pCov1_Temp, pCov1_Invert);
MatrixInvert(pCov2_Temp, pCov2_Invert);
pCovAdd[0] = pCov1_Invert[0] + pCov2_Invert[0];
pCovAdd[1] = pCov1_Invert[1] + pCov2_Invert[1];
pCovAdd[2] = pCov1_Invert[2] + pCov2_Invert[2];
pCovAdd[3] = pCov1_Invert[3] + pCov2_Invert[3];
fTemp2[0] = pMeanSub[0]*pCovAdd[0] + pMeanSub[1]*pCovAdd[2];
fTemp2[1] = pMeanSub[0]*pCovAdd[1] + pMeanSub[1]*pCovAdd[3];
fTemp3 = fTemp2[0]*pMeanSub[0]+fTemp2[1]*pMeanSub[1];
fAI_b = exp((-0.5)*fTemp3);
fTemp4 = sqrt(pBlob->fHist[i]*pSearch->fHist[i]);
fTemp7 = fTemp4*fAI_b;
fSum += fTemp7;
if (pSearch->fHist[i] != 0)
{
fArf[i] += fAI_b * sqrt(pBlob->fHist[i]/pSearch->fHist[i]);
}
pTemp5[0] = fTemp7* pCovAdd[0];
pTemp5[1] = fTemp7* pCovAdd[1];
pTemp5[2] = fTemp7* pCovAdd[2];
pTemp5[3] = fTemp7* pCovAdd[3];
fTemp6[0] = pTemp5[0]*pMeanSub[0] + pTemp5[1]*pMeanSub[1];
fTemp6[1] = pTemp5[2]*pMeanSub[0] + pTemp5[3]*pMeanSub[1];
fV_b[0] += fTemp6[0];
fV_b[1] += fTemp6[1];
}
int ntemp,nSub,nCount[20]={0},m,n,fi,fj;
float dRange,fSum_y=0.0,fSum_x=0.0,fSum_Arf=0.0;
for (i=pSearchRect.nTop;i<pSearchRect.nBottom; i++)
{
for (j=pSearchRect.nLeft; j<pSearchRect.nRight; j++)
{
nMax = nMax>pImg[i*m_nWidth+j]?nMax:pImg[i*m_nWidth+j];
nMin = nMin<pImg[i*m_nWidth+j]?nMin:pImg[i*m_nWidth+j];
}
}
//dRange = (double)(MAXBIN-MINBIN) / 20.0;
dRange = (double)(nMax-nMin) / 20.0;
for (i=pSearchRect.nTop,m=0,fi=-nHalfHeight; i<pSearchRect.nBottom; i++,m++,fi++)
{
for (j=pSearchRect.nLeft,n=0,fj=-nHalfWidth; j<pSearchRect.nRight; j++,n++,fj++)
{
nSub = pImg[i*m_nWidth+j] - nMin;
if (nSub<=0)
{
ntemp = 0;
}
else
{
ntemp = ceil((double)nSub / dRange);
if (ntemp>19)
{
ntemp = 19;
}
}
fSum_y += fArf[ntemp]*fi;
fSum_x += fArf[ntemp]*fj;
fSum_Arf += fArf[ntemp];
nCount[ntemp]++;
}
}
X = (fSum_x-fV_b[0]) / fSum_Arf;
Y = (fSum_y-fV_b[1]) / fSum_Arf;
return fSum;
}
void ObjectTracking::evalKernel (float*** kArray,int*** nDevi,int nWidth,int nHeight)
{
int half_x = nWidth>>1;
int half_y = nHeight>>1;
float euclideanDistance;
for (int x = -half_x; x<half_x; x++)
{
for (int y =-half_y; y<half_y; y++)
{
euclideanDistance = sqrt( pow( ( (double)(x)/(double)(half_x) ) ,2.0)
+pow( ( (double)(y)/(double)(half_y) ) ,2.0) );
if (euclideanDistance > 1)
(*nDevi)[x+half_x][y+half_y] = 0;
else
(*nDevi)[x+half_x][y+half_y] = 1;
(*kArray)[x+half_x][y+half_y] = euclideanDistance;
}
}
}