SiameseFC-TensorFlow 代码详细注解(二):训练数据VID2015预处理

SiameseFC-TensorFlow 代码详细注解(二):训练数据VID2015预处理

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/StayFoolish_Fan/article/details/80432531

说明:该系列博客源码链接为:https://github.com/bilylee/SiamFC-TensorFlow,是实验室同小组的师兄用TensorFlow实现SiameseFC算法的最终公开版本,经过了长时间的打磨,各个模块功能明确,整体可读性和可移植性极好,我相信这对做Tracking的小伙伴来说,是个入门SiameseFC Tracker的特别好的选择。哈哈,觉得代码很棒的小伙伴们可以点个Star哦,也欢迎交流学习和指教。

上一篇介绍跑SiameseFC代码的主要流程,这一篇主要介绍开始训练自己的模型的第一步:训练数据预处理。

1:VID2015相关链接

ImageNet比赛官网 :http://image-net.org/challenges/LSVRC/,可以了解比赛信息,包含各比赛实验数据。

VID2015数据下载链接:http://bvisionweb1.cs.unc.edu/ilsvrc2015/download-videos-3j16.php#vid

2:ILSVRC2015 VID数据

解压缩之前,数据大小约86G,解压缩之后的文件夹目录如下:


ImageSets:包含一些.txt文件,子数据集的相关描述,预处理过程中用不到,可忽略。

Data :存储的所有数据信息,包括了图片(val,train,test)和视频片段(snippets)。

Annotations:对应的Data中图片的注释信息,包括val和train部分。

Data子文件夹VID下的文件目录如下:


查看当前文件目录下的文件数量命令:(R代表包含子目录)

ls -lR|grep"^-"| wc -l

可通过上面的指令进入到对应的文件夹中统计VID数据的详细信息如下:

Snippets :  3862+ 555 + 937 = 5354 videos

Train       :   3862  videos  ( 1122397 images )

Val          :   555    videos  ( 176126   images )

Test         :   937    videos  ( 315175   images )


Annotations子文件夹VID下的文件目录如下:


只包含了val和train部分,和上面Data/VID/val和train相对应,存储的是每个图片的.xml格式的标注信息。

挑出来一个.xml文件看看里面长什么样,如下:


.xml注释文件有我们需要用到的folder,filename,size,trackid,bndbox等信息,后面会解析出相关的信息的,说明一下这个trackid很重要,同一个image中有多个trackid说明包含该image的短视频存在着很多个目标,在后面就会解析出来更多的videos,记住这点对看后面的数据处理有帮助。

3:VID2015训练数据预处理

我们下载了VID数据之后也知道数据长什么样了,那如何处理这些数据使得可供SiameseFC训练呢?第一步就需要按照SiameseFC论文中Data Curation的部分对数据进行预处理,接着将训练数据存储为.pickle文件方便训练加载,最后还需要下载一些预训练模型和一个测试的视频,详细内容参见下面的注解。

3.1 Data Curation

核心文件:scripts/preprocess_VID_data.py

核心功能:根据SiamsesFC论文中的Curation方式进行图片预处理。


     
     
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright © 2017 bily Huazhong University of Science and Technology
  5. #
  6. # Distributed under terms of the MIT license.
  7. from __future__ import absolute_import
  8. from __future__ import division
  9. from __future__ import print_function
  10. import os
  11. import os.path as osp
  12. import sys
  13. import xml.etree.ElementTree as ET # 解析xml文件的模块
  14. from glob import glob
  15. from multiprocessing.pool import ThreadPool # 多进程加速
  16. import cv2
  17. from cv2 import imread, imwrite # 使用 opencv 读写图像
  18. CURRENT_DIR = osp.dirname(__file__)
  19. ROOT_DIR = osp.join(CURRENT_DIR, '..')
  20. sys.path.append(ROOT_DIR) # 添加搜索路径
  21. from utils.infer_utils import get_crops, Rectangle, convert_bbox_format # 自己写的小函数
  22. from utils.misc_utils import mkdir_p
  23. def get_track_save_directory(save_dir, split, subdir, video): # 存储路径的一个简单映射函数,简化存储目录
  24. subdir_map = { 'ILSVRC2015_VID_train_0000': 'a', # 将train映射到(a,b,c,d),val映射到(e)
  25. 'ILSVRC2015_VID_train_0001': 'b',
  26. 'ILSVRC2015_VID_train_0002': 'c',
  27. 'ILSVRC2015_VID_train_0003': 'd',
  28. '': 'e'}
  29. return osp.join(save_dir, 'Data', 'VID', split, subdir_map[subdir], video)
  30. def process_split(root_dir, save_dir, split, subdir='', ): # 数据处理核心函数,spilt就是['val','train']中的值
  31. data_dir = osp.join(root_dir, 'Data', 'VID', split) # 待处理图片数据路径
  32. anno_dir = osp.join(root_dir, 'Annotations', 'VID', split, subdir) # 待处理图片的注释数据路径
  33. video_names = os.listdir(anno_dir) # train和val数据集所有的video names,因为我们只有这两个数据集的annotations
  34. for idx, video in enumerate(video_names):
  35. print( '{split}-{subdir} ({idx}/{total}): Processing {video}...'.format(split=split, subdir=subdir,
  36. idx=idx, total=len(video_names),
  37. video=video))
  38. video_path = osp.join(anno_dir, video)
  39. xml_files = glob(osp.join(video_path, '*.xml')) # 获得当前video的所有图片对应的.xml文件
  40. for xml in xml_files: # 使用ET处理单个图片(.jpeg && .xml)
  41. tree = ET.parse(xml)
  42. root = tree.getroot()
  43. folder = root.find( 'folder').text # 解析.xml文件的folder
  44. filename = root.find( 'filename').text # 解析.xml文件中的filename
  45. # Read image
  46. img_file = osp.join(data_dir, folder, filename + '.JPEG') # 将.xml文件名对应到相同的图片文件名
  47. img = None
  48. # Get all object bounding boxes
  49. bboxs = []
  50. for object in root.iter( 'object'): # 找到所有的objects
  51. bbox = object.find( 'bndbox') # 找到 box项,.xml文件中名称是bndbox
  52. xmax = float(bbox.find( 'xmax').text) # 找到对应的 xmax并转换为float类型的box数据,以下类似
  53. xmin = float(bbox.find( 'xmin').text)
  54. ymax = float(bbox.find( 'ymax').text)
  55. ymin = float(bbox.find( 'ymin').text)
  56. width = xmax - xmin + 1 # 计算width 和 height
  57. height = ymax - ymin + 1
  58. bboxs.append([xmin, ymin, width, height]) # 返回的box的形式是[xmin,ymin,wedth,height]
  59. for idx, object in enumerate(root.iter( 'object')):
  60. id = object.find( 'trackid').text # 获取object的trackid,因为同一个video中可能存在多个需要跟踪的目标,加以区分
  61. class_name = object.find( 'name').text # 所属类别名称(VID中的30个大类)
  62. track_save_dir = get_track_save_directory(save_dir, 'train', subdir, video) # 获取存储路径
  63. mkdir_p(track_save_dir)
  64. savename = osp.join(track_save_dir, '{}.{:02d}.crop.x.jpg'.format(filename, int(id)))
  65. if osp.isfile(savename): continue # skip existing images # 文件存在的情况下无需存储
  66. if img is None:
  67. img = imread(img_file) # 读取image文件
  68. # Get crop
  69. target_box = convert_bbox_format(Rectangle(*bboxs[idx]), 'center-based') # box格式转换
  70. crop, _ = get_crops(img, target_box,
  71. size_z= 127, size_x= 255,
  72. context_amount= 0.5, )
  73. imwrite(savename, crop, [int(cv2.IMWRITE_JPEG_QUALITY), 90]) # 图片存储,质量为90
  74. if __name__ == '__main__':
  75. vid_dir = osp.join(ROOT_DIR, 'data/ILSVRC2015') # VID原始数据集存储的根目录,可以跟改为自己存储数据的绝对路径
  76. # Or, you could save the actual curated data to a disk with sufficient space
  77. # then create a soft link in `data/ILSVRC2015-VID-Curation`
  78. save_dir = 'data/ILSVRC2015-VID-Curation' # 处理之后的数据存储的位置,可以修改为绝对路径
  79. pool = ThreadPool(processes= 5) # 开启5个线程加快处理速度
  80. one_work = lambda a, b: process_split(vid_dir, save_dir, a, b) # 执行函数,下面调用的时候每个会在每个线程中执行
  81. results = []
  82. results.append(pool.apply_async(one_work, [ 'val', ''])) # 非阻塞方式,线程1调用one_work处理val数据集,下类似
  83. results.append(pool.apply_async(one_work, [ 'train', 'ILSVRC2015_VID_train_0000']))
  84. results.append(pool.apply_async(one_work, [ 'train', 'ILSVRC2015_VID_train_0001']))
  85. results.append(pool.apply_async(one_work, [ 'train', 'ILSVRC2015_VID_train_0002']))
  86. results.append(pool.apply_async(one_work, [ 'train', 'ILSVRC2015_VID_train_0003']))
  87. ans = [res.get() for res in results] # 获取子线程结果,作用就是阻塞主线程,等待子线程执行完成

3.2 将训练数据保存为pickle格式

核心文件:scripts/build_VID2015_imdb.py

核心功能:将Data Curation处理后的训练数据存储为.pickle格式(train_imdb.pickle 和 validation_imdb.pickle)


     
     
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright © 2017 bily Huazhong University of Science and Technology
  5. #
  6. # Distributed under terms of the MIT license.
  7. """Save the paths of crops from the ImageNet VID 2015 dataset in pickle format"""
  8. from __future__ import absolute_import
  9. from __future__ import division
  10. from __future__ import print_function
  11. import glob
  12. import os
  13. import os.path as osp
  14. import pickle # 导入pickle模块,将VID数据存储为pickle格式
  15. import sys
  16. import numpy as np
  17. import tensorflow as tf
  18. CURRENT_DIR = osp.dirname(__file__)
  19. sys.path.append(osp.join(CURRENT_DIR, '..')) # 添加搜索路径
  20. from utils.misc_utils import sort_nicely
  21. class Config: # 参数配置
  22. ### Dataset
  23. # directory where curated dataset is stored
  24. dataset_dir = '/home/ssd_datasets/ILSVRC2015_curated' # 之前curated数据测存储路径,可使用绝对路径或相对路径
  25. save_dir = '/workspace/czx/Projects/SiamFC-TensorFlow/assets/' # imdb文件存储路径
  26. # percentage of all videos for validation
  27. validation_ratio = 0.1 # validation所占的数据比例
  28. class DataIter:
  29. """Container for dataset of one iteration"""
  30. pass
  31. class Dataset: # 数据集类
  32. def __init__(self, config): # 初始化参数设置
  33. self.config = config
  34. def _get_unique_trackids(self, video_dir): # 根据video_dir来获取特定的跟踪目标
  35. """Get unique trackids within video_dir"""
  36. x_image_paths = glob.glob(video_dir + '/*.crop.x.jpg') # 取得video_dir下所有crop图片存储的文件名
  37. trackids = [os.path.basename(path).split( '.')[ 1] for path in x_image_paths] # 根据文件名获取对应trackid
  38. unique_trackids = set(trackids) # 因为每个视频snippet都可能有很多段小视频,每个小视频里面又会有多个跟踪的目标
  39. return unique_trackids
  40. def dataset_iterator(self, video_dirs): # 将所有的videos进行处理
  41. video_num = len(video_dirs) # videos的数量
  42. iter_size = 150 # 每次循环处理的视频个数
  43. iter_num = int(np.ceil(video_num / float(iter_size)))
  44. for iter_ in range(iter_num):
  45. iter_start = iter_ * iter_size
  46. iter_videos = video_dirs[iter_start: iter_start + iter_size] # 每次处理的videos数量为150
  47. data_iter = DataIter()
  48. num_videos = len(iter_videos)
  49. instance_videos = []
  50. for index in range(num_videos):
  51. print( 'Processing {}/{}...'.format(iter_start + index, video_num))
  52. video_dir = iter_videos[index] # 单个视频路径
  53. trackids = self._get_unique_trackids(video_dir) # 该视频对应到有多少个target trackid
  54. for trackid in trackids:
  55. instance_image_paths = glob.glob(video_dir + '/*' + trackid + '.crop.x.jpg') #trackid所有图片的路径
  56. # sort image paths by frame number
  57. instance_image_paths = sort_nicely(instance_image_paths) # 根据image number排序
  58. # get image absolute path # 获得排序好的图片计算对应的图片的绝对路径
  59. instance_image_paths = [os.path.abspath(p) for p in instance_image_paths]
  60. instance_videos.append(instance_image_paths)
  61. data_iter.num_videos = len(instance_videos) # 150个视频里面trackid的数量,>=150
  62. data_iter.instance_videos = instance_videos
  63. yield data_iter # yield返回一个生成器
  64. def get_all_video_dirs(self): # 获取VID数据集中所有videos的路径
  65. ann_dir = os.path.join(self.config.dataset_dir, 'Data', 'VID')
  66. all_video_dirs = []
  67. # 根据之前预处理的训练数据存储的文件结构进行解析获取所有trackid的路径
  68. # We have already combined all train and val videos in ILSVRC2015 and put them in the `train` directory.
  69. # The file structure is like:
  70. # train
  71. # |- a
  72. # |- b
  73. # |_ c
  74. # |- ILSVRC2015_train_00024001
  75. # |- ILSVRC2015_train_00024002
  76. # |_ ILSVRC2015_train_00024003
  77. # |- 000045.00.crop.x.jpg
  78. # |- 000046.00.crop.x.jpg
  79. # |- ...
  80. train_dirs = os.listdir(os.path.join(ann_dir, 'train'))
  81. for dir_ in train_dirs:
  82. train_sub_dir = os.path.join(ann_dir, 'train', dir_)
  83. video_names = os.listdir(train_sub_dir)
  84. train_video_dirs = [os.path.join(train_sub_dir, name) for name in video_names]
  85. all_video_dirs = all_video_dirs + train_video_dirs
  86. return all_video_dirs
  87. def main():
  88. # Get the data.
  89. config = Config() # 加载参数设置
  90. dataset = Dataset(config) # dataset实例
  91. all_video_dirs = dataset.get_all_video_dirs() # 获取所有VID中videos的路径
  92. num_validation = int(len(all_video_dirs) * config.validation_ratio) # validation数据数量
  93. ### validation 数据
  94. validation_dirs = all_video_dirs[:num_validation]
  95. validation_imdb = dict()
  96. validation_imdb[ 'videos'] = []
  97. for i, data_iter in enumerate(dataset.dataset_iterator(validation_dirs)):
  98. validation_imdb[ 'videos'] += data_iter.instance_videos
  99. validation_imdb[ 'n_videos'] = len(validation_imdb[ 'videos']) # 视频数量
  100. validation_imdb[ 'image_shape'] = ( 255, 255, 3) # 图片大小
  101. ### train 数据
  102. train_dirs = all_video_dirs[num_validation:]
  103. train_imdb = dict()
  104. train_imdb[ 'videos'] = []
  105. for i, data_iter in enumerate(dataset.dataset_iterator(train_dirs)):
  106. train_imdb[ 'videos'] += data_iter.instance_videos
  107. train_imdb[ 'n_videos'] = len(train_imdb[ 'videos'])
  108. train_imdb[ 'image_shape'] = ( 255, 255, 3)
  109. if not tf.gfile.IsDirectory(config.save_dir): # imdb数据存储路径
  110. tf.logging.info( 'Creating training directory: %s', config.save_dir)
  111. tf.gfile.MakeDirs(config.save_dir)
  112. with open(os.path.join(config.save_dir, 'validation_imdb.pickle'), 'wb') as f:
  113. pickle.dump(validation_imdb, f)
  114. with open(os.path.join(config.save_dir, 'train_imdb.pickle'), 'wb') as f:
  115. pickle.dump(train_imdb, f)
  116. if __name__ == '__main__':
  117. main()

4: 小结

1:核心介绍了VID2015数据集的结构是怎么样的,以及进行SiameseFC训练之前需要对该数据集如何处理。

2:这部分数据处理因为很早之前就已经处理好了,这里只贴一下一个样例吧。

原始图片样例:/Data/VID/train/ILSVRC2015_VID_train_0000/ILSVRC2015_train_00005004/000000.jpeg

原始的图片大小:1280*256。(下图是原图片截图)


Data Curation之后保存的图片:255*255,这就是训练过程中加载的search image。(也是截图)


这里还贴一个训练过程中crop出来的一个127*127的examplar吧。(还是截图)


3:训练数据VID2015的准备工作到这基本就做好了,接下来该聊聊如何构建模型了。要是觉得这份代码还不错,就顺手点个star吧,哈哈。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值