关于blobtracker的一些解析

virtual CvBlob* AddBlob(CvBlob* pB, IplImage* pImg, IplImage* pImgFG = NULL )

//这个函数的主要作用是在m_BlobList中加入新的blob,该结构包含了新创建的预测器和跟踪器
//pPredictor 采用卡尔曼线性滤波器来预测blob的位置
//pResolver 采用meanshift或者/和 particle filter粒子滤波器来进行跟踪

virtual void Process(IplImage* pImg, IplImage* pImgFG = NULL)
//这个函数先通过轮廓找到contour blob
//然后对前一帧的blob进行预测位置
//再将预测到的新位置与新产生的contour blob进行距离相关处理,
//如果是一个contour blob对应多个预测值,则认为有碰撞
//如果是多个contour blob对应一个预测数值,这里程序未做处理,个人认为应该有个分离处理
//接着对上述信息综合处理,m_BlobList列表中某个blob如果有碰撞,则采用meanshift 或者/和 
// particle filter进行跟踪的结果(位置信息,预测器,跟踪器)更新该blob
//如果没碰撞,如果是一个contour blob对应一个m_BlobList列表中的某个blob,则用contour blob更新
//该blob,如果多个contour blob对应一个m_BlobList列表中的某个blob,则找最佳的contour blob
//更新该blob。最佳blob有两中方式去判断,第一是根据meanshift算法中直方图最小距离法Bhattacharyya
//获得一个可信度,最大可信度的最匹配;第二采用空间上最小距离法,距离最小最匹配
//这里需要说明的是在处理碰撞情况下pResolver调用的process,由于上层的默认采用meanshift+Partical filter
//进行跟踪,所以运算量有时候非常大
//最终结果是用跟踪法更新了m_BlobList表中blob的位置

//新contour blob与以前多个blob的预测位置有交集则认为有碰撞
if(m_BlobList.GetBlobNum()>0 && m_BlobListNew.GetBlobNum()>0)

}/* check intersection */
//
//这里如果没有找到相关物体,则认为被隐藏,
//程序未做处理也
//可以判断是否到图像边界,如果在图像边界则认为消失,如果不在图像边界,则认为被遮挡,
//可以考虑继续跟踪,直到预测计数达到某个数值的时候认为该物体消失
//判断依据很简单:pFLast是否为NULL

}/* check next new blob */

if(pBT->Collision)
{/* tracking in collision */
//多个blob对应一个contour blob
if(pBT->pResolver)
{
//这个函数太耗资源了,恐怖哦,又有粒子跟踪又有meanshift,肯定很慢
//pBT->pResolver->Process(&(pBT->BlobPredict),pImg, pImgFG)[0];

pB[0] = pBT->BlobPredict;//pBT->pResolver->Process(&(pBT->BlobPredict),pImg, pImgFG)[0];
}
}/* tracking in collision */

/这里还有一种情况是 no contour blob对应的blob,此时pBT->pBlobHyp->GetBlobNum()应该为0
//所以CvBlob NewCC = pBT->BlobPredict;就是预测值
/* one blob several CC */
CvBlob* pBBest = NULL;

int CvBlobDetectorCC::DetectNewBlob(IplImage* /*pImg*/, IplImage* pFGMask, CvBlobSeq* pNewBlobList, CvBlobSeq* pOldBlobList)
/这个函数首先通过轮廓获得contour blob
//然后筛掉与其关联的已经存在的blob,该blob应该是通过预测,跟踪后的blob
//然后将剩下的blob与存在的track进行关联操作,如果符合关联条件则计数加1,
//这里的track类似于预备blob的历史轨迹表,他们可能成为新blob的,需要符合计数达到SEQ_SIZE
//轨迹符合线形拟合
//如果多个contour blob对应一个track则复制这个contour
//如果多个track对应一个contour blob,则通过计数和线形拟合进行最后判断
/* cvDetectNewBlobs return 1 and fill blob pNewBlob by blob parameters if new blob is detected */



/SEQ_SIZE应该是控制是否符合新blob条件的计数上限,
//比如一个contour blob在一个track里连续SEQ_SIZE次符合新blob条件,则判断是否该contour blob是一个新的blob,
//符合新blob条件有三个条件:
//1,物体高宽分别大于门限
//2,前后帧质心X,Y方向距离与以前blob列表中的所有blob分别都大于两个物体宽度和的平均高度和平均
//3,对连续SEQ_SIZE个物体的质心进行最小二乘法的线性拟合看是否符合一定运动轨迹规律
//前面的blob都是coutour blob,通过找轮廓方法获得的blob,
//coutour blob通过筛选确定是否为新物体


//m_TrackSeq用于存放可能为新blob的contour blob,每一个DefSeq
//都保存了符合条件contour blob的历史轨迹 当track计数达到了SEQ_SIZE的时候
//就与已有的 blob进行比对,看是否与已有的blob关联,关联条件主要是看两个blob的质心X,Y方向的距离是否
//大于两个blob宽度和的平均高度和平均,个人 认为这里多余了,因为前面已经检测过了
//还有就是判断物体是否在边界附近,如果在边界附近也可以不用处理跟踪了
//当所有的都符合,则用最小二乘法来最终确定track中SEQ_SIZE个历史blob的轨迹是否合理
{/* shift each track */

int j;
for(j=0;j<m_TrackNum;++j)
{
int i;
DefSeq* pTrack = m_TrackSeq+j;
for(i=SEQ_SIZE-1;i>0;--i)pTrack->pBlobs[i]=pTrack->pBlobs[i-1];
pTrack->pBlobs[0] = NULL;
if(pTrack->size == SEQ_SIZE)
pTrack->size--;
}
}/* shift each track */


else if((m_TrackNum+NewTrackNum)<SEQ_NUM)
{ /* duplicate existed track */
//这里表示前面已有contour blob符合要求,这样
//两个contour blob分开成两个track,类似一个物体分离出两个物体情况,
m_TrackSeq[m_TrackNum+NewTrackNum] = pTrack[0];//pTrack[0]前面已经pTrack->size++;这里直接赋值过去就可以了

//如果contour blob没有和任何的track关联则生成新的track
if(AsignedTrack==0 && (m_TrackNum+NewTrackNum)<SEQ_NUM )
{/* init new track */





//这里采用了最小二乘法进行线性拟合
//y=a*x+b,这里x是从0~N-1的数值,y分别表示运动轨迹的坐标值x,y,将他们分别进行线性拟合
//根据最小二乘法的线性拟合公式
//a=((x*y)'-x'*y')/((x*x)'-x'*x');
//b=y'-a*x';
//这里'是表示平均的意思

//首先有 1^2 + 2^2 + …… + n^2 = n*(n+1)*(2n+1)/6 
//有 1 + 2 + …… + n = n*(n+1)/2; 
//考虑x,是从0开始则,
//0 + 1^2 + 2^2 + …… + (n-1)^2=n*(n+1)*(2n+1)/6 -n*n=n*(n-1)*(2n-1)/6;
//0 + 1 + 2 + …… + n-1 = n*(n-1)/2; 
//公式推导过程
// a = (jsum/N-(N-1)/2*sum/N)/((N*(N+1)*(2*N+1)/6 -N*N)/N-(N-1)/2*(N-1)/2)
// = (jsum-(N-1)/2*sum)/((N-1)*(2N-1)/6-(N-1)*(N-1)/4)/N
// = 6*(2*jsum-(N-1)*sum)/((N-1)*(N+1)*N)
// = 6*(2*jsum-(N-1)*sum)/((N*N-1)*N)
// b = sum/N-a*(N-1)/2;
// = sum/N-3*(2*jsum-(N-1)*sum)/(N*(N+1));
// = ((N+1)*sum-6*jsum-3*(N-1)*sum)/(N*(N+1));
// = ((6*N-3)*sum-6*jsum)/(N*(N+1));
//与程序公式符合
a[0] = 6*((1-N)*sum[0]+2*jsum[0])/(N*(N*N-1));
b[0] = -2*((1-2*N)*sum[0]+3*jsum[0])/(N*(N+1));
a[1] = 6*((1-N)*sum[1]+2*jsum[1])/(N*(N*N-1));
b[1] = -2*((1-2*N)*sum[1]+3*jsum[1])/(N*(N+1));
for(j=0;j<N;++j)
{
Error += 
pow(a[0]*j+b[0]-pBL[j]->x,2)+
pow(a[1]*j+b[1]-pBL[j]->y,2);
}
//a[0],a[1]是斜率,如果斜率过大,表示速度快,这里过滤了快速运动 
//
Error = sqrt(Error/N);
if( Error > S.width*0.01 || 
fabs(a[0])>S.width*0.1 ||
fabs(a[1])>S.height*0.1)
{
Good = 0;
}
做一件有意义的事是很容易的事,困难的是一直坚持做,坚持那颗用不服输的心,坚持学习,坚持。。。
原文地址:https://www.cnblogs.com/rosekin/p/2981330.html