AVA Actions Dataset 详解


0. 前言

  • 要基于AVA数据集做一些工作,网上的文章都不能满足我的要求,所以自己写一篇记录一下。
  • 参考资料:
  • 感想:
    • 行为识别数据集下载真的困难,国内搞过的都懂……
    • 作为组里第一个吃螃蟹的,到现在还在跟 Kinetics-700、ActivityNet 等数据集死磕,辛酸泪。
    • AVA 已经是最容易的了,毕竟可以用迅雷下载。
  • 本文主要内容:
    • 第一章:介绍AVA,如何获取、标注过程、annotations解析。
    • 第二章:SlowFast中解析AVA的过程。
    • 第三章:mmaction中解析AVA的过程。(尚未完成)

1. AVA简介

1.1. 基本情况

  • 数据集类别:Spatio-Temporal Action Detection,即时空行为检测。
    • 举个例子,就是检测出视频中所有人的位置以及对应的行为类别。
  • 数据集形式(这里是简单介绍,后面会有更详细的说明):
    • 要标记的内容包括人物bbox,以及每个人的行为类别,同一时间同一人可能有多个行为
      • 标记的内容还有还有每个实体编号,即相邻关键帧中的人物如果是同一个人,则拥有相同的实体编号。换句话说,“实体编号”其实就是目标跟踪的标签。
    • 并不是对视频中的每一帧进行标记,而只是对关键帧进行标记。
    • 所谓关键帧,按我的理解就是每秒取1帧作为关键帧,对该帧进行标记。
  • 行为类别:标签一共有80类,(但验证时只用到其中的60类)。80类标签分为三类(person movement, object manipulation, person interaction),具体信息如下。
    • person movement
      • bend/bow (at the waist)
      • crawl
      • crouch/kneel
      • dance
      • fall down
      • get up
      • jump/leap
      • lie/sleep
      • martial art
      • run/jog
      • sit
      • stand
      • swim
      • walk
    • object manipulation
      • answer phone
      • brush teeth
      • carry/hold (an object)
      • catch (an object)
      • chop
      • climb (e.g., a mountain)
      • clink glass
      • close (e.g., a door, a box)
      • cook
      • cut
      • dig
      • dress/put on clothing
      • drink
      • drive (e.g., a car, a truck)
      • eat
      • enter
      • exit
      • extract
      • fishing
      • hit (an object)
      • kick (an object)
      • lift/pick up
      • listen (e.g., to music)
      • open (e.g., a window, a car door)
      • paint
      • play board game
      • play musical instrument
      • play with pets
      • point to (an object)
      • press
      • pull (an object)
      • push (an object)
      • put down
      • read
      • ride (e.g., a bike, a car, a horse)
      • row boat
      • sail boat
      • shoot
      • shovel
      • smoke
      • stir
      • take a photo
      • text on/look at a cellphone
      • throw
      • touch (an object)
      • turn (e.g., a screwdriver)
      • watch (e.g., TV)
      • work on a computer
      • write
    • person interaction
      • fight/hit (a person)
      • give/serve (an object) to (a person)
      • grab (a person)
      • hand clap
      • hand shake
      • hand wave
      • hug (a person)
      • kick (a person)
      • kiss (a person)
      • lift (a person)
      • listen to (a person)
      • play with kids
      • push (another person)
      • sing to (e.g., self, a person, a group)
      • take (an object) from (a person)
      • talk to (e.g., self, a person, a group)
      • watch (a person)

1.2. 如何获取

  • 两种获取方式
    • 标签可以在官网上下载标签,视频可以通过 youtube-dl 获取。
    • 官方提供了aws数据源,具体可以参考这里
      • 可以用迅雷,可以用迅雷,可以用迅雷,重要的事说三遍。写个脚本写上所有视频链接地址,然后批量传入迅雷,美滋滋。(如果Kinetics和ActivityNet都能这么下就好了)
      • 可以用百度云离线下载,不过好像不能批量导入下载链接,没仔细研究。
  • SlowFast/MMAction 中都提供了 AVA 数据预处理相关脚本,具体在后续章节会介绍,可以参考。

1.3. 数据集构建过程

  • 这部分内容主要参考了 数据集论文
  • 第一步:Action vocabulary generation
    • 任务:确定要标注的行为类别以及继承关系。
    • 选择/设置“行为类别”时有三个准则:
      • generality,即通用性,而不是特定环境下的特定动作(如“在篮球场打篮球”)。
      • atomicity,即原子性。每个动作都有其特点,且与交互的物体无关(如行为 hold 且不要指定hold的物体)。
      • exhaustivity,即类别尽可能丰富。
  • 第二步:Movie and segment selection
    • 任务:构建原始视频数据集,为后续标注工作做准备。
    • AVA的数据源来自电影片段
    • 每个电影只标注第15-30分钟内的视频
    • 每个长度为15分钟的视频都转换为897个长度为3s的视频片段(clip)。
      • 15分钟共900秒,窗口长度为3秒,stride为1秒,滑动897次得到897个clip。
      • 每个clip对对应一个keyframe(关键帧),关键帧是1.5秒位置。
    • 搞了一个各个国家顶尖演员列表,然后在Youtube中对每个演员进行搜索,寻找符合条件的电影。
      • 条件包括:有 file/television 标签,时长超过30分钟,发布时间超过1年,观看人数超过1000,且不包含黑白、低清晰度、卡通等类别的电影。
  • 第三步:Person bounding box annotation
    • 任务:针对每个keyframe标注人物bbox。
    • 使用了混合标注法:
      • 先用Faster-RCNN标注,(说是 set operating point 从而保证高精度,不知道啥意思,猜测就是提高了阈值吧)。
      • 之后在人工标注遗漏的bbox。
    • bbox对最终结果影响很大,所以这一步会比较注意。
  • 第四步:Person link annotation
    • 任务:对相邻keyframe中的任务bbox进行关联。
    • 方法:
      • 先机器标注一波:通过计算相邻两帧不同bbox之间的相似度,然后根据匈牙利算法进行匹配。
      • 再手动处理一波:手工删除FP样本。
  • 第五步:Action annotation
    • 任务:标注行为类别。
    • 通过众包实现。不可避免的,标注人会少标行为(因为行为太多了)。
    • 参考界面如下:image_1ecmlpe5j19naf9g1nnpf211pq59.png-476kB

1.4. annotations 解析

  • 以 v2.2 为例,解压 ava_v2.1.zip 得到的结果如下。
    • V2.1 和 V2.2 的区别:
      • 标签内容没细看,可能v2.2细化了吧。
      • 视频源没有任何变化,即V2.1与V2.2的 train/val/test 的视频是完全相同的。
  • 行为类别文件:
    • ava_action_list_v2.1_for_activitynet_2018.pbtxt:60类行为,Evaluate时使用
    • ava_action_list_v2.1.pbtxt:80类行为
  • 行为标签文件:
    • ava_train_v2.1.csvava_val_v2.1.csvava_test_v2.1.txt
    • 其中,train/val有标签,test只是视频名称列表。
    • train/val 每行代表一个样本,共有5个部分
      • video_id:视频名称,不包括文件后缀,即Youtube对应url
      • middle_Frame_timestamp:关键帧所在位置(第几秒)
      • person_box:包括了四列,(x1, y1, x2, y2),分别代表左上、右下点的位置。
      • action_id:即ava_action_list_v2.1.pbtxt中对应的id。
      • person_id:bbox中人物的编号,即 person link 时产生的标签,每个人的id不同。
  • ava_included_timestamps_v2.2.txt:每个视频要检测的位置,即第902到1798秒。
  • 不需要进行检测的timestamp
    • ava_train_excluded_timestamps_v2.1.csv
    • ava_val_excluded_timestamps_v2.1.csv
    • ava_test_excluded_timestamps_v2.1.csv
    • 即 train/val/test 数据集中每个视频不需要进行检测的timestamp。

2. SlowFast

2.1. 构建 Ava 对象

  • 第一步:为每个视频进行编号,并保存对应的帧绝对路径的列表。
    • 从代码角度看保存了两个列表
      • _video_idx_to_name
        • 每个视频原来有个 video_name,即youtube中对应url后缀,如 1j20qq1JyX4
        • 在代码中,video_name用起来不方便,所以对视频进行编号,即每个 video_name 对应一个 video_id(从0开始编号)。
        • 本对象是 list,index就是 video_id,value就是video_name
      • _image_paths
        • 保存每个视频对应帧的绝对路径。
        • 本对象是list,index是 video_id,value是一个list(中每个元素是帧绝对路径,注意,这个list中帧文件的顺序必须是从小到大,不然后面代码有问题)。
    • 源码细节:主要输入数据就是 frame_lists 文件
      • 该文件不是AVA官方提供的,而是FAIR提供的,可以自己生成。
      • 该文件中保存有video_name以及对应所有帧的相对路径,且帧文件的顺序就是从小到大。
    • 主要就是 ava_helper.load_image_lists 实现。
  • 第二步:解析行为标签文件。
    • 从代码角度看,就是构建了一个list boxes_and_labels
      • 该数据类型是:boxes_and_labels[video_id][frame_sec_int] = list([box_i, box_i_labels])
        • boxes_and_labels[video_id].keys() 就是所有可用的时间点,即range(902, 1799)
        • len(boxes_and_labels[video_id][frame_sec_int]) 就是这个时间点 box 的数量。
      • boxes_and_labels 整体是一个列表,index是 video_id,value是一个字典。
      • 该字典的 key 是 frame_sec_int,即 [902, 1798],表示视频中的第几帧。
      • 该字典的 value 是列表,取名为 value_list
      • value_list通过列表形式保存 bbox(x1, y1, x2, y2形式) 以及对应的
      • labels(同一个box可能有多个标签)两部分信息。
      • 其中,box_i 的形式是 x1, y1, x2, y2
    • 源码细节:
      • 这一步的输入数据主要包括GT与Predict两部分。
      • GT指的就是AVA官方提供的标签文件,如ava_train_v2.1.csv
      • Predict指的是验证/测试时用的数据,只包括每个视频每一帧的人物bbox以及对应的score,不包括行为类别。包括 video_name, frame_sec, bbox_x1, bbox_y1, bbox_x2, bbox_y2, category, score。在使用Predict数据时会根据 score 筛选一部分数据。
    • 主要通过 ava_helper.load_boxes_and_labels 实现。
  • 第三步:构建关键帧数据。
    • 从源码上看,就是构建了 _keyframe_indices_keyframe_boxes_and_labels 两个列表。
      • 这两个对象是配合使用的。两个列表中相同index的元素就是后续构建 clip 样本的输入数据。
      • 保存了所有可用关键帧相关信息。
    • _keyframe_indices
      • 是个list对象,index的作用就是与 _keyframe_boxes_and_labels 对应。
      • 主要保存四个数据 video_idx, sec_idx, sec, frame_idx
      • sec_idx 指的是当前关键帧在这个视频中所有关键帧的idx,从0开始取值
      • sec 指的是当前关键帧在这个视频中的位置,从902开始取值
      • frame_idx 指的是当前关键帧的具体编号,计算方法(sec-900)*FPS,其实就是每个clip的中心frame编号。
    • _keyframe_boxes_and_labels
      • 是个list对象,index的作用就是与 _keyframe_indices 对应。
      • 其实就是将上一步中的 boxes_and_labels[video_id][frame_sec_int] 直接保存下来。
    • 主要通过 ava_helper.get_keyframe_data 实现。

2.3. 读取某个keyframe信息

  • 这里,每个keyframe的信息就是对应一个clip数据,主要就是通过 __getitem__ 实现。
    • 输入的idx其实就是 2.2. 中第三步 _keyframe_indices 中的下标。
  • 第一步:获取 _keyframe_indices 对应 idx 下标信息。
    • video_idx, sec_idx, sec, center_idx,sec_idx 从0开始取值,sec从902开始取值。
  • 第二步:根据输入数据,进行数据采样。
    • center_idx 为中心,根据输入数据 _seq_len_sample_rate 进行采样。
    • 采样细节:
      • center_idx - _seq_len // 2开始,在 [center_idx - _seq_len // 2, center_idx + _seq_len // 2) 范围内,根据 _sample_rate 进行采样。
      • _seq_len 的取值其实是 _sample_rate * _sample_frames_length 得到的。
      • 刚开始在想,为什么这个采样刚好就能用。列了不等式算了算,刚刚好,这个样子采样其实刚好能得到 _sample_frames_length 个帧下标。
  • 第三步:获取 _keyframe_boxes_and_labels 获取该关键帧的所有boxes与对应label信息。
  • 第四步:根据采样结果以及 _image_paths 读取帧文件绝对路径,并读取对应图片。
    • _image_paths[video_idx][frame] for frame in seq,其中 seq 就是上面采样得到的结果。
  • 第五步:图片数据预处理。
    • 有pytorch与cv2两种模式,预处理的过程是一样的,只是调用的库不同。
    • 得到的结果都是 C, T, H, W 结构。
    • 预处理过程包括:
      • 数据类型/范围转换:[0, 255] -> [0, 1]
      • resize/crop操作:训练集 随机短边resize -> random crop -> random flip;验证集 短边resize -> center crop;测试集 短边resize。
        • 随机短边resize通过 transform.random_short_side_scale_jitter 实现,根据输入参数 TRAIN_JITTER_SCALES 指定短边范围,随机获取其中数值作为短边的size,然后进行resize。
      • 随机色彩变换,主要通过 transform.color_jittertransform.lighting_jitter 实现。
      • 图像标准化,减去平均数除以标准差。
  • 第六步:构建行为识别 one-hot 形式label。
    • label的shape为 [num_boxes, num_classes]
    • 注意,每行可能不止一个类别为1。
  • 第七步:分别为不同分支构建输入数据。
    • 对于I3D模型,这一步其实也没做什么。
    • 对于SlowFast模型,这一步会分别对 Slow 分支与 Fast 分支构建对应的输入图片。
      • Fast分支就是之前输入的。
      • Slow分支就是在T纬度上进行sample rate为SLOWFAST.ALPHA的采样。
  • 第八步:构建输出数据。
    • 输出数据包括四部分 imgs, labels, idx, extra_data
    • imgs 是第七步图像预处理的结果,是个list,分别对应每个分支的结果,每个分支的shape为 [C, T, H, W]
    • labels 就是第六步的结果,shape为 [num_boxes, num_classes]
    • idx__getitem__ 的输入数据。
    • extra_data 是个字典,包括三个数据:
      • boxes 经过数据预处理后的bbox。
      • ori_boxes 原始 boxes,即在resize/crop等操作前的bbox。
      • metadata 元数据列表,列表长度与 boxes 相同,每个元素都是 [video_id, sec]。sec从902开始取值。

3. MMAction

这是一个构建决策树的函数,其中`dataSet`是数据集,`label`是数据集中每个特征的名称。具体来说,该函数实现了决策树的构建过程,包括选择最优特征、划分数据集、递归构建子树等步骤。该函数的返回值是一个字典型的决策树,其中每个键表示一个决策节点,对应的值是该节点的子树或分类结果。在每个决策节点中,会选择一个最优特征作为划分依据,将数据集划分成若干个子集,对每个子集递归调用`createTree`函数构建子树,并将子树作为该节点的值返回。当递归到叶子节点时,将该节点的类别作为分类结果返回。下面是函数的伪代码: ``` def createTree(dataSet, label): # 如果数据集中所有实例属于同一类别,则返回该类别 if 所有实例属于同一类别: return 类别 # 如果特征集为空,则返回数据集中实例数最多的类别 if 特征集为空: return 数据集中实例数最多的类别 # 选择最优特征作为划分依据 best_feature = 选择最优特征(dataSet, label) # 创建决策树 decision_tree = {best_feature: {}} # 删除已选择的特征 del(label[best_feature]) # 根据最优特征划分数据集,递归构建子树 for 特征取值 in 最优特征的所有可能取值: # 根据最优特征将数据集划分成若干个子集 sub_dataset = 划分数据集(dataSet, best_feature, 特征取值) # 如果子集为空,则创建叶子节点,返回该节点的类别 if 子集为空: decision_tree[best_feature][特征取值] = 数据集中实例数最多的类别 # 否则递归调用createTree函数构建子树,并将子树作为该节点的值返回 else: decision_tree[best_feature][特征取值] = createTree(sub_dataset, label) return decision_tree ```
评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值