庖丁解牛TLD

转载 2015年11月21日 19:53:54

一、庖丁解牛TLD——开篇

最近在网上多次看到有关Zdenek Kalal的TLD的文章,说他做的工作如何的帅,看了一下TLD的视频,感觉确实做的很好,有人夸张的说他这个系统可以和Kniect媲美,我倒是两者的工作可比性不大,实现的方法也不同。但这个哥们做的真的很棒,最可贵的是人家提供了源码可以下载。他相关的工作网上一搜一大片,推荐一个链接http://www.cvchina.net/article-22-1.html,再给个作者网站的链接http://info.ee.surrey.ac.uk/Personal/Z.Kalal/


看了他的demo视频顿时心潮澎湃,赶紧下载了他的源代码后又有些崩溃了。他的工作量还是很大的,得静下心来慢慢研究。直接看代码难免云里雾里的,先看看人家的论文吧。

这哥们这几年可真没少发paper啊,我比较关注他实现的算法。TLD即Tracking Learning Detector,我认为就是依据跟踪学习的目标检测。看了他08年发表的一篇文章,介绍了他的这个算法,那时候还把算法称为TMD(tracking、modeling、detection),他的tracking工作时基于Lucas-Kanade光流法的。modeling学习的过程有growing和pruning两方面的工作,可以正负反馈,得到较好的学习结果,对于他的学习过程,他在另一篇文章中又详细介绍了P-N learning这种学习算法。detection的部分用的是随机森林的机器学习办法,加上bootstarps。对于特征的选择,他提出了一种基于LBP特征的2bit BP特征。几篇文章下来,我已经有点晕乎了,这些算法都不是太熟悉,看来得结合代码一个个啃了。

代码正在一点点啃,有同样兴趣的朋友可以交流指导一下,不胜感激。


二、庖丁解牛TLD——初始化工作(为算法的准备)

我说的初始化,还不是算法的初始化工作,而是读入图像,响应键盘鼠标之类的工作。作者提供的代码中的工作包含了从摄像头读取和从文件中读取两种输入方案。这里介绍一下从文件输入的办法。因为OpenCV从视频读取图像序列的办法有很好的demo,我这里就不介绍摄像头的办法了。TLD下载后有一个文件夹是_input,里面存放着一组图片组,图片文件的名字为00001.png、00002.png....。我读取图片组的关键代码如下,这段代码具有普遍意义,可以移植到以后想读入图片组的任意程序中:

stringstream fileNameStream;
string sourceImageFileName;
for(int nFrame=0; nFrame<NUM; nFrame++)
{
    nFrame++;
    fileNameStream << "_input\\" << setw(5) << setfill('0') << nFrameNum << ".png";
    sourceImageFileName = fileNameStream.str();
    fileNameStream.clear();
    fileNameStream.str("");

    // 读取图像
    g_src = imread(sourceImageFileName);
}

这就实现了图片的读入工作,再参考camshiftdemo的办法实现了鼠标和键盘的响应。鼠标的响应就是得到目标区域的范围,用鼠标选中boundingbox。文件读进来了,目标区域boundingbox也得到了,接下来就是需要对算法进行研究了。

先介绍几个我研究过的心得,bbox文件夹下面的代码主要都是对boundingbox的处理。tld文件夹下面的存放的是主干的算法,从run_TLD入手,感觉就是对起始帧进行初始化工作,然后逐帧读入图片序列,进行算法处理。还是先分析初始化工作,作者的tldInitSource函数实现的就是基本的初始化,给一些变量赋值,开辟矩阵大小,这个没什么好讲的。tldInitFirstFrame文件完成的工作就是选中boundingbox,这个功能我已经通过鼠标的响应得到了boundingbox,也可以略过不细分析。重点的初始化工作是在tldInit里实现的,这个函数也是我接下来研究的重点,本人Matlab较差,真希望有高人指点啊,一起研究啊


三、庖丁解牛TLD——算法初始化

上一讲我提到对于算法的初始化工作主要是在tldInit这个函数里实现的。主要分为如下几大步骤,1)初始化Detector。2)初始化Trajectory。3)训练Detector

1)初始化Detector

其中bb_scan为扫描grid区域,该函数输入为boundingBox,输出为一系列的RectBox,是根据boundingBox的大小参数对待搜素区域选择一系列的box作为备选的跟踪区域,box的位置和尺度都有变化,和RectBox相应的尺度。但RectBox有6个参数,前4个分别为Rect的左上角坐标(x1,y1)和右下角坐标(x2,y2)。后两个参数求大神解释(PS:后来在fern函数里找到了解释,分别为指向对应尺度特征的指针位置、每一行box的数量——用在搜索邻近box)!对于这个函数内部我还有一个疑惑,就是对ntuples函数功能的使用,哎,怎奈Matlab语法都不熟悉,只能慢慢啃了,感觉作者这里就是把RectBox的左上角的所有可能的坐标值传入该函数,得到左上角坐标位置的全部组合(不知道理解对了没)。

接下来的工作时特征的初始化,是在tldGenerateFeature函数里实现的。这个函数相对独立,作者这里为了产生效果较好的随机特征真是煞费苦心,输入的参数有两个,一个是nTREE = 10,一个是nFEATURE = 13。输出为nTREE组特征,每组特征为nFEATURE个点对,每一个点对有4个参数,分别两点坐标(x1,y1),(x2,y2),取值范围为(0~1)其中第一个点的分辨率为0.1,还不太明白这样设计的原因,待进一步分析代码,有高人指点一下更好。值得注意的是产生的点对不是横坐标相同x1 = x2,就是纵坐标相同y1 = y2。这里用图片显示一组特征,线段的两个端点


下一步工作为初始化detector。这个功能是用强大的fern函数写的,该函数有多个功能,根据传入参数的标志分别可以实现clear操作、init操作、update操作、evaluate操作、detect操作、get pattern操作。fern函数是用c写的,混合编程没有弄的太明白,还没能调试一下看看,只能看代码猜。在初始化detector的工作里,用到的是init操作。

2)初始化Trajectory

这部分没有什么要说明的,都是些零碎的初始化工作,matlab里面对一些必要的变量开辟一些空间和定义一些变量的值。具体分析Trajectory的工作的时候可以具体再分析

3)训练Detector

首先得到Target,作者注释说该Target只是用来显示,有待我后续验证。得到Target要调用函数img_patch,img_patch函数是获得一幅图像中目标区域box的像素信息patch。

接下来产生正样本数据集,调用tldGeneratePositiveData。其中第二个参数为RectBox和box的重复区域比例信息,保存在overlap参数中,由函数bb_overlap得到。tldGeneratePositiveData函数首先根据overlap的比例信息选出重复区域比例大于60%并且前num_closet  = 10个的最接近box的RectBox,相当于对RectBox进行筛选。并通过bb_hull函数得到这些RectBox的最大边界。接下来的工作比较重要,要得到Pattern,调用的函数为tldGetPattern。初始化的工作就是对最接近box的RectBox区域得到其patch,然后调用tldPatch2Pattern将像素信息转换为Pattern,具体的说就是归一化RectBox对应的patch的size(放缩至patch_size = 15*15),将2维的矩阵变成一维的向量信息,然后将向量信息均值设为0,调整为zero mean and unit variance(ZMUV),这个过程调用函数tldPatch2Pattern实现。接下来处理RectBox最大边界的模糊信息,再次用到img_patch函数,但这次调用的函数有很大的不同,还没太理解作者要做什么啊,怎么感觉还有平移旋转矩阵都出来了,晕啦(求高人指点)。该函数最后返回3个参数,pX为处理后的RectBox最大边界处理后的像素信息,pEx最近邻的RectBox的Pattern,bbP0为最近邻的RectBox。

然后再产生负样本数据tldGenerateNegativeData。得到远离box(重复区域比例小于20%)的num_patches = 100个Pattern保存到nX中,随机选中num_patches = 100个RectBox得到对应的patch保存到nEx中。这里调用了fern(5),即该函数的get pattern操作。

接下来对负样本进行分类,分类到训练集Training Set和验证集Validation Set中去。

接下来使用Training Set进行训练,先调用fern(2),更新,然后调用tldTrainNN最近邻训练数据。

接下来评估验证集Validation Set的阈值。调用tldNN验证。

至此,初始化的工作基本完成,限于本人水平有限,只能先对函数有个大概的认识,深深觉得先要静下心来把训练的算法搞清楚,再回过头来再看一编代码。


四、 庖丁解牛TLD——Tracking解析

前几节都是根据作者的程序流程一步步介绍作者的工作,感觉只是对代码的一个注释,这次换一个思路,一部分一部分啃,作者的工作主要就是3部分么,tracking,learning,detection。

这次先介绍Tracking的工作。对于Tracking,作者主要使用的是他提出的Forward-Backward Error的办法,使用Lucas-Kanade光流法跟踪,对跟踪的结果,用Forward-Backward Error做反馈,求FB error的结果与原始位置的欧式距离,把距离过大的跟踪结果舍弃,他把这种利用FB error舍弃坏值的跟踪方法叫做Median Flow,是把欧式距离集合中较大的50%的那些跟踪结果舍弃。作者在他的文章Forward-Backward Error:Automatic Detection of Tracking Failures里提到用FB+NCC(交叉验证)的方案,可以使跟踪的结果最佳。作者的Tracking的办法就是根据我以上介绍的流程实现的。接下来结合代码再详细剖析一下

先用bb_points函数在box中均匀采样10*10个点,注意作者这里设置了采样点的区域比box的区域少一圈边界,边界为5,在后面我会介绍作者这里的独到用心。然后调用混合编程的lk函数实现lucas-Kanade光流法跟踪,得到的结果有为这100个点的lk结果,前两个参数为利用l-k方法得到的点当前的跟踪位置坐标,第三个参数是利用NCC把跟踪预测的结果周围取10*10的小图片与原始位置周围10*10(这里取10*10,有心的朋友应该笑了,为什么作者之前在bb_points函数里要设置个边界5,原来是防止越界哦)的小图片(使用函数getRectSubPix得到)进行模板匹配(调用matchTemplate),再对匹配的结果归一化,把这个结果保存在第三个参数中,第四个参数为FB error的欧氏距离。这个lk函数过程中有很多参数可以设置,对最终的结果我想应该应该也是有的,有待实验验证。接下来就是利用作者提出的Median Flow,得到NCC和FB error结果的中值,分别去掉中值一半的跟踪结果不好的点,利用这一半(其实不到50%)的跟踪点输入函数bb_predict函数中预测bounding box在当前帧的位置和大小。

这基本就是Tracking工作的主要部分了,至于被遮挡的tracking(tldTrack_occlusion),作者进行了单独处理,下一次再分析。

PS:很感谢最近有些网友与我一起研究TLD,不过本人能力不足,很多东西还是不理解,对于作者detection和learning的工作,感觉那部分的代码实在好比天书,没法拿出来和大家交流了,希望有识之士也能写出来,和大家分享~~



五、庖丁解牛TLD——井底之蛙啦~

随着和我交流TLD的朋友越来越多,我渐渐的知道的也多了,才发现我研究的结果只是沧海一粟。

这里先膜拜一下Alan Torres大神,他已经用c++把TLD重新写好了,而且代码很规范。他设计的理念有:

1. depends *only* on OpenCV (2.3) 
2. no Matlab! 
3. easy to compile and run (on linux, work in progress on OSX and windows) 
4. fast! (and more potential to be much faster) 
5. No Matlab! (did I say no matlab?) 

没有matlab,多平台,更快的速度。真好,就是我想做的,不过他现在这个程序,在我这电脑上实现速度还不行。他代码的下载地址为https://github.com/alantrrs/OpenTLD,好像打不开,我是在这上面得到的https://github.com/arthurv/OpenTLD。不过是个Linux版本的。大家这么强,改改肯定就可以在xp下跑起来了,反正我是搞定了。

附上他软件的设计接口。真是赏心悦目啊,不得不说人家做的东西很规范,惭愧惭愧


看不清还是下载下来大家自己看咯,不好意思,我不知道怎么能传上去看得清晰

从他这个设计图也可以看出来我之前几讲分析的流程还是可以接受的,init部分和track部分是相对独立的。而比较复杂的是learning的部分和detect部分。下一步主攻这两部分了。学习的越深入,越是发现自己很挫,都没信心继续写下去了。硬着头皮装大葱吧~


出处:http://blog.csdn.net/yang_xian521/article/details/6952870

举报

相关文章推荐

手机游戏优化技巧

手机游戏优化技巧:     a.减少内存使用:      —尽可能避免使用对象:具备某种意义功能时才使用对象,否则用基本数据类型;      —重用对象:重用对象(初始化...

TLD学习(2)-调试lk.cpp

All Right。 step1. 现在我们有OpenTLD-Master的代码放在:C:\Users\Administrator\Documents\MATLAB\OpenTLD-master\me...
  • zinnc
  • zinnc
  • 2015-11-23 23:16
  • 909

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

TLD学习(1)-搭建环境

在跑demo的过程中出现以下错误。 Error: 无法找到"Program Files..." 解决办法:include和libpath中的opencv路径不能有空格。将opencv的安装包ext...
  • zinnc
  • zinnc
  • 2015-07-25 15:35
  • 1757

64位Mex文件在Matlab 2014b和Visual Studio 2013中的调试

网上有很多关于VS调试mex文件的教程,不过他们的VS和Matlab版本都不高,一般得到的都是mexw32文件,并且还有些地方有错误。楼主借鉴了很多人的博客,并自己在Matlab 2014b和Visu...

OpenTLD 未完成 - 虎头

TLD是一种算法的简称,原作者把它叫做Tracking-Learning-Detection。搞视觉的人看到这个名字都会吓一跳,很ambitious的计划。是09年的工作,不算太久,不过也不太新。网上...

庖丁解牛TLD(四)——Tracking解析

前几节都是根据作者的程序流程一步步介绍作者的工作,感觉只是对代码的一个注释,这次换一个思路,一部分一部分啃,作者的工作主要就是3部分么,tracking,learning,detection。 这次...

庖丁解牛TLD(一)——开篇

最近在网上多次看到有关Zdenek Kalal的TLD的文章,说他做的工作如何的帅,看了一下TLD的视频,感觉确实做的很好,有人夸张的说他这个系统可以和Kniect媲美,我倒是两者的工作可比性不大,实...

庖丁解牛TLD(三)——算法初始化 .

转自:http://blog.csdn.net/yang_xian521/article/details/6957732 上一讲我提到对于算法的初始化工作主要是在tldInit这个函数里实现的。主要...

庖丁解牛TLD(五)——井底之蛙啦~

随着和我交流TLD的朋友越来越多,我渐渐的知道的也多了,才发现我研究的结果只是沧海一粟。 这里先膜拜一下Alan Torres大神,他已经用c++把TLD重新写好了,而且代码很规范。他设计的理念有:...

庖丁解牛TLD(三)——算法初始化

上一讲我提到对于算法的初始化工作主要是在tldInit这个函数里实现的。主要分为如下几大步骤,1)初始化Detector。2)初始化Trajectory。3)训练Detector 1)初始化Dete...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)