1.命令行参数处理 ->
2.设置随机数生成器环境,创建随机数生成器、并且对其初始化。->
3.初始化视频句柄 ->
4.取视频中的一帧进行处理 ->
1)GRB->HSV
2)保存当前帧在frames
3) 判断是否为坦裂谈第一帧,
若是则,源悄
(1)忙等用户选定欲跟踪的区域
(2)计算相关区域直方图
(3)得到跟踪粒子
若不是则,
(1)对每个粒子作变换,并计算每个粒子的权重
(2)对粒子集合进行归一化
(3)重新采样粒子
4)画出粒子所代表的区域
5.释放图像
OpenCV学习——物体跟踪的粒子滤波算法实现之命令行参数处理
void arg_parse( int argc, char** argv )
{
int i = 0
pname = remove_path( argv[0] )
while( TRUE )
{
char* arg_check
int arg = getopt( argc, argv, OPTIONS )
if( arg == -1 )
break
switch( arg )
{
case 'h':
usage( pname )
exit(0)
break
case 'a':
show_all = TRUE
break
case 'o':
export = TRUE
break
case 'p':
if( ! optarg )
fatal_error( "error parsing arguments at -%c\n"\
"Try '%s -h' for help.", arg, pname )
num_particles = strtol( optarg, &arg_check, 10 )
if( arg_check == optarg || *arg_check != '\0' )
fatal_error( "-%c option requires an integer argument\n"\
"Try '%s -h' for help.", arg, pname )
break
default:
fatal_error( "-%c: invalid option\nTry '%s -h' for help.",
optopt, pname )
}
}
if( argc - optind <1 )
fatal_error( "no input image specified.\nTry '%s -h' for help.", pname )
if( argc - optind >2 )
fatal_error( "too many arguments.\nTry '%s -h' for help.", pname )
vid_file = argv[optind]
}
作者让碰使用Getopt这个系统函数对命令行进行解析,-h表示显示帮助,-a表示将所有粒子所代表的位置都显示出来,-o表示输出tracking的帧,-p number进行粒子数的设定,然后再最后指定要处理的视频文件。
OpenCV学习——物体跟踪的粒子滤波算法实现之RGB->HSV
IplImage* bgr2hsv( IplImage* bgr )
{
IplImage* bgr32f, * hsv
bgr32f = cvCreateImage( cvGetSize(bgr), IPL_DEPTH_32F, 3 )
hsv = cvCreateImage( cvGetSize(bgr), IPL_DEPTH_32F, 3 )
cvConvertScale( bgr, bgr32f, 1.0 / 255.0, 0 )
cvCvtColor( bgr32f, hsv, CV_BGR2HSV )
cvReleaseImage( &bgr32f )
return hsv
}
程序现将图像的像素值归一化,然后使用OpenCV中的cvCvtcolor函数将图像从RGB空间转换到HSV空间。
OpenCV学习——物体跟踪的粒子滤波算法实现之设定随机数
gsl_rng_env_setup()//setup the enviorment of random number generator
rng = gsl_rng_alloc( gsl_rng_mt19937 )//create a random number generator
gsl_rng_set( rng, time(NULL) )//initializes the random number generator.
作者使用GSL库进行随机数的产生,GSL是GNU的科学计算库,其中手册中random部分所述进行随机数生成有三个步骤:
随机数生成器环境建立,随机数生成器的创建,随机数生成器的初始化。
OpenCV学习——物体跟踪的粒子滤波算法实现之计算选定区域直方图
histogram** compute_ref_histos( IplImage* frame, CvRect* regions, int n )
{
histogram** histos = malloc( n * sizeof( histogram* ) )
IplImage* tmp
int i
for( i = 0i <ni++ )
{
cvSetImageROI( frame, regions[i] )//set the region of interest
tmp = cvCreateImage( cvGetSize( frame ), IPL_DEPTH_32F, 3 )
cvCopy( frame, tmp, NULL )
cvResetImageROI( frame )//free the ROI
histos[i] = calc_histogram( &tmp, 1 )//calculate the hisrogram
normalize_histogram( histos[i] )//Normalizes a histogram so all bins sum to 1.0
cvReleaseImage( &tmp )
}
return histos
}
程序中先设置了一个类型为histogram的指向指针的指针,是histogram指针数组的指针,这个数组是多个选定区域的直方图数据存放的位置。然后对于每一个用户指定的区域,在第一帧中都进行了ROI区域设置,通过对ROI区域的设置取出选定区域,交给函数calc_histogram计算出直方图,并使用normalize_histogram对直方图进行归一化。
计算直方图的函数详解如下:
histogram* calc_histogram( IplImage** imgs, int n )
{
IplImage* img
histogram* histo
IplImage* h, * s, * v
float* hist
int i, r, c, bin
histo = malloc( sizeof(histogram) )
histo->n = NH*NS + NV
hist = histo->histo
memset( hist, 0, histo->n * sizeof(float) )
for( i = 0i <ni++ )
{
img = imgs[i]
h = cvCreateImage( cvGetSize(img), IPL_DEPTH_32F, 1 )
s = cvCreateImage( cvGetSize(img), IPL_DEPTH_32F, 1 )
v = cvCreateImage( cvGetSize(img), IPL_DEPTH_32F, 1 )
cvCvtPixToPlane( img, h, s, v, NULL )
for( r = 0r <img->heightr++ )
for( c = 0c <img->widthc++ )
{
bin = histo_bin( pixval32f( h, r, c ),
pixval32f( s, r, c ),
pixval32f( v, r, c ) )
hist[bin] += 1
}
cvReleaseImage( &h )
cvReleaseImage( &s )
cvReleaseImage( &v )
}
return histo
}
这个函数将h、s、 v分别取出,然后以从上到下,从左到右的方式遍历以函数histo_bin的评判规则放入相应的bin中(很形象的)。函数histo_bin的评判规则详见下图:
|----|----|----|。。。。|----|------|------|。。。。|-------|
1NH 2NH 3NHNS*NHNS*NH+1NS*NH+2 NS*NH+NV
OpenCV学习——物体跟踪的粒子滤波算法实现之初始化粒子集
particle* init_distribution( CvRect* regions, histogram** histos, int n, int p)
{
particle* particles
int np
float x, y
int i, j, width, height, k = 0
particles = malloc( p * sizeof( particle ) )
np = p / n
for( i = 0i <ni++ )
{
width = regions[i].width
height = regions[i].height
x = regions[i].x + width / 2
y = regions[i].y + height / 2
for( j = 0j <npj++ )
{
particles[k].x0 = particles[k].xp = particles[k].x = x
particles[k].y0 = particles[k].yp = particles[k].y = y
particles[k].sp = particles[k].s = 1.0
particles[k].width = width
particles[k].height = height
particles[k].histo = histos[i]
particles[k++].w = 0
}
}
i = 0
while( k <p )
{
width = regions[i].width
height = regions[i].height
x = regions[i].x + width / 2
y = regions[i].y + height / 2
particles[k].x0 = particles[k].xp = particles[k].x = x
particles[k].y0 = particles[k].yp = particles[k].y = y
particles[k].sp = particles[k].s = 1.0
particles[k].width = width
particles[k].height = height
particles[k].histo = histos[i]
particles[k++].w = 0
i = ( i + 1 ) % n
}
return particles
}
程序中的变量np是指若有多个区域n,则一个区域内的粒子数为p/n,这样粒子的总数为p。然后程序对每个区域(n个)中p/n个粒子进行初始化,三个位置坐标都为选定区域的中点,比例都为1,宽度和高度为选定区域的高度。然后又跑了个循环确定p个粒子被初始化。
OpenCV学习——物体跟踪的粒子滤波算法实现之粒子集合变换
particle transition( particle p, int w, int h, gsl_rng* rng )
{
float x, y, s
particle pn
x = A1 * ( p.x - p.x0 ) + A2 * ( p.xp - p.x0 ) +
B0 * gsl_ran_gaussian( rng, TRANS_X_STD ) + p.x0
pn.x = MAX( 0.0, MIN( (float)w - 1.0, x ) )
y = A1 * ( p.y - p.y0 ) + A2 * ( p.yp - p.y0 ) +
B0 * gsl_ran_gaussian( rng, TRANS_Y_STD ) + p.y0
pn.y = MAX( 0.0, MIN( (float)h - 1.0, y ) )
s = A1 * ( p.s - 1.0 ) + A2 * ( p.sp - 1.0 ) +
B0 * gsl_ran_gaussian( rng, TRANS_S_STD ) + 1.0
pn.s = MAX( 0.1, s )
pn.xp = p.x
pn.yp = p.y
pn.sp = p.s
pn.x0 = p.x0
pn.y0 = p.y0
pn.width = p.width
pn.height = p.height
pn.histo = p.histo
pn.w = 0
return pn
}
程序使用动态二阶自回归模型作为基本变换思路,变换的对象有坐标x,坐标y,和比例s。变换的x和y要符合在width和height之内的条件。
OpenCV学习——物体跟踪的粒子滤波算法实现之粒子集重新采样
particle* resample( particle* particles, int n )
{
particle* new_particles
int i, j, np, k = 0
qsort( particles, n, sizeof( particle ), &particle_cmp )
new_particles = malloc( n * sizeof( particle ) )
for( i = 0i <ni++ )
{
np = cvRound( particles[i].w * n )
for( j = 0j <npj++ )
{
new_particles[k++] = particles[i]
if( k == n )
goto exit
}
}
while( k <n )
new_particles[k++] = particles[0]
exit:
return new_particles
}
程序先使用C标准库中的qsort排序函数,按照权重,由大到小将原粒子集排序。然后将权重大的在新的粒子集中分配的多一点。
OpenCV学习——物体跟踪的粒子滤波算法实现之权重归一化
void normalize_weights( particle* particles, int n )
{
float sum = 0
int i
for( i = 0i <ni++ )
sum += particles[i].w
for( i = 0i <ni++ )
particles[i].w /= sum
}
粒子滤波(PF: Particle Filter)算法起源于20世纪50年代Poor Man's Monte Carlo问题的研究,但第一个具有应用性的粒子滤波算法于1993年由Gordon等提出(“A novel Approach to nonlinear/non-Gaussian Bayesian State estimation”)。它是利用粒子集来表示概率,可以用在任何形式的状态空间模型上。其核心思想是通过从后验概率中抽取的随机状态粒子来表示其分布情况配兄陆,是一种顺序重要性采样法(Sequential Importance Sampling)。
粒子滤波的应用非常广泛,尤其是在目标跟踪(“A probabilistic framework for matching temporal trajectories”)等视觉任务方面。粒子滤波算法有许多不同的改进方式。针对不同的问题,PF算法被改造以适应更好的问题。本文主要侧重于目标跟踪方面的应用。以人脸跟踪为例,下图展示了粒子滤波的跟踪结果。下面介绍下粒子滤波的基本过程:初培顷始化、概率转移、权重重计算和重采样四个阶段。
1.初始化阶段
跟踪区域初始化。在使用粒子滤波算法进行目标跟踪前需要选择要跟踪的目标物体。这个过程可以用人工划定方法和自动识别方法。使用人工的方法可以通过鼠标在图像区域标记出一个感兴趣矩形;使用自动的方法就是利用自动的目标检测技术,初步检测出图像中要跟踪物体的大致位置。以人脸跟踪为例,人工方法就是鼠标划定视频第一帧中人脸的区域;自动方法就是可以使用人脸检测算法检测出人脸的初始位置。
粒子初始化。对于本文人脸检测的示例,粒子就是图像中的矩形区域,主要由矩形中心(x,y)和宽高(w,h)四个变量表示。粒子初始化的步骤,就是在图像中选择指定数量的粒子(矩形),比如N=100个粒子。粒子初始化过程就是在图尘漏像中随机或指定方式放粒子。比如说,我们可以指定100个粒子初始状态和跟踪区域一致,即粒子参数和跟踪区域的(x,y,w,h)相等。
2.状态转移阶段
使用粒子滤波算法来对目标进行跟踪,即是通过前一次的先验概率来估算出当前环境下的后验概率密度,这个过程也是由粒子来完成的。具体来说,即根据上一帧中粒子的状态(x,y,w,h)t-1,来估计出本帧中各个粒子的状态(x,y,w,h)t。从上一帧图像的粒子状态转变为当前帧粒子的状态,这个变异过程就叫作转移(transmission)。粒子滤波的转移方程跟Kalman滤波的差不多:
上面的是状态转移方程,下面的为观测方程,wk和vk是高斯噪声。在本文示例中,xk=(x,y,w,h)t。变量x,y,w,h可以依据公式(1)分别更新。在不同的算法中,f采用的函数也不相同。如果xk=xk-1+wk,则状态转移方程其实是随机游走过程;如果xk=Axk-1+wk,状态转移方程则为一阶自回归方程;如果xk=A1xk-1+A2xk-2+wk,则状态转移方程为二阶自回归方程。
3.权重重计算阶段
转移阶段将上一帧中粒子的位置进行了转移,得到当前帧中新的位置。但并不是所有粒子的作用都有用。也就是有些粒子并不是跟踪区域所要所移动的位置。因此,在此阶段,粒子滤波算法将对每个粒子进行打分,将得分较低的粒子删除,将得分多的粒子生成更多的粒子(重采样过程完成)。具体打分的方法根据不同的需求会不同,例如人脸跟踪方法中使用距离作为衡量的标准。将每个粒子与跟踪区域进行相似度计算(在这里,分别提取粒子和跟踪区域的视觉特征进行计算,比如颜色直方图),使用相似度作为相应粒子的权重。每一个粒子都需要计算其权重,并且需要将其归一化。该阶段其实也是后验概率进行更新的过程。
4.重采样阶段
粒子滤波算法会淘汰权值低的粒子,让权值高的粒子来产生出更多的粒子,这就使得算法朝着权值高的地方收敛。假设有100个粒子,1号粒子的权重为0.02而2号粒子的权重为0.003。于是在重采样阶段,1号粒子生孩子的指标是0.02×100=2,2号粒子的指标是0.003×100=0.3,可以发现,1号粒子除了刚产生的粒子外还要再额外的产生一个粒子,而2号粒子就被铲除了。如此,最后得到的100个粒子即为所求,然后取个加权平均就得到了目标的状态值。
与卡尔曼滤波(Kalman Filter)相比较
粒子滤波(PF: Particle Filter)的思想基于蒙特卡洛方法(Monte Carlo methods),它是利用粒子集来表示概率,可以用在任何形式的状态空间模型上。其核心思想是通过从后验概率中抽取的随机状态粒子来表达其分布,是一种顺序重要性采样法(Sequential Importance Sampling)。简单来说,粒子滤波法是指通过寻找一组在状态空间传播的随机样本对概率密度函数进行近似,以样本均值代替积分运算,从而获得状态最小方差分布的过程。这里的样本即指粒子,当样本数量N→∝时可以逼近任何形式的概率密度分布。
尽管算法中的概率分布只是真实分布的一种近似,但由于非参数化的特点,它摆脱了解决非线性滤运握波问题时随机量必须满足高斯分布的制约,能表达比高斯模型更广泛的分布,也对变量参数的非线性特性有更强的建模能力。因此,粒子滤波能够比较精确地表达基于观测量和控制量的后验概率分布,可以用于解决SLAM问题。 在现代目标跟踪领域,由于实际问题的复杂性,所面对的更多的是非线性非高斯问题,Hue等把PF推广到多目标跟踪和数据关联 ,Gordon等对杂波中的目标跟踪问题提出混合粒子滤波器弼 ,Mcginnity等提出机动目标跟踪的多模型粒子滤波器 ,Doucet等对跳跃Markov系统状态估计提出了更有效的PF算法 j,Guo把PF用于传感器网络下的协同跟踪 J,Freitas等用PF训练神经网络 ,Srivastava等把PF用于自动目标识别 ,Fox等把PF用于移动机器人定位 ,Ward等提出语音源定位的PF算法,Orton等对来自多个传感器的无序量测提出基于PF的多目标跟踪和信息融合方法 ,Penny等使用PF实现多传感器资源最优管理和部署 ,Hernandez等结合PF、数据融合和优化算法实现多传感器资源管理 .研究表明PF是解决此类非线性问题的有力工具之一.PF在计算机视觉、可视化跟踪领域被称为凝聚算法(CONDENsATION),该领域是PF的一个非常活跃的应用领域,Bruno提出图像序列中目标跟踪的PF算法 ,Maskell等提出基于图像传感器多目标跟踪的PF算法_4 .在听觉视觉联合目标定位和跟踪方面,Vermaak等利用PF提出声音和视觉融合的集成跟踪 ,Zotkin等使用PF将来自多个摄像机和麦克风组的视觉听觉信息融合跟踪移动目标。
在粒子滤波算法下一些传统的难点问题如目标检测、遮挡、交叉、失跟等得到更好的结果.在无线通讯中PF被广泛用于信道盲均衡、盲检测、多用户检测等方面.其它的应用领域还有机器人视觉跟踪 、导航 、图象处理 、生物信息 引、故障诊断和过程控制 、金融数据处理 等.研究表明在有关非高斯非线性系统的数据处理和分析领域PF都具有潜在的应用价值.值得一提的是国内学者在PF的研究上也取得许多成果,莫等利用PF算法提出一旁渣庆种混合系统状态监测与诊断的新方法 ,Chen等利用PF预测非线性系统状态分布,获得故障预测概率 ,Li等提出基于PF的可视化轮廓跟踪方法 J,Shan等提出基于PF的手形跟踪识别方法 ,Hu等提出闪烁噪声下的PF跟踪算法 等,这些工作推动PF在国内的研究. 粒子滤波器采用一组随机粒子逼近状态的后验概率分布,有可能用粒子逼近平滑分布,由于重采样使得粒子丧失多样性,直接由滤波分布边缘化得到的平滑分布效果很差,Doucet等应用MCMC方法增加样本多样性用于固定延迟平滑取梁姿得好的效果,Fong等把RBPF推广到粒子平滑器,并用于语音信号处理 1.
在PF的性能优化方面,目前大多优化某个局部的性能指标,如重要性权的方差等,Doucet等使用随机逼近对PF关于某个全局性能指标进行在线优化 ,Chan等人进一步利用SPSA随机优化方法优化PF ,避免1r梯度的计算.为了减少计算量使得PF能用于实时数据处理,Foxt提出了粒子个数可变的自适应粒子滤波器 ,Kwok等把粒子划分为小的集合,每个小样本集可以进行实时处理,采用加权和的方法逼近状态后验分布 ,Brun等提出PF的并行结构算法以获得在线实时应用 .
最近几年,粒子方法出现了又一些新的发展,一领域用传统的分析方法解决不了的问题,现在可以借助基于粒子仿真的方法来解决.在动态系统的模型选择,故障检测、诊断方面,出现了基于粒子的假设检验、粒子多模型、粒子似然度比检测等方法.在参数估计方面,通常把静止的参数作为扩展的状态向量的一部分,但是由于参数是静态的,粒子会很快退化成一个样本,为避免退化,常用的方法有给静参数人为增加动态噪声_9 以及Kernel平滑方法 ,而Doucet等提出的点估计方法避免对参数直接采样,在粒子框架下使用最大似然估计(ML)以及期望值最大(EM)算法直接估计未知参数 .在随机优化方面,出现了基于粒子方法的梯度估计算法,使得粒子方法也用于最优控制等领域.Andrieu,Doucet等在文献[70]中详细回顾了粒子方法在变化检测、系统辨识和控制中的应用及理论上的一些最新进展,许多仅仅在几年前不能解决的问题现在可以求助于这种基于仿真的粒子方法.
总结与展望(Summarization and prospect)
目前粒子滤波器的研究已取得许多可喜的进展,应用范围也由滤波估计扩展到新的领域,作为一种新方法,粒子方法还处于发展之中,还存在许多有待解决的问题,例如随机采样带来Monte Carlo误差的积累甚至导致滤波器发散、为避免退化和提高精度而需要大量的粒子使得计算量急剧增加、粒子方法是否是解决非线性非高斯问题的万能方法还值得探讨.此外粒子滤波器还只是停留在仿真阶段,全面考虑实际中的各种因素也是深化PF研究不可缺少的一个环节.尽管如此,在一些精度要求高而经典的分析方法又解决不了的场合,这种基于仿真的逼近方法发挥了巨大潜力,而现代计算机和并行计算技术的迅速发展又为粒子方法的发展和应用提供了有力支持,相信粒子滤波器的研究将朝着更深,更广的方向发展.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)