TLD源码深度分析:初始化模块
2015-09-29 08:59
232 查看
对于TLD的研究,已有些时日。最开始的时候看Zdenek Kalal的论文,但是有很多啃不动的地方。看完只觉得了解了个大体框架,很多地方都不明白。后来,又看完了各位牛人的分析及讲解(大部分已转载到本博客,大家可以查阅),受益匪浅!但是觉得对很多问题还是不明白!好在网友【冷月无心】给我推荐了C++版本作者的论文,作者分析得很细,看完很受用,解除了很多困惑!最近,打算再根据C++源码深入地走一遍,并把源码功能详细分享给大家!希望后面学习使用TLD算法的朋友通过我的分析,能够不走那么多弯路,也欢迎朋友们和我一起讨论!废话就说到这里,开始分享。。。
1. buildGrid(frame1,box)
输入:
当前帧图像:frame1
初始边界框:box
输出:
所有边界框及其信息:vector<BoundingBox> grid
描述:
使用滑动窗法对整帧图像,按从上到下、从左到右的顺序,取边界框并记录其大
小、位置、尺度、与初始边界框(第一帧中手工所取)重叠度。其中,尺度取初
始边界框的1.2(S次方)倍,S取值为-10、-9、…、9、10。
2. getOverlappingBoxes(box,num_closest_init)
输入:
初始边界框:box
欲得到good_box(与初始边界框最相似的box)的个数:num_closest_init
输出:
最相似边界框:best_box
最相似的num_closest_init个边界框:vector<int>good_boxes
不重叠边界框:vector<int> bad_boxes
描述:
将所有边界框中,与初始框box重叠度最高的边界框信息赋给best_box。把所有重
叠度高于0.6的边界框归类到good_boxes;把所有重叠度低于阈值bad_overlap(读
取自parameters.yml,论文中为0.2)的边界框归类到bad_boxes。如果good_boxes
中边界框个数多于num_closest_init个,则从中取重叠率最高num_closest_init
个边界框good_boxes。
函数末尾调用getBBHull()函数的目的是,得到good_boxes中所有边界框能覆盖到
的最大边界。
3. classifier.prepare(scales):函数位于FerNNClassifier.cpp中。
输入:
所有有效尺度:scales
输出:
所有待获取2bitBP特征(位置):features
阈值:0.5*nstructs
初始化Posteriors、pCounter、nCounter
描述:
对特征提取的位置(均匀任选图像块中两点)进行选取(共计:蕨个数*特征位数
(二进制数位数)*尺度大小(21) 个),声明并初始化每个蕨的可信度、正样
本计数器、负样本计数器。
4. generatePositiveData(frame1,num_warps_init)
输入:
当前帧图像:frame1
图像块变换次数:num_warps_init
最相似边界框:best_box
相似边界框:good_boxes
输出:
集成分类器正样本集:pX
best_box图像块处理结果:pEx
描述:
getPattern(frame(best_box),pEx,mean,stdev):
frame(best_box)为该帧图像中best_box边界框对应图像块;将该图像块resize
为15*15的大小;计算该图像的均值、方差,分别存放到mean、stdev中;将该
图像块与均值作差的结果存于pEx中。
generator(frame,pt,warped,bbhull.size(),rng):
pt为good_boxes最大边界框(2中有提到)的中心点;该函数对每个good_box对
应图像块仿射变换:±1%范围的偏移,±1%范围的尺度变化,±10%范围的平面
内旋转,并且在每个像素上增加方差为5的高斯噪声(确切的大小是在指定的范
围内随机选择的),共计num_warps_init种。
关于该部分,详情见《关于PatchGenerator类 》
对每一仿射图像块计算特征,并存于pX中。
classifier.getFeatures(patch,grid[idx].sidx,fern):
对尺度grid[idx].sidx下的图像块patch,使用3中定义的位置计算特征,并存于
fern中。
注意:
原C++版本作者此处代码有误。没有用到变换后的图像块。
(也有朋友说没有错,待验证,但修改的一定是正确的)
修改方法一:
将generator(frame,pt,warped,bbhull.size(),rng);
修改成generator(img,pt,img,frame.size(),rng);
修改方法二:
将整个for循环内容修改为:
for (int i=0;i<num_warps;i++)
{
if(i == 0)
{
for (int b = 0; b < good_boxes.size(); b ++)
{
idx=good_boxes;
patch = img(grid[idx]);
classifier.getFeatures(patch, grid[idx].sidx, fern);
pX.push_back(make_pair(fern,1));
}
}
else
{
generator(img,pt,warped,bbhull.size(),rng);
for (int b = 0; b < good_boxes.size(); b ++)
{
idx=good_boxes[b];
Rect region(grid[idx].x-bbhull.x, grid[idx].y - bbhull.y, grid[idx].width, grid[idx].height);
patch = warped(region);
classifier.getFeatures(patch, grid[idx].sidx, fern);
pX.push_back(make_pair(fern,1));
}
}
}
[b]5. meanStdDev(frame1(best_box),mean,stdev)
输入:
最相似图像块:frame1(best_box)
输出:
图像块均值:mean
图像块标准差:stdev
描述:
计算best_box边界框对应图像块的均值和标准差,并分别存于mean、stdev中。
6. integral(frame1,iisum,iisqsum)
输入:
整帧图像:frame1
输出:
积分图:iisum
平方积分图:iisqum
描述:
对整帧图像计算积分图、图像平方的积分图
7. generateNegativeData(frame1)
输入:
整帧图像:frame1
模板个数:bad_patches
所有不重叠边界框:bad_boxes
积分图:iisum
平方积分图:iisqum
输出:
负样本特征集:nX
负样本模板集:nEx
描述:
random_shuffle(bad_boxes.begin(),bad_boxes.end()):
随机打乱bad_boxes的顺序。
取所有bad_boxes边界框中,方差值高于best_box图像块阈值一半的图像块,计算
特征并保存到nX中。(why?:因为检测的时候,方差分类器位于集合分类器的前一
级。也就是说,方差低于0.5倍best_box图像块方差的部分都被排除,如果在此处
将其作为负样本是没有意义的,甚至会降低集合分类器的检测效果。)
任取bad_patches个图像块作为负模板。
注意:
原程序版本有错,对方差分类器方差重复取50%。
将if (getVar(grid[idx],iisum,iisqsum)<var*0.5f)
修改成if (getVar(grid[idx],iisum,iisqsum)<var*1.0f)
8. classifier.trainF(ferns_data,2)
输入:
已混合打乱的正负样本特征数据:ferns_data
输出:
分类器模型:任何特征对应可信度(该图像块为正样本的概率):posteriors
描述:
统计P/N约束被使用的次数,来计算一个特征的可信度
更多详情见《集成分类器》
9. classifier.trainNN(nn_data)
输入:
已混合打乱的正负样本模板数据:nn_data
输出:
筛选出的模板:pEx、nEx
描述:
通过计算自相关系数NCC筛选模板
更多详情见《最近邻分类器》
10. classifier.evaluateTh(nXT,nExT)
输入:
负样本随机蕨测试集:nXT
负样本模板测试集:nExT
输出:
更新后的随机蕨阈值:thr_fern
更新后的模板NCC阈值:thr_nn
更新后的有效性判断(P/N学习)阈值:thr_nn_valid
描述:
对所有负样本随机蕨测试集,计算其随机蕨可信度,若最大值大于预设阈值
thr_fern,则用该最大值替换更新;对所有负样本模板测试集,计算其NCC系数,
若最大值大于预设阈值thr_nn,则用该最大值替换更新;若最后更新得到的thr_nn
大于预设thr_nn_valid,则替换更新thr_nn_valid。
1. buildGrid(frame1,box)
输入:
当前帧图像:frame1
初始边界框:box
输出:
所有边界框及其信息:vector<BoundingBox> grid
描述:
使用滑动窗法对整帧图像,按从上到下、从左到右的顺序,取边界框并记录其大
小、位置、尺度、与初始边界框(第一帧中手工所取)重叠度。其中,尺度取初
始边界框的1.2(S次方)倍,S取值为-10、-9、…、9、10。
2. getOverlappingBoxes(box,num_closest_init)
输入:
初始边界框:box
欲得到good_box(与初始边界框最相似的box)的个数:num_closest_init
输出:
最相似边界框:best_box
最相似的num_closest_init个边界框:vector<int>good_boxes
不重叠边界框:vector<int> bad_boxes
描述:
将所有边界框中,与初始框box重叠度最高的边界框信息赋给best_box。把所有重
叠度高于0.6的边界框归类到good_boxes;把所有重叠度低于阈值bad_overlap(读
取自parameters.yml,论文中为0.2)的边界框归类到bad_boxes。如果good_boxes
中边界框个数多于num_closest_init个,则从中取重叠率最高num_closest_init
个边界框good_boxes。
函数末尾调用getBBHull()函数的目的是,得到good_boxes中所有边界框能覆盖到
的最大边界。
3. classifier.prepare(scales):函数位于FerNNClassifier.cpp中。
输入:
所有有效尺度:scales
输出:
所有待获取2bitBP特征(位置):features
阈值:0.5*nstructs
初始化Posteriors、pCounter、nCounter
描述:
对特征提取的位置(均匀任选图像块中两点)进行选取(共计:蕨个数*特征位数
(二进制数位数)*尺度大小(21) 个),声明并初始化每个蕨的可信度、正样
本计数器、负样本计数器。
4. generatePositiveData(frame1,num_warps_init)
输入:
当前帧图像:frame1
图像块变换次数:num_warps_init
最相似边界框:best_box
相似边界框:good_boxes
输出:
集成分类器正样本集:pX
best_box图像块处理结果:pEx
描述:
getPattern(frame(best_box),pEx,mean,stdev):
frame(best_box)为该帧图像中best_box边界框对应图像块;将该图像块resize
为15*15的大小;计算该图像的均值、方差,分别存放到mean、stdev中;将该
图像块与均值作差的结果存于pEx中。
generator(frame,pt,warped,bbhull.size(),rng):
pt为good_boxes最大边界框(2中有提到)的中心点;该函数对每个good_box对
应图像块仿射变换:±1%范围的偏移,±1%范围的尺度变化,±10%范围的平面
内旋转,并且在每个像素上增加方差为5的高斯噪声(确切的大小是在指定的范
围内随机选择的),共计num_warps_init种。
关于该部分,详情见《关于PatchGenerator类 》
对每一仿射图像块计算特征,并存于pX中。
classifier.getFeatures(patch,grid[idx].sidx,fern):
对尺度grid[idx].sidx下的图像块patch,使用3中定义的位置计算特征,并存于
fern中。
注意:
原C++版本作者此处代码有误。没有用到变换后的图像块。
(也有朋友说没有错,待验证,但修改的一定是正确的)
修改方法一:
将generator(frame,pt,warped,bbhull.size(),rng);
修改成generator(img,pt,img,frame.size(),rng);
修改方法二:
将整个for循环内容修改为:
for (int i=0;i<num_warps;i++)
{
if(i == 0)
{
for (int b = 0; b < good_boxes.size(); b ++)
{
idx=good_boxes;
patch = img(grid[idx]);
classifier.getFeatures(patch, grid[idx].sidx, fern);
pX.push_back(make_pair(fern,1));
}
}
else
{
generator(img,pt,warped,bbhull.size(),rng);
for (int b = 0; b < good_boxes.size(); b ++)
{
idx=good_boxes[b];
Rect region(grid[idx].x-bbhull.x, grid[idx].y - bbhull.y, grid[idx].width, grid[idx].height);
patch = warped(region);
classifier.getFeatures(patch, grid[idx].sidx, fern);
pX.push_back(make_pair(fern,1));
}
}
}
[b]5. meanStdDev(frame1(best_box),mean,stdev)
输入:
最相似图像块:frame1(best_box)
输出:
图像块均值:mean
图像块标准差:stdev
描述:
计算best_box边界框对应图像块的均值和标准差,并分别存于mean、stdev中。
6. integral(frame1,iisum,iisqsum)
输入:
整帧图像:frame1
输出:
积分图:iisum
平方积分图:iisqum
描述:
对整帧图像计算积分图、图像平方的积分图
7. generateNegativeData(frame1)
输入:
整帧图像:frame1
模板个数:bad_patches
所有不重叠边界框:bad_boxes
积分图:iisum
平方积分图:iisqum
输出:
负样本特征集:nX
负样本模板集:nEx
描述:
random_shuffle(bad_boxes.begin(),bad_boxes.end()):
随机打乱bad_boxes的顺序。
取所有bad_boxes边界框中,方差值高于best_box图像块阈值一半的图像块,计算
特征并保存到nX中。(why?:因为检测的时候,方差分类器位于集合分类器的前一
级。也就是说,方差低于0.5倍best_box图像块方差的部分都被排除,如果在此处
将其作为负样本是没有意义的,甚至会降低集合分类器的检测效果。)
任取bad_patches个图像块作为负模板。
注意:
原程序版本有错,对方差分类器方差重复取50%。
将if (getVar(grid[idx],iisum,iisqsum)<var*0.5f)
修改成if (getVar(grid[idx],iisum,iisqsum)<var*1.0f)
8. classifier.trainF(ferns_data,2)
输入:
已混合打乱的正负样本特征数据:ferns_data
输出:
分类器模型:任何特征对应可信度(该图像块为正样本的概率):posteriors
描述:
统计P/N约束被使用的次数,来计算一个特征的可信度
更多详情见《集成分类器》
9. classifier.trainNN(nn_data)
输入:
已混合打乱的正负样本模板数据:nn_data
输出:
筛选出的模板:pEx、nEx
描述:
通过计算自相关系数NCC筛选模板
更多详情见《最近邻分类器》
10. classifier.evaluateTh(nXT,nExT)
输入:
负样本随机蕨测试集:nXT
负样本模板测试集:nExT
输出:
更新后的随机蕨阈值:thr_fern
更新后的模板NCC阈值:thr_nn
更新后的有效性判断(P/N学习)阈值:thr_nn_valid
描述:
对所有负样本随机蕨测试集,计算其随机蕨可信度,若最大值大于预设阈值
thr_fern,则用该最大值替换更新;对所有负样本模板测试集,计算其NCC系数,
若最大值大于预设阈值thr_nn,则用该最大值替换更新;若最后更新得到的thr_nn
大于预设thr_nn_valid,则替换更新thr_nn_valid。
相关文章推荐
- TLD初始化模块实现流程
- DOM2定位与高宽类属性专题学习【DOM专题学习系列(一)】
- 使用android快速开发框架afinal的FinalDb操作android数据库
- 物联网通信协议介绍
- 【Espruino】NO.03 从点灯开始
- Python 网页爬虫
- iOS 推送证书制作 命令行部分记录
- webservice工作原理
- iOS基础-网络-监测网络状态
- Android4.4KitKat支持u盘功能
- afinal 上传文件服务端接受参数为空
- odoo8新API之Environment
- sqlserver学习--SQL语句
- 不拼颜值拼实力—讲述CTO女神奋斗史
- CocoaPods—使用CocoaPods删除已经配置的类库和移除CocoaPods
- javascript:使用代理绑定事件
- uva 10934(dp)
- Android的快速开发框架 afinal
- iwpriv
- 友元类