TLD算法流程说明--episode2

来源:互联网 发布:非结构化数据举例 编辑:程序博客网 时间:2024/04/30 02:35

一、    初始化工作进行完毕之后,开始顺序读取每一帧,也即调用tld.processFrame(last_gray,current_gray,pts1,pts2,pbox,status,tl,bb_file)逐帧处理。last_graycurrent_gray分别是上一帧和当前帧的灰度图;pts1pts2是跟踪点的坐标,初始化为空,在函数内部实现赋值和应用;pbox是上一帧跟踪的结果;statusbool值用于表示上一帧是否有跟踪到窗口;tl个人理解t对应trackl对应learn,也即tl是表示是否进行tracklearnbool标记;bb_file是存放跟踪结果的文件的路径。这个函数依次执行以下四个模块:跟踪模块、检测模块、综合模块、学习模块。

1.     跟踪模块:track(img1,img2, points1,points2)

这个函数的输入是上一帧灰度图img1和当前帧灰度图img2,以及跟踪点的坐标points1points2。它分以下几个步骤进行:

1.1    bbPoints(points1,lastbox)

这个函数主要功能就是进行点的生成,在上一帧的跟踪区域lastbox中进行均匀采样,得到不超过10*10=100个点放到points1(因为采样步长是用ceil进一法得到,所以每行或每列得到的点可能无法达到10)

1.2    tracker.trackf2f(img1,img2,points1,points2)

这个函数输入是上一帧灰度图img1和当前帧灰度图img2bbPoints()生成的点序列points1,输出是points2,主要功能是完成:跟踪、计算FB error和匹配相似度sim,然后剔除 匹配度小于匹配度中值的(sim_error[i] median(sim_error)),再剔除跟踪误差大于误差中值的(FB_error[i] <= median(FB_error)) 也即把跟踪结果不好的特征点去掉,剩下的是不到50%的特征点,对应地留在points1points2中。

跟踪的原理基于Forward-Backward Error的中值流跟踪方法,对于points1中的每个点,使用前向跟踪,即上一帧的点A(由于点A是在lastbox行生成的,所以确实是上一帧的点)在当前帧的跟踪结果为B,然后使用后向跟踪,即当前帧的点B反向跟踪得到上一帧的跟踪点C,这样就产生了前向和后向两条跟踪轨迹,理想的情况应该是两条轨迹重合,即AC是重合的,所以计算AC的距离FB_error,得到一个FB_error[]数组。之后调用normCrossCorrelation()计算ABsimilarity,这个similarity是以AB为中心的,分别在上一帧和当前帧截取的10*10的区域调用matchTemplate()函数计算匹配度,将匹配度值赋给similarity,得到一个similarity[]数组。

接下来调用filterPts(vector&points1,vector& points2)对所得到的点进行过滤,其中points1是所有点A组成的集合,points2是所有点B组成的集合。首先计算similarity[]数组中所有数的中值simmed,对于similarity超过simmed的点进行保留,其余的剔除,这样FB_error[]数组的规模也相应减小。之后计算这个减小规模后的FB_error[]数组的中值fbmed,对于FB_error小于fbmed的点进行保留,其余的剔除。

1.3    bbPredict(points1,points2,lastbox,tbb)

这个函数输入中的point1points2是前面用光流法跟踪并剔除跟踪效果不好的特征点而剩下的点集,lastbox是上一帧的跟踪结果,tbb是用于记录当前帧的跟踪结果。主要功能是利用剩下的这不到一半的跟踪点作为输入来预测bounding box在当前帧的位置和大小 并放到tbb中。 它先按x维度和y维度分别计算所有点在上一帧和当前帧的跟踪差距,并计算出这些差距的中值dxdy。接下来计算points1中所有点两两之间的距离d1points2中所有点两两之间的距离d1,将d2/d1都放到d中,计算所有的d的中值s,这个s就表征了进行光流跟踪之后特征点变化相对于上一帧位置的偏移比例,从而用s去乘以上一帧窗口的宽高度以得到当前帧跟踪结果窗口的宽高度;另外,跟踪窗口的左上角坐标也要更新,坐标的偏移不能只考虑位移的绝对值,还要考虑窗口本身宽高度,也即这个位移相对于窗口本身的比例,所以用0.5*(s-1)分别去乘以上一帧窗口的宽度和高度,得到偏移量s1s2,再结合表征了上一帧和当前帧跟踪差距的dxdy,得到新跟踪结果tbb(trackbounding box)的左上角坐标(lastbox.x+ dx -s1, lastbox.y + dy -s2)

1.4    对跟踪结果进行判断,如果fbmed超过10(固定经验值)、或者窗口坐标位于图像外,说明跟踪的结果不稳定,将跟踪结果丢弃,置tvalidtrackedfalse并进入下一帧,否则继续进行下面的过程。

1.5    估计置信度和有效性,调用getPattern()计算当前帧在跟踪结果区域的pattern,把pattern做为输入调用NNConf计算它与在线模型的保守相似度tconf,如果tconf>thr_nn_valid,则置tvalidtrue,也即表示当前跟踪结果有效,否则tvalid仍为上一帧的值。

2.     检测模块:detect(img2)

这个函数的输入是当前帧的灰度图,对该图中的所有扫描窗口,依次用上面提到的方差分类器、Fern分类器、最近邻分类器所形成的级联分类器进行检测,只有通过所有分类器检测的扫描窗口才认为含有前景目标而可能是跟踪区域。具体过程如下:

2.1    计算积分图和积分平方图,对img2进行高斯平滑。之后对所有扫描窗口,依次进入以下级联着的分类器

2.2    方差检测分类器,利用积分图调用getVar()计算每个扫描窗口的方差,如果方差大于var阈值(var初始初始是best_box标准差平方的一半,也即目标patch方差的一半),则认为其含有前景目标,(注意:虽说标准差是方差的平方根,但是程序中求方差和标准差是用两个不同的函数计算的)

2.3    Fern分类器,对通过前面方差检测分类器的扫描窗口,调用getFeatures()计算10棵树对该扫描窗口的编码(长度为1301序列),利用该编码结合measure_forest()得到10棵树对该扫描窗口的10个后验概率累加和的平均值,如果平均值大于Fern分类器的阈值fern_th(初始从myParam.yml获取是0.65后面会不断更新),则该扫描窗口也通过Fern分类器的检测,将窗口放到容器中以便后面最近邻分类器的检测。(程序中是10个后验概率累加和conf10*fern_th进行比较,其实一样,就是将除法换成乘法,以加快计算速度,同时conf也可用于下面的排序)

2.4    通过前面两个分类器检测的扫描窗口按照后验概率累加和conf进行降序排列,如果窗口数目超过100个,则取前面100个后验概率较大的。对这些窗口,调用getPattern()获取pattern,然后调用NNConf()计算与在线模型的相关相似度conf1和保守相似度conf2,如果相关相似度conf1大于近邻分类器的阈值nn_th,则保留该窗口及其对应的保守相似度的值,通过以上三个分类器检测的扫描窗口放到dbb容器中,对应的保守相似度放到dconf容器中。

3.     综合模块

这个模块是对跟踪和检测结果进行综合,按照是否检测到、是否跟踪到的两两组合可以分为四种情况:跟踪到检测到、跟踪到但没检测到、没跟踪到但检测到、没跟踪到没检测到。由于需要用到检测模块中的保守相似度,也即必须使用通过检测模块的扫描窗口的信息,所以只考虑第一和第三种情况。

3.1    如果跟踪到并检测到

对检测到的窗口(通过检测模块的三个分类器后得到的窗口),调用clusterConf(dbb,dconf,cbb,cconf)进行聚类,其中dbbdconf是检测模块得到的结果(dbb->detectbounding box)cbb(cbb->clusterbounding box)cconf是该函数的输出。这个函数针对dbb中窗口的数目采取不同策略,如果只有一个窗口,那么不用聚类,直接把dbbdconf分别赋给cbbcconf即可;如果有两个窗口,调用bbOverlap()计算两个窗口的重叠率,如果重叠率小于一定的阈值1-space_thr(固定值为0.5),则分为两类。如果窗口超过两个,那么调用partition()函数按照重叠率将窗口分为两类,一类是重叠率小于0.5的,另一类是超过0.5的。此处自己不是特别理解,参考BeyondEgozouxy09的博客,说到“c= partition(dbb,T,(*bbcomp))”把一个区间中的元素按照某个条件分成两类,并返回第二类子集的起点。bbcomp这个指针所对应的函数是比较两个窗口重叠率,小于0.5返回假,否则返回真。但是他们又提到partition()函数返回的是第二个子类的起点,那么c到底是类别的数目还是第二个子类的起点呢?(最开始以为可以直接按照重叠率排序后选出重叠率超过.5的即可,何必用partition()那么麻烦,后来仔细想想,如果是按照重叠率排序,那么计算的是这些窗口和哪个窗口的重叠率?其实这里并没有哪个参考窗口,所以计算的重叠率其实是这些窗口两两之间的重叠率,然后将重叠率不超过0.5的归为一类,有点像聚类分析中的类内距离)后来找到partition()函数是在\core\operations.hpp中,里面提到“Thisfunction splits the input sequence or set into one or moreequivalence classes and returns the vector of labels - 0-basedclass indexes for each element”,所以这个函数应该是分成多个等价类,而不一定是两个,函数返回的c是等价类的数目,T是每个元素所属的类别标签。比如有ABCDEFG七个窗口,经过调用后ABC是一类,两两之间重叠率小于0.5DE是一类,FG是一类,DEABC的所有窗口两两之间重叠率超过0.5FGABC的所有窗口重叠率超过0.5,而DEFG之间的窗口两两之间重叠率也超过0.5。在聚类结束之后,把每个类别中的窗口信息进行平均,也即ABC所有窗口的x坐标求和再除以该类别数目3,以其作为聚类中心窗口的x坐标,其它信息包括y坐标、宽度、高度、保守相似度也按如此计算,并保存到cbbcconf中,也即cbbcconf的规模是聚类的数目。

接下来对cbb中每个聚类中心进行判断,如果有聚类中心满足如下条件一:“它与tbb(也即跟踪模块中光流跟踪得到的当前帧的跟踪区域)的重叠率小于0.5但是保守相似度却大于tbb的保守相似度,也即找到一个聚类中心离跟踪器的跟踪结果较远(重叠率小于0.5)但是比跟踪器更为可信(保守相似度高于tbb)”,那么记录满足条件一的聚类中心的数目,如果这个数目是1,也即只有一类满足,那么重新初始化跟踪器,并置lastvalid=false表示上一帧在跟踪器中是无效的(也即用检测器的检测结果对跟踪器的跟踪结果进行修正)。如果没有找到满足条件一的聚类中心,则找出检测到检测结果dbb中所有窗口与跟踪结果tbb重叠率超过0.7的,将其与tbb的信息一起累加再求平均,但是跟踪器tbb的权重较大,虽然tbb只有一个窗口,但是在计算平均值的时候是用10tbb加上其它dbb中的信息再除以总个数,所以跟踪器tbb权重大(一抵十)

总之,如果有跟踪到(tbb)并检测到(dbb),那么对检测到的结果聚类得到cbb(dbb->cbb),判断聚类中心与tbb的重叠率和可信度,如果两者重叠率低于0.5cbb可信度更高,那么用cbb修正tbb,也即用检测器修正跟踪器;如果重叠率接近,那么用检测器和跟踪器结果加权平均得到结果bbnext,其中跟踪器的权重更大。

3.2    如果没跟踪到但检测到

此时没有tbb只有dbb,置lastboxfoundlastvalidfalse表示上一帧的box无效。同样对dbb进行聚类得到cbb,如果聚类中心只有一个,将聚类中心的信息作为当前帧的处理结果bbnext,如果聚类中心有多个,丢弃检测器的检测结果。

对于综合模块,其实就是用跟踪模块和检测模块的结果进行综合考虑,前提是检测器有检测到结果dbb,对dbb进行聚类得到cbb,然后根据跟踪器的结果tbb的情况来分析:如果tbb存在,看tbbcbb的重叠率,如果重叠率低但是cbb可信度高,用cbb修正tbb;如果重叠率接近,将dbbcbb加权平均得到当前帧跟踪结果bbnext,但是跟踪器dbb权重较大;如果tbb不存在,看聚类结果tbb是否只有一个中心,是则以其为当前帧跟踪结果bbnext,如果不只一个中心则将聚类结果丢弃,当前帧没有跟踪到。

4.     学习模块learn(img2)

这个函数的输入是当前帧的灰度图,主要功能是进行学习。首先,用上一帧的跟踪区域lastbox在当前帧上截取,并调用getPattern()得到其pattern和方差,再调用NNConf()计算其与在线模型最近邻数据集的相关相似度conf,如果相关相似度太小、或者方差太小、或者被识别为负样本,则不进行训练,lastvalid置为false表示上一帧失效然后直接return

如果以上条件都不满足,则更新当前帧扫描窗口与上一帧窗口lastbox的重叠率,调用getOverlappingBoxes(lastbox,num_closest_update)更新best_boxgood­_boxesbad_boxesbbhull,此时bad_boxes中的规模为num_closest_update(值为10,从myParam.yml中获取),也即bad_boxes的规模一直不变。然后借助good_boxes结合generatePositiveData(img,num_warps_update)清空并重新生成pX(仍然存储仿射变换后所得的200个样本)fern中每棵树对pX200个正样本的编码。之后对bad_boxes中的样本进行判断,如果10棵树对bad_boxes中的样本得到的10个后验概率之和超过1,则将其作为Fern分类器fern_examples中的样本,用于后面对Fern分类器的阈值进行更新。

接下来更新近邻数据集nn_examples,将检测模块中通过方差分类器和Fern分类器的样本dtlastbox进行重叠率计算看是否不超过bad_overlap(固定值0.2myParam.yml中读取),不超过则可以将其放入近邻数据集nn_examples中,用于后面近邻分类器的更新训练和阈值的更新。

             这样,逐帧处理的过程也就结束了,如此每帧处理直到结束。

关于代码注释部分就不贴出来了,大部分是写得只有自己才看得懂的,就不献丑了,可以参考前面提到两个的博客

0 0
原创粉丝点击