分享

视频中对多目标运动物体跟踪的算法解析

 littertree 2013-02-27

视频中对多目标运动物体跟踪的算法解析

1. 算法目的:

运动目标跟踪算法的目的就是对视频中的图象序列进行分析,计算出目标在每帧图象上的位置。这里要根据区域分割过程给出的目标质心位置,计算出目标位 移,并且根据质心位置的变化判断出目标的运动方向,以及运动目标是否在观察窗口,实现对客流量的统计。因为该跟踪是对多目标的追踪,需要找出运动目标在相 邻帧上的对应区域。

系统具有固有噪声,目标周围背景的干扰可能会产生误差,但这些噪声在前面的过程已经去除,如有必要可做适当调整修正。

2. 算法难点:

(1)因为要跟踪的是多目标,需要找到相邻帧之间对应的运动目标区域不致跟踪混乱。

(2)如何判断运动目标区域是否是新的目标进入观测窗口

(3)运动目标是否离开了观测窗口以及离开的方向;即计数器何时加1、是否加1

(4)对跟踪过程中出现的一些偏差和问题,要进行必要的修正

3. 算法描述:

(1)跟踪首先要判断的是:帧与帧之间如何将运动目标对应起来。追踪过程中的追踪特

征是物体的质心(由运动区域分割过程中给出),这里判断对应目标可以:a.只利用质心间的最短距离做为特征; b.利用加权系数将最短距离,运动目标区域的长度,宽度以及长宽比和面积等综合起来作为特征。

(2)根据判断特征设置目标链,记录每个被跟踪目标的最新质心位置,为下步判断提供条件。另外将每个目标的质心位置存储起来,可以随时掌握目标的运动情况,为以后要输出目标的运动曲线做基础。

(3)每进入观察窗口一个新的运动目标,就将它的最新质心位置加入该目标链。如何判断该运动目标是新的:设置门限值ymin,ymax(当 ymin<y<ymax视为在观测窗口,当y>ymax或y<ymin可认为是新目标区域),当有目标的质心位置 目标.y<ymin或目标.y>ymax并且它的标志位为未被跟踪,则肯定是新目标(在新目标区域出现的目标有可能是要离开观测窗口的目标, 不过它们的标志位肯定为被跟踪)。这样判断出来的新目标方向是有出、入之分的。

(4)与目标链(MB[h][l])相对应的还有位置数组(WZ[m][n]),用来存放目标链中相应目标的质心位置。最初进行处理时,目标链是空的,在当前帧中若有新目标,则将其横、纵坐标加入到目标链中,并存储在对应的位置数组中,置标记为被跟踪。

(5)处理新的当前帧时,首先将目标链MB中每个元素(代表前一帧中所有运动目标)依次与当前帧中记录的每个运动目标进行距离计算,求出其中最小距 离d(假设是MB[i]与当前帧中运动目标t的质心距离)则判断d与门限值λ的大小,若d<λ,则说明运动目标t就是前一祯MB[i]对应的运动目 标区域,则将t的质心位置更新代替MB[i]中的横纵坐标(MB[i]中记录目标i的最新质心位置),并将其质心位置加入到WZ[i]中去,记录该目标运 动质心的记录,将该运动目标标记为被跟踪;如d>λ则说明该最小值不足以证明它们是对应目标,可能MB[i]代表的目标已经不在跟踪窗口,则做如下 处理:

检查对应MB[i]代表的目标质心位置的最新记录,如果MB[i][1](纵坐标)>ymax,可认为目标离开观测窗口,并且方向是进入,则计数器加1;如果MB[i][1]< ymin,目标离开观测窗口,但方向是出去,计数器不动作。

(6)设置数组CC[m][n],存储离开观测窗口并且方向是进入的运动目标质心位置记录,象(5)中的MB[i]若是进入就将对应位置记录 WZ[i]存放在数组CC中,同时清除MB[i]中的特征值和WZ[i]中的质心记录。这里可以另外设置一个空闲位置数组KWZ[i],记录被清空的WZ 中的位置,每次有新目标到来,须分配数组空间就先检查是否有被清空的记录。

(7)直至目标链中的目标检查完毕,则查看当前祯中的各运动目标,如有未被标记的,且在新目标区域中则将其加入到目标链中,标记设为已被跟踪。

(8)接收新的当前祯,继续如此处理。

处理过程中可能出现的几个问题为:

(1) 如果当前祯中一个运动目标t已经被标记,但是当处理到目标链中下一个目标是最小距离的仍是t,说明目标链中有两个目标都与t的距离最小,这样就需要调整。

(2) 如果门限值λ设置不当,则可能产生误判。

(3) 如果目标链中所有目标检查完毕,但是在当前祯中有未被标记并且不在新目标区域,

即不是新目标,又不是被跟踪目标的相应目标,则有差错出现,可能是噪声。

(4) 是否将离开观测窗口并且运动方向是出去的目标质心位置存储在数组CC中。

4.算法实现

数据结构:

a. 设置数组WZ[m][n]用来存放跟踪过程中被跟跟踪目标的各时刻质心位置,WZ[i][0]存放下次填写质心记录的位置,从WZ[0][1]开始记录横坐标。

b. 设置数组MB[M][2]存放目标链,记录被跟踪目标的最新质心位置,MB[0][0]存放被跟踪目标的个数,MB[0][1]闲置。

c. 设置数组CC[h][l]存放离开观察窗口已跟踪完毕的各目标的质心位置,供若质心位置曲

线,提高精度用。

d. 设置KWZ[m]记录清空的WZ数组序号;KWZ[0]表示清空的WZ数组元素的个数,若再次分配数组空间给新目标时,先检查KWZ数组中KWZ[0]是否为0,若为0,则分配新数组空间,否则重新利用被清空的数组位置

e. 设置门限值λ,ymax,ymin.

f.接收到的运动目标为一个struct

初始化:

For (I=0;I<m;I++)

{ WZ[I][0]=1;

MB[I][0]=-1; 置初值;

MB[I][1]=-1;

}

for(I=0;I<n;I++)

CC[I][0]=-1; 初始化数组CC,

初始化数组KWZ;

KWZ[0]=0; 初始化时没有清空的数组

MB[0][0]=0;记录目标链中目标的数目

Cursorm=1; 记录目标链中最末位置

Cursorc=0; 记录数组CC中最末位置

Count=0; 计数器

While ( 有下一祯数据传送 )

{ for( I=1;I<cursorm;I++) 依次对目标链各目标进行处理

{ x=MB[I][0];

y=MB[I][1];

p=head; p指向一祯数据的头

do {

接收当前祯的数据;

d=sqrt(pow(x-p.x,2)+pow(y-p.y,2));

if(d<dmin) { dmin=d ; q=p;}

继续接收当前祯的下个运动目标的数据结构;

p=p->next;

}

while ( 当前祯的数据接收完全 )

if ( d<λ)

{ MB[I][0]=q.x;

MB[I][1]=q.y;

WZ[I][WZ[I][0]]=q.x;

WZ[I][WZ[I][0]]=q.y;

WZ[I][0]=WZ[I][0]+2;

q.mark=’y’;

}

else

{ if(MB[I][1]>ymax) 离开观测窗口方向是进入

{ count++;

将WZ[I]中的记录转存到CC数组中;

cursorc++;

清除WZ[I]和MB[I]中的数据;

KWZ[0]++; 标记空闲数组元素个数

KWZ[KWZ[0]]=I;

}

if(MB[I][1]<ymin) 离开观测窗口方向是出去

{ 清除WZ[I]和MB[I];

KWZ[0]++;

KWZ[KWZ[0]]=I;

}

}

}

目标链中的所有目标处理结束且目标链不空则:

{ 判断当前祯中各运动目标的标记;

p=head; 重新指向一祯的开头

while ( p!=null)

{ if(p.mark==’n’)

if(p.y<ymin||p.y>ymax)

{ 将该新目标加入到目标链中;

p.mark=’y’;

}

else 出错处理,修正;出现既非新目标又非被跟踪目标

p=p->next;

}

}

if (MB[0][0]==0) 说明还未有被跟踪目标,目标链为空

{ 依次读取当前祯的数据;

p=head;

while (当前祯数据未完)

{ if ( p.mark==’n’&&(p.y < ymin || p.y > ymax)) 在新目标区域

{ MB[cursorm][0]=p.x;

MB[cursorm][1]=p.y; 修改最新质心位置

MB[0][0]++;

WZ[cursorm][WZ[cursorm][0]]=p.x;

WZ[cursorm][WZ[cursorm][0]]=p.y;

WZ[cursorm][0]=WZ[cursorm][0]+2;

p.mark=’y’;

}

cursorm++;

p=p->next;

}

}

接收下一祯运动目标的数据结构;

} 对应while循环

5. 算法优化:

其中λ,ymin和ymax的取值要得当,否则会出现差错,这需要反复测试得到合适的值。

另外对图象的噪声影响和跟踪过程中出现的不期望的结果如果进行修正,则结果可能会更精确。

6. 各个函数功能及其输入输出

所有函数在程序track..c中存放。

(1)void Init() 初始化函数,将程序中全局变量——数组WZ和MB初始化,kwhead是指向空闲数组位置的指针,初始化为NULL,cursorm的值表示数组WZ和MB的最大下标+1;

其中MB[0][0]存放正在被跟踪目标个数,WZ[I][0]存放第I个被跟踪目标的下一个轨迹质心存放位置(在数组WZ中),countin,countout分别记录进入和出去的人数;

(2)void Addkw(int xh):

功能:将释放的数组元素下标加入一个链表中,便于以后分配。

输入:刚释放的数组元素的下标xh;

输出:无输出,下次分配时,利用指针头kwhead依次分配数组空间。

(3)int Delkw():

功能:有新的目标出现在运动区域,找到合适的数组下标,将此数组空间分配给该目标。

输入:无输入,直接调用该函数,从kwhead所指的链表中(为空闲数组下标)依次分

配空间。

输出:输出要分配的数组下标。

(5) int Getxymax(int WZtemp[Nmax]):

功能:从数组Wztemp所记录的运动轨迹中找到最大的横坐标或纵坐标。

输入:输入该运动目标的所有运动轨迹记录Wztemp.

输出:输出找到的最大的横坐标或纵坐标(如果定义Coordinate则找最大的横坐标,此

时运动目标在横轴上运动幅度较大而纵轴上几乎不变)

(6) int Getxymin(int WZtemp[Nmax]):

功能:从数组Wztemp所记录的运动轨迹中找到最小的横坐标或纵坐标。

输入:输入该运动目标的所有运动轨迹记录Wztemp;

输出:输出找到的最小的横坐标或纵坐标。

(7) void HandledataY():

如果没有定义Coordinate(表示目标运动方向是顺着或逆着纵坐标)则运行该程序。

功能:处理得到的运动质心,将各质心位置一一对应,找到各个运动目标的运动轨迹,并记数。

输入:无输入,数据的得到靠指针的传递,Crhead是每一帧目标质心位置的头指针,

靠指针的移动来读取数据。

输出:无输出,直接修改全局变量,得到被跟踪目标的运动轨迹和最新位置,并根据

相应的情况修改countin和countout。

在该函数中处理了一般情况和一些特殊情况,比如:运动目标在运动区域来回运动、以及停止不动,几帧之后重新运动、丢失一些帧的相关处理等等。

(8) void HandledataX()

如果定义Coordinate(表示目标运动方向是顺着或逆着横坐标)则运行该程序。

功能,输入和输出同(7)。

JBean发表于 2008年10月20日 10:44:00
From:http://hi.baidu.com/langson/item/bbe2a12c74fa44d20f37f926 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多