OpenCV中实现了粒子滤波的代码,位置在c:/program files/opencv/cv/src/cvcondens.cpp文件,通过分析这个文件,可以知道库函数中如何实现粒子滤波过程的。
首先是从手册上拷贝的粒子滤波跟踪器的数据结构:
typedef struct CvConDensation
{
int MP; // 测量向量的维数: Dimension of measurement vector
int DP; // 状态向量的维数: Dimension of state vector
float* DynamMatr; // 线性动态系统矩阵:Matrix of the linear Dynamics system
float* State; // 状态向量: Vector of State
int SamplesNum; // 粒子数: Number of the Samples
float** flSamples; // 粒子向量数组: array of the Sample Vectors
float** flNewSamples; // 粒子向量临时数组: temporary array of the Sample Vectors
float* flConfidence; // 每个粒子的置信度(译者注:也就是粒子的权值):Confidence for each Sample
float* flCumulative; // 权值的累计: Cumulative confidence
float* Temp; // 临时向量:Temporary vector
float* RandomSample; // 用来更新粒子集的随机向量: RandomVector to update sample set
CvRandState* RandS; // 产生随机向量的结构数组: Array of structures to generate random vectors
} CvConDensation;
与粒子滤波相关的几个函数:
cvCreateConDensation:用于构造上述滤波器数据结构
cvReleaseConDensation:释放滤波器
cvConDensInitSampleSet:初始化粒子集
cvConDensUpdateByTime:更新粒子集
下面着重对这几个函数进行分析。
CV_IMPL CvConDensation* cvCreateConDensation( int DP, int MP, int SamplesNum )
{
int i;
CvConDensation *CD = 0;
CV_FUNCNAME( "cvCreateConDensation" );
__BEGIN__;
if( DP < 0 || MP < 0 || SamplesNum < 0 )
CV_ERROR( CV_StsOutOfRange, "" );
/* allocating memory for the structure */
CV_CALL( CD = (CvConDensation *) cvAlloc( sizeof( CvConDensation )));
/* setting structure params */
CD->SamplesNum = SamplesNum;
CD->DP = DP;
CD->MP = MP;
/* allocating memory for structure fields */
CV_CALL( CD->flSamples = (float **) cvAlloc( sizeof( float * ) * SamplesNum ));
CV_CALL( CD->flNewSamples = (float **) cvAlloc( sizeof( float * ) * SamplesNum ));
CV_CALL( CD->flSamples[0] = (float *) cvAlloc( sizeof( float ) * SamplesNum * DP ));
CV_CALL( CD->flNewSamples[0] = (float *) cvAlloc( sizeof( float ) * SamplesNum * DP ));
/* setting pointers in pointer's arrays */
for( i = 1; i < SamplesNum; i++ )
{
CD->flSamples[i] = CD->flSamples[i - 1] + DP;
CD->flNewSamples[i] = CD->flNewSamples[i - 1] + DP;
}
CV_CALL( CD->State = (float *) cvAlloc( sizeof( float ) * DP ));
CV_CALL( CD->DynamMatr = (float *) cvAlloc( sizeof( float ) * DP * DP ));
CV_CALL( CD->flConfidence = (float *) cvAlloc( sizeof( float ) * SamplesNum ));
CV_CALL( CD->flCumulative = (float *) cvAlloc( sizeof( float ) * SamplesNum ));
CV_CALL( CD->RandS = (CvRandState *) cvAlloc( sizeof( CvRandState ) * DP ));
CV_CALL( CD->Temp = (float *) cvAlloc( sizeof( float ) * DP ));
CV_CALL( CD->RandomSample = (float *) cvAlloc( sizeof( float ) * DP ));
/* Returning created structure */
__END__;
return CD;
}
输入参数分别是系统状态向量维数、测量向量维数以及粒子个数,然后根据这些参数为滤波器相应结构分配空间。
CV_IMPL void
cvReleaseConDensation( CvConDensation ** ConDensation )
{
CV_FUNCNAME( "cvReleaseConDensation" );
__BEGIN__;
CvConDensation *CD = *ConDensation;
if( !ConDensation )
CV_ERROR( CV_StsNullPtr, "" );
if( !CD )
EXIT;
/* freeing the memory */
cvFree( &CD->State );
cvFree( &CD->DynamMatr);
cvFree( &CD->flConfidence );
cvFree( &CD->flCumulative );
cvFree( &CD->flSamples[0] );
cvFree( &CD->flNewSamples[0] );
cvFree( &CD->flSamples );
cvFree( &CD->flNewSamples );
cvFree( &CD->Temp );
cvFree( &CD->RandS );
cvFree( &CD->RandomSample );
/* release structure */
cvFree( ConDensation );
__END__;
}
释放滤波器占用的空间,没什么好说的
CV_IMPL void
cvConDensInitSampleSet( CvConDensation * conDens, CvMat * lowerBound, CvMat * upperBound )
{
int i, j;
float *LBound;
float *UBound;
float Prob = 1.f / conDens->SamplesNum;
CV_FUNCNAME( "cvConDensInitSampleSet" );
__BEGIN__;
if( !conDens || !lowerBound || !upperBound )
CV_ERROR( CV_StsNullPtr, "" );
if( CV_MAT_TYPE(lowerBound->type) != CV_32FC1 ||
!CV_ARE_TYPES_EQ(lowerBound,upperBound) )
CV_ERROR( CV_StsBadArg, "source has not appropriate format" );
if( (lowerBound->cols != 1) || (upperBound->cols != 1) )
CV_ERROR( CV_StsBadArg, "source has not appropriate size" );
if( (lowerBound->rows != conDens->DP) || (upperBound->rows != conDens->DP) )
CV_ERROR( CV_StsBadArg, "source has not appropriate size" );
LBound = lowerBound->data.fl;
UBound = upperBound->data.fl;
/* Initializing the structures to create initial Sample set */
这里根据输入的动态范围给每个系统状态分配一个产生随即数的结构
for( i = 0; i < conDens->DP; i++ )
{
cvRandInit( &(conDens->RandS[i]),
LBound[i],
UBound[i],
i );
}
/* Generating the samples */
根据产生的随即数,为每个粒子的每个系统状态分配初始值,并将每个粒子的置信度设置为相同的1/n
for( j = 0; j < conDens->SamplesNum; j++ )
{
for( i = 0; i < conDens->DP; i++ )
{
cvbRand( conDens->RandS + i, conDens->flSamples[j] + i, 1 );
}
conDens->flConfidence[j] = Prob;
}
/* Reinitializes the structures to update samples randomly */
产生以后更新粒子系统状态的随即结构,采样范围为原来初始范围的-1/5到1/5
for( i = 0; i < conDens->DP; i++ )
{
cvRandInit( &(conDens->RandS[i]),
(LBound[i] - UBound[i]) / 5,
(UBound[i] - LBound[i]) / 5,
i);
}
__END__;
}
CV_IMPL void
cvConDensUpdateByTime( CvConDensation * ConDens )
{
int i, j;
float Sum = 0;
CV_FUNCNAME( "cvConDensUpdateByTime" );
__BEGIN__;
if( !ConDens )
CV_ERROR( CV_StsNullPtr, "" );
/* Sets Temp to Zero */
icvSetZero_32f( ConDens->Temp, ConDens->DP, 1 );
/* Calculating the Mean */
icvScaleVector_32f是内联函数,表示flConfidence乘flSamples,放到State里,即求系统状态的过程,系统状态保存在temp中
for( i = 0; i < ConDens->SamplesNum; i++ )
{
icvScaleVector_32f( ConDens->flSamples[i], ConDens->State, ConDens->DP,
ConDens->flConfidence[i] );
icvAddVector_32f( ConDens->Temp, ConDens->State, ConDens->Temp, ConDens->DP );
Sum += ConDens->flConfidence[i];
ConDens->flCumulative[i] = Sum;
}
/* Taking the new vector from transformation of mean by dynamics matrix */
icvScaleVector_32f( ConDens->Temp, ConDens->Temp, ConDens->DP, 1.f / Sum );
icvTransformVector_32f( ConDens->DynamMatr, ConDens->Temp, ConDens->State, ConDens->DP,
ConDens->DP );
Sum = Sum / ConDens->SamplesNum;
/* Updating the set of random samples */
重采样,将新采样出来的粒子保存在flNewSamples中
for( i = 0; i < ConDens->SamplesNum; i++ )
{
j = 0;
while( (ConDens->flCumulative[j] <= (float) i * Sum)&&(j<ConDens->SamplesNum-1))
{
j++;
}
icvCopyVector_32f( ConDens->flSamples[j], ConDens->DP, ConDens->flNewSamples[i] );
}
/* Adding the random-generated vector to every vector in sample set */
for( i = 0; i < ConDens->SamplesNum; i++ )
{
为每个新粒子产生一个随即量
for( j = 0; j < ConDens->DP; j++ )
{
cvbRand( ConDens->RandS + j, ConDens->RandomSample + j, 1 );
}
将flNewSamples加一个随即量,保存入flSamples中
icvTransformVector_32f( ConDens->DynamMatr, ConDens->flNewSamples[i],
ConDens->flSamples[i], ConDens->DP, ConDens->DP );
icvAddVector_32f( ConDens->flSamples[i], ConDens->RandomSample, ConDens->flSamples[i],
ConDens->DP );
}
__END__;
}
运行完上述函数之后,经重采样后的粒子保存在flSamples中,同时上次迭代的加权系统状态保存在State中