笔者最近刚刚开始研究粒子滤波器,因为硕士论文的原因,最近在研究图像处理算法中的目标跟踪算法,我偶然间发现粒子滤波的简单性,于是在网上找相关的素材和博客来阅读,最后从Rob Hess的代码开始看起,大概理解额粒子跟踪算法的基本算法原理,因此,献出第一篇文章,希望能够给新手一点指点,也希望获得大牛的指点。
我不喜欢从枯燥的理论开始研究一个算法,拿到一个新的算法,我总要先找源码或者例程,开始自己跑一下,看一看效果,再从代码一步一步分析,当然,少不了查阅大量的文献和阅读大量的博客(博友的力量我觉得不亚于很多的硕士博士论文)。
废话不多说,这里从Rob Hess的代码开始讲起,我会一步一步的贴出源码,希望新手能够理解。
int main( int argc, char** argv )
{
gsl_rng* rng;//gsl库的使用 可以百度
IplImage* frame, * hsv_frame, * frames[MAX_FRAMES];
IplImage** hsv_ref_imgs;
histogram** ref_histos;
CvCapture* video;//用于视频每一帧图像的获取
particle* particles, * new_particles;//粒子的指针,保存粒子的信息
CvScalar color;//颜色
CvRect* regions;//一个矩形区域
int num_objects = 0;//目标物体的数量,待追踪物体数量
float s;
int i, j, k, w, h, x, y;
/* parse command line and initialize random number generator */
//arg_parse( argc, argv );
//以下都是关于gsl库的使用,用于生成自然数来用于高斯分布。
gsl_rng_env_setup();
rng = gsl_rng_alloc( gsl_rng_mt19937 );
gsl_rng_set( rng, time(NULL) );
video = cvCaptureFromFile( vid_file );//opencv中打开视频
//video = cvCaptureFromCAM( 0);
if( ! video )
fatal_error("couldn't open video file %s", vid_file);
以上是代码中的while主循环之前的初始化部分,因为这个代码是基于opencv的,所以用到了很多opencv的库函数,这个很简单,直接网上稍微学习一下就ok了。 上面都是一些很简单的初始化工作,真正的粒子算法在while中,用于每获取一帧图像后,进行循环处理。下面开始整体分析while的结构。
while( frame = cvQueryFrame( video ) )
{
hsv_frame = bgr2hsv( frame );
frames[i] = cvClone( frame );
/* allow user to select object to be tracked in the first frame */
if( i == 0 )
{
w = frame->width;
h = frame->height;
fprintf( stderr, "Select object region to track\n" );
while( num_objects == 0 )
{
num_objects = get_regions( frame, ®ions );
if( num_objects == 0 )
fprintf( stderr, "Please select a object\n" );
}
/* compute reference histograms and distribute particles */
ref_histos = compute_ref_histos( hsv_frame, regions, num_objects );
if( export )
export_ref_histos( ref_histos, num_objects );
particles = init_distribution( regions, ref_histos,
num_objects, num_particles );
}
else
{
/* perform prediction and measurement for each particle */
for( j = 0; j < num_particles; j++ )
{
particles[j] = transition( particles[j], w, h, rng );
s = particles[j].s;
particles[j].w = likelihood( hsv_frame, cvRound(particles[j].y),
cvRound( particles[j].x ),
cvRound( particles[j].width * s ),
cvRound( particles[j].height * s ),
particles[j].histo );
}
/* normalize weights and resample a set of unweighted particles */
normalize_weights( particles, num_particles );
new_particles = resample( particles, num_particles );
free( particles );
particles = new_particles;
}
/* display all particles if requested */
qsort( particles, num_particles, sizeof( particle ), &particle_cmp );//按照粒子的权重排序
if( show_all )
for( j = num_particles - 1; j > 0; j-- )
{
color = CV_RGB(255,255,0);
display_particle( frames[i], particles[j], color );//显示出所有的粒子位置 除了最接近的粒子
}
/* display most likely particle */
color = CV_RGB(255,0,0);
display_particle( frames[i], particles[0], color );
cvNamedWindow( "Video", 1 );
cvShowImage( "Video", frames[i] );
if(cvWaitKey( 5 ) == 27)
break;
cvReleaseImage( &hsv_frame );
i++;
}
整个while循环分成三个部分,if部分—else部分—显示部分。
if部分来判断是不是第一帧,因为第一帧需要手动选择待跟踪的目标物体,所以需要单独处理。 手动选择完待跟踪区域之后,开始计算物体的直方图并且初始化粒子。
else部分是在不是第一帧时,来根据上次的粒子位置,来重新抛洒粒子,并且计算每个粒子的直方图,和原始物体的直方图作比较,来筛选出最接近的粒子位置,记一个权重,这样的话就可以产生新的一组粒子。
显示部分用于显示每组新的粒子的位置。
未完待续,下一次将详细分析一下关键的粒子初始化部分和每一帧粒子的抛洒和重采样代码。