计算机视觉之目标跟踪——论文Learning to Track at 100 FPS with Deep Regression Networks
2017-03-13 18:01
746 查看
论文解读
模型
输入
输出
模型结构
训练
motion model
训练数据
实现
说明
源码解读
srchelper文件夹
bounding_boxcpp
image_proccpp
srctrain文件夹
example_generatorcpp
tracker_trainercpp
traincpp
问题
Learning to Track at 100 FPS with Deep Regression Networks,
David Held, Sebastian Thrun, Silvio Savarese,
European Conference on Computer Vision (ECCV), 2016 (In press)
作者一直在强调的是本模型可以离线训练,这样可以从大量的训练数据中学到数据的分布;而且在使用的时候由于只有正向的一个推理过程,在GPU上的速度可以达到100fps(其他基于神经网络的跟踪器速度在0.8fps-15fps之间,性能最好的神经网络跟踪器的速递为1fps。);另外大量的训练数据也使得模型的泛化性能比较好,可以跟踪其他没有见过的物体。需要补充一点,速度的提升的原因除了离线训练还有模型本身的原因,本文提出的模型是回归模型,网络只需正向跑一次,而其他深度跟踪模型本身是分类模型,需要对多个候选patches进行打分,以得分最高者作为目标。
那么问题来了,不同图片上的目标的BBox大小形状不一,导致截图不一样,但是神经网络的输入要求固定大小,怎么办呢?对截图进行reshape处理,缩放到一样大小。
为什么要在当前图片中以c为中心截宽k2w高k2h截图?是因为作者简化了问题,认为当物体运动速度不是特别快时是会出现在这个区域中的。那么问题来了,如果运动速度过快怎么办?作者只是说可以增大搜索区域的范围,但是这样的话超参k就是动态的了,需要先判断物体运动速度,然后再选择k;或者结合其他的跟踪方法,这一点作者留在了未来工作中。这个搜索区域对于遮挡情况也处理不了,这一点不是很理解,希望大家指教。
三层4096全连接层:使用ReLU非线性函数,层之间加上dropout层
c′x=cx+w⋅Δx(1)
c′y=cy+h⋅Δy(2)
其中w和h分别为上一张图片的宽和高。Δx和Δy两个随机变量,作者发现这两个随机变量服从均值为0的Laplace分布。
对BBox的大小变化建立以下模型:
w′=w⋅γw(3)
h′=h⋅γh(4)
其中w′和h′是当前BBox的宽和高。γw和γh是两个随机变量,可以用均值为1的Laplace分布建模。
那对于一张标明目标的图片,怎么产生两张图片呢?通过查看作者的实现发现,深度回归网络的两个输入是一样的,都是对这幅图片的填充完全截图。而对于用random crop生成的人造数据,是对图片的BBox进行变换,然后再根据新BBox在图片上进行截图,得到人造当前截图。
对于视频的上一图片和当前图片,除了前面介绍的真实截图输入,我们也对当前图片进行random crop生成数据(上一张图片的截图保持不变)。具体来说,根据Laplace分布随机采样位移Δx、Δy和大小变化γw、γh,然后对当前图片的BBox进行变化,得到新的BBox,再根据新的BBox在当前图片上进行完全填充截图。???一头黑线啊,怎么可以在当前图片的BBox上进行变换呢?不是应该在上一张图片的BBox上进行变化,然后再在当前图片上截图吗?
这里简单地阅读一下源码以便后面可以对代码做些修改。
截图、完全截图、填充完全截图、填充完全变换截图:在截图的时候,可能会出现截图范围超过图片的情况。这时我们把在图片内部的部分称为截图;整个截图(包括超出部分)称为完全截图;超出部分用黑色填充称为填充完全截图;对目标BBox做变换后再截图称为填充完全变换截图。
全局变量:
类BoundingBox:
成员变量:
成员函数:
参数:无
返回:
参数:
返回:无
image_proc.cpp:
函数:
参数:
参数:
返回:
参数:
返回:
类ExampleGenerator:处理两张图片,生成训练数据,包括真实样本和生成样本
成员变量:
成员函数:
构造函数:
参数
返回:无
参数:
返回:无
参数:
返回:无
参数:
返回:无
参数:
返回:无
参数:
返回:
tracker_trainer.cpp:
变量:
类TrackerTrainer:
成员变量:
成员函数:
参数:
返回:
参数:
返回:
参数:
返回:
train.cpp
变量:
函数:
参数:
返回:
参数:
返回:
在Regressor::Estimate()函数中会对数据reshape到神经网络需要的大小。
模型
输入
输出
模型结构
训练
motion model
训练数据
实现
说明
源码解读
srchelper文件夹
bounding_boxcpp
image_proccpp
srctrain文件夹
example_generatorcpp
tracker_trainercpp
traincpp
问题
Learning to Track at 100 FPS with Deep Regression Networks,
David Held, Sebastian Thrun, Silvio Savarese,
European Conference on Computer Vision (ECCV), 2016 (In press)
论文解读
本文采用深度学习回归模型GOTURN(Generic Object Tracking Using Regression Networks)解决单目标跟踪问题。单目标跟踪问题的难点在于物体的平移、旋转、大小变化、视角变化、明暗变化、变形以及遮挡等情况。作者一直在强调的是本模型可以离线训练,这样可以从大量的训练数据中学到数据的分布;而且在使用的时候由于只有正向的一个推理过程,在GPU上的速度可以达到100fps(其他基于神经网络的跟踪器速度在0.8fps-15fps之间,性能最好的神经网络跟踪器的速递为1fps。);另外大量的训练数据也使得模型的泛化性能比较好,可以跟踪其他没有见过的物体。需要补充一点,速度的提升的原因除了离线训练还有模型本身的原因,本文提出的模型是回归模型,网络只需正向跑一次,而其他深度跟踪模型本身是分类模型,需要对多个候选patches进行打分,以得分最高者作为目标。
模型:
输入:
GOTURN是按帧处理视频的,根据上一张图中目标的位置来判断当前图片的目标位置,本质上还是在处理图片。假设上一张图片目标以c=(cx,cy)为中心,宽w高h,那么以c为中心宽k1w高k1h的截图作为神经网络的一个输入。并在当前图片中同样以c为中心截宽k2w高k2h的图,我们称这个截图为搜索区域,是神经网络的另一个输入。那么问题来了,不同图片上的目标的BBox大小形状不一,导致截图不一样,但是神经网络的输入要求固定大小,怎么办呢?对截图进行reshape处理,缩放到一样大小。
为什么要在当前图片中以c为中心截宽k2w高k2h截图?是因为作者简化了问题,认为当物体运动速度不是特别快时是会出现在这个区域中的。那么问题来了,如果运动速度过快怎么办?作者只是说可以增大搜索区域的范围,但是这样的话超参k就是动态的了,需要先判断物体运动速度,然后再选择k;或者结合其他的跟踪方法,这一点作者留在了未来工作中。这个搜索区域对于遮挡情况也处理不了,这一点不是很理解,希望大家指教。
输出:
跟踪目标在搜索区域中的相对位置,左上角及右下角的位置(x1,y1,x2,y2)。注意作者设置的坐标范围不是在[0,1]之间,而是乘以扩展因子变换到[0,10]之间,不知道为什么?模型结构:
五层卷积层:CaffeNet结构的前五层三层4096全连接层:使用ReLU非线性函数,层之间加上dropout层
训练
损失函数为L1距离。motion model
作者针对视频中物体的运动情况进行统计,发现物体由上一帧运动到下一帧的过程是有规律的。假设上一张图片的BBox的中心点为c,当前图片BBox的中心点为c′x,我们为两者建立以下模型:c′x=cx+w⋅Δx(1)
c′y=cy+h⋅Δy(2)
其中w和h分别为上一张图片的宽和高。Δx和Δy两个随机变量,作者发现这两个随机变量服从均值为0的Laplace分布。
对BBox的大小变化建立以下模型:
w′=w⋅γw(3)
h′=h⋅γh(4)
其中w′和h′是当前BBox的宽和高。γw和γh是两个随机变量,可以用均值为1的Laplace分布建模。
训练数据
训练数据既有视频,还由图像。使用大量图片数据进行训练可以增加模型的泛化能力,追踪更多种类的目标。那对于一张标明目标的图片,怎么产生两张图片呢?通过查看作者的实现发现,深度回归网络的两个输入是一样的,都是对这幅图片的填充完全截图。而对于用random crop生成的人造数据,是对图片的BBox进行变换,然后再根据新BBox在图片上进行截图,得到人造当前截图。
对于视频的上一图片和当前图片,除了前面介绍的真实截图输入,我们也对当前图片进行random crop生成数据(上一张图片的截图保持不变)。具体来说,根据Laplace分布随机采样位移Δx、Δy和大小变化γw、γh,然后对当前图片的BBox进行变化,得到新的BBox,再根据新的BBox在当前图片上进行完全填充截图。???一头黑线啊,怎么可以在当前图片的BBox上进行变换呢?不是应该在上一张图片的BBox上进行变化,然后再在当前图片上截图吗?
实现
作者在Github上上传了实现源码https://github.com/davheld/GOTURN。在测试集上跑了一下,跟踪速度非常快,但是会出现目标错误、跟踪范围过大的情况,而且目标错误出现了多次。这里简单地阅读一下源码以便后面可以对代码做些修改。
说明
首先对解读源码过程中用到的词语做一下说明:截图、完全截图、填充完全截图、填充完全变换截图:在截图的时候,可能会出现截图范围超过图片的情况。这时我们把在图片内部的部分称为截图;整个截图(包括超出部分)称为完全截图;超出部分用黑色填充称为填充完全截图;对目标BBox做变换后再截图称为填充完全变换截图。
源码解读
src/helper文件夹
bounding_box.cpp:全局变量:
kContextFactor = 2:为目标填充多少上下文,BBox大小的相对值
kScaleFactor = 10:基于神经网络的输出值范围,缩放BBox的坐标
use_coordinates_output:决定在初始化BoundingBox时传入的浮点数向量代表的坐标含义。为true时,神经网络输出(x1, y1, x2, y2);为false时,输出(center_x, center_y, width, height)
类BoundingBox:
成员变量:
x1_, y1_, x2_, y2_:BBox的坐标
scale_factor_:输入神经网络前缩放BBox的坐标
成员函数:
double compute_output_width() const:计算截图的宽,为kContextFactor * bbox_width。
参数:无
返回:
output_weight:截图的宽
double edge_spacing_x() const:当截图的左边界超过图片的左边界时,超出的长度。如果不超出,则返回0。
void Recenter(const BoundingBox& search_location, const double edge_spacing_x, const double edge_spacing_y, BoundingBox* bbox_gt_recentered) const:计算BBox相对搜索区域(填充完全变换截图)的位置。
void Scale(const cv::Mat& image, BoundingBox* bbox_scaled) const:根据图片的大小规范化BBox,即不再以像素点长度作为坐标值而是以和图片之间的比例。先缩放BBox的坐标使其位于[0,1]之间,然后再乘以scale_factor_,使其到[0,scale_factor_]之间。
参数:
image:
bbox_scaled:就是调用此函数的BoundingBox对象,现在保存的坐标值是在[0, scale_factor_]之间,scale_factor_在创建BoundingBox对象时初始化为kScaleFactor。
返回:无
void Shift(const cv::Mat& image, const double lambda_scale_frac, const double lambda_shift_frac, const double min_scale, const double max_scale, const bool shift_motion_model, BoundingBox* bbox_rand) const:根据Laplace分布得到BBox附近的一个BBox保存在bbox_rand中
image_proc.cpp:
函数:
void CropPadImage(const BoundingBox& bbox_tight, const cv::Mat& image, cv::Mat* pad_image):在BBox周围截图。
参数:
bbox_tight:BBox
image:整幅图片
pad_image:保存截图
void CropPadImage(const BoundingBox& bbox_tight, const cv::Mat& image, cv::Mat* pad_image, BoundingBox* pad_image_location, double* edge_spacing_x, double* edge_spacing_y):基于BBox截图,并增加一些padding。根据BBox进行截图后,因为考虑到完全截图可能会超过图片,所以截图和完全截图不一定一样大小,作者又恢复了完整截图,只不过对于超过图片的部分用黑色进行填充。
参数:
bbox_tight:BBox
image:图片
pad_image:保存被黑色填充的target_pad完全截图
pad_image_location:保存截图的BBox
edge_spacing_x:截图的左边界超出图片的时候,超出的长度;不超过的时候为0
edge_spacing_y:截图的上边界超出图片的时候,超出的长度;不超出的时候为0
返回:
void ComputeCropPadImageLocation(const BoundingBox& bbox_tight, const cv::Mat& image, BoundingBox* pad_image_location):计算截图的位置,以BBox的中心为中心,大小为(output_weight, output_height)。如果截图超过图片,那么只考虑图片内的截图。
参数:
bbox_tight:BBox,图片中目标的BBox
image:整张图片
pad_image_location:保存截图的BBox
返回:
src/train文件夹
example_generator.cpp:类ExampleGenerator:处理两张图片,生成训练数据,包括真实样本和生成样本
成员变量:
lambda_shift_:BBox的平移随机变量服从的分布的参数
lambda_scale_:BBox的缩放随机变量服从的分布的参数
min_scale_:
max_scale_:限制BBox放大、缩小比例
image_curr_:当前的训练图片
bbox_curr_gt_:当前图片中的目标的BBox
bbox_prev_gt_:上一张图片中的目标的BBox
target_pad_:根据上一张图片的目标截取的用黑色填充的完全截图
video_index_:
frame_index_:当前样本生成自哪一个视频和哪一个帧,这两个参数只在保存图片的额时候才会用到
成员函数:
构造函数:
ExampleGenerator(const double lambda_shift, const double lambda_scale, const double min_scale, const double max_scale)
参数
lambda_shift:paramater of Laplace distribution of shift
lambda_scale:paramater of Laplace distribution of rescale
min_scale:
max_scale:constraint on change of size
返回:无
void Reset(const BoundingBox& bbox_prev, const BoundingBox& bbox_curr, const cv::Mat& image_prev, const cv::Mat& image_curr):根据输入的参数设置ExampleGenerator对象对应的成员变量值
参数:
bbox_prev:上一张图片的BBox
bbox_curr:当前图片的BBox
image_prev:上一张图片
image_curr:当前图片
返回:无
void get_default_bb_params(BBParams* default_params) const:把ExampleGenerator对象的lambda参数和scale参数保存至defaut_params。
void MakeTrainingExampleBBShift(const bool visualize_example, const BBParams& bbparams, cv::Mat* rand_search_region, cv::Mat* target_pad, BoundingBox* bbox_gt_scaled) const:生成人造数据。对当前BBox进行平移和缩放(Laplace分布),然后对变换BBox在当前图片上进行填充完全截图(称为搜索区域),并计算新BBox此时相对搜索区域的位置得到新的bbox_gt_recentered,对这个BBox的坐标缩放到[0, kScaleFactor]之间。
参数:
visualize_example:是否可视化
bbparams:获取ExampleGenerator对象的变换参数
rand_search_region:填充完全转换截图
target_pad:填充的完全截图
bbox_gt_scaled:BBox相对于搜索区域的位置(经过规范化的,坐标取值在[0, kScaleFactor]之间)
返回:无
void MakeTrainingExampleBBShift(cv::Mat* image_rand_focus, cv::Mat* target_pad, BoundingBox* bbox_gt_scaled) const:平移和缩放
参数:
image_rand_focus:保存填充完全转换截图
target_pad:保存上一张图片的目标BBox的完全填充截图
bbox_gt_scaled:保存BBox相对于搜索区域的位置(经过规范化的,坐标取值在[0, kScaleFactor]之间)
返回:无
void MakeTrainingExamples(const int num_examples, std::vector<cv::Mat>* images, std::vector<cv::Mat>* targets, std::vector<BoundingBox>* bboxes_gt_scaled): 根据当前图片生成num_examples个人造数据。根上一张图片的截图保持不变,对当前图片的目标进行变换并截图:[targets,images]就是神经网络的输入。
参数:
num_examples:合成样本数
images:保存得到的填充完全变换截图的向量
targets:保存填充完全截图的向量
bboxes_gt_scaled:保存BBox在搜索区域(填充完全变换截图)中的相对位置,坐标在[0, kScaleFactor]之间
返回:无
void MakeTrueExample(cv::Mat* curr_search_region, cv::Mat* target_pad, BoundingBox* bbox_gt_scaled) const:根据当前图片和上一图片得到的截图(真实数据)
参数:
curr_search_region:当前图片目标的填充完全截图
target_pad:上一图片目标的填充完全截图
bbox_gt_scaled:ground truth
返回:
tracker_trainer.cpp:
变量:
const int kBatchSize = 50:batch大小
const int kGeneratedExamplesPerImage = 10:对每张图片生成多少个人工样本
类TrackerTrainer:
成员变量:
std::vector<cv::Mat> image_batch_:当前训练batch的数据。这个是当前图片的截图
std::vector<cv::Mat> targets_batch_:上一张图片的截图
std::vector<BoundingBox> bboxes_gt_scaled_batch_:输出的ground truth
ExampleGenerator* example_generator_:用来生成真实训练数据以及人工数据
RegressorTrainBase* regressor_train_:神经网络
int num_batches_:已经训练的batch总数
成员函数:
void Train(const cv::Mat& image_prev, const cv::Mat& image_curr, const BoundingBox& bbox_prev, const BoundingBox& bbox_curr):根据提供的当前图片、上一图片以及对应的BBox参数得到一个真实样本以及kGeneratedExamplesPerImage个人工样本。用这些样本去补TrackerTrainer的batch数据。如果这些样本数加上TrackerTrainer的数据超过了kBatchSize,那么填满batch后剩下的数据留作下一个batch用,并且由于TrackerTrainer的数据达到一个batch开始训练,然后清空batch,并把由当前图片得到的数据中没有使用的部分再添加到空batch中;如果没有达到kBatchSize个数据,那么添加到batch中去等待再一个数据。
参数:
image_prev:
image_curr:
bbox_prev:
bbox_curr:
返回:
virtual void MakeTrainingExamples(std::vector<cv::Mat>* images, std::vector<cv::Mat>* targets, std::vector<BoundingBox>* bboxes_gt_scaled):根据传递给train函数的参数设置成员变量example_generator_,然后调用example_generator_的MakeTrueExample()函数以及MakeTrainingExamples()得到真实样本以及生成样本
参数:
images:保存根据当前图片目标生成的填充完全截图以及填充完全变换截图
targets:保存上一图片的目标填充完全截图
bboxes_gt_scaled:保存ground truth
返回:
virtual void ProcessBtch():根据TrackerTrainer的batch数据训练网络
参数:
返回:
train.cpp
变量:
kNumBatches = 500000:batch的数目
函数:
void train_image(const LoaderImagenetDet& image_loader, const std::vector<std::vector<Annotation> >& images, TrackerTrainer* tracker_trainer):任意选择一个图片,并任意选择它的一个Annotation,通过image_loader加载响应的图片数据和BBox进行训练
参数:
image_loader:用于加载图片数据和BBox
images:所有图片的所有Annotation
tracker_trainer:训练器
返回:
void train_video(const std::vector<Video>& videos, TrackerTrainer* tracker_trainer):任意选择一个视频,然后选择该视频中任意一个Annotation,以其对应的帧作为上一张图片,以下一个Annotation对一个的帧作为当前图片,加载两个图片和两个BBox进行训练
参数:
videos:所有视频
tracker_trainer:训练器
返回:
main函数:需要数据文件参数、网络文件参数、以及目标BBox变换所需要的四个参数,用于加载图片数据集和视频数据集;创建神经网络;创建ExampleGenerator来生成训练样本。定义TrackerTrainer对象,然后随机训练一张图片,随机训练一个视频。
问题
怎么保证神经网络的输入是一样大小的?不同目标的BBox的大小不一样,所以截图也不一样;在人工数据中,对BBox进行的变换是不定的,对应的截图大小也不一样。在Regressor::Estimate()函数中会对数据reshape到神经网络需要的大小。
相关文章推荐
- 目标跟踪之GOTURN:Learning to Track at 100 FPS with Deep Regression Networks
- Learning to Track at 100 FPS with Deep Regression Networks 论文理解及应用笔记(二)
- Learning to Track at 100 FPS with Deep Regression Networks 论文笔记
- Learning to Track at 100 FPS with Deep Regression Networks 论文理解及应用笔记(一)
- 深度学习Tracking(1)——Learning to Track at 100 FPS with Deep Regression Networks(代码理解)
- Learning to Track at 100 FPS with Deep Regression Networks
- GOTURN——Learning to Track at 100 FPS with Deep Regression Networks
- 深度学习Tracking(1)——Learning to Track at 100 FPS with Deep Regression Networks
- 【目标跟踪】Learning to Track at 100 FPS with Deep Regression Networks 学习
- 经典计算机视觉论文笔记——《ImageNet Classification with Deep Convolutional Neural Networks》
- Learning to Track at 100 FPS with Deep Regression Networks ECCV 2016 论文笔记
- Visual Tracking with Online Multiple Instance Learning (MIL)目标跟踪论文笔记
- 计算机视觉-论文阅读笔记-基于高性能检测器与表观特征的多目标跟踪
- 论文笔记:Occlusion-free Face Alignment: Deep Regression Networks Coupled with De-corrupt Auto-Encoders
- 从特征描述子到深度学习:计算机视觉的20年历程 From feature descriptors to deep learning: 20 years of computer vision
- GOTURN: Learning to Track at 100 FPS with Deep Regression Networks笔记
- 【论文笔记】Sequence to sequence Learning with Neural Networks
- 论文笔记 Ensemble of Deep Convolutional Neural Networks for Learning to Detect Retinal Vessels in Fundus
- 【学习笔记】WEEK 1_Introduction to Deep Learning_Supervised Learning with Neural Networks
- neural networks deep learning Logistic Regression with a Neural Network mindset Homework