首先就是把st-gcn网络的运行环境完全配置好了,并且可以正常进行行为识别
配置环境参考:
1. 复现旧版STGCN GPU版 (win10+openpose1.5.0)
2. 复现st-gcn(win10+openpose1.5.1+VS2017+cuda10+cudnn7.6.4)
对于准备自己的数据集,作者有提到具体的做法,如下所示
we first resized all videos to the resolution of 340x256 and converted the frame rate to 30 fps we extracted skeletons from each frame in Kinetics by Openpose rebuild the database by this command: python tools/kinetics_gendata.py --data_path <path to kinetics-skeleton> To train a new ST-GCN model, run python main.py recognition -c config/st_gcn/<dataset>/train.yaml [--work_dir <work folder>]
把准备好的视频裁剪成5-8s的视频,用剪映可能比较方便简单
再把裁剪好的视频,利用脚本左右镜像翻转一下,扩充一下数据集,脚本:
import os import skvideo.io import cv2 if __name__ == '__main__': ###########################修改处################ type_number = 12 typename_list = [] ################################################# for type_index in range(type_number): type_filename = typename_list[type_index] #视频所在文件夹 originvideo_file = './mydata/裁剪/{}/'.format(type_filename) videos_file_names = os.listdir(originvideo_file) #1. 左右镜像翻转视频 for file_name in videos_file_names: video_path = '{}{}'.format(originvideo_file, file_name) name_without_suffix = file_name.split('.')[0] outvideo_path = '{}{}_mirror.mp4'.format(originvideo_file, name_without_suffix) writer = skvideo.io.FFmpegWriter(outvideo_path, outputdict={'-f': 'mp4', '-vcodec': 'libx264', '-r':'30'}) reader = skvideo.io.FFmpegReader(video_path) for frame in reader.nextFrame(): frame_mirror = cv2.flip(frame, 1) writer.writeFrame(frame_mirror) writer.close() print('{} mirror success'.format(file_name)) print('the video in {} are all mirrored'.format(type_filename)) print('-------------------------------------------------------')
这一步主要的目的是把自己的视频数据集创建成kinetics-skeleton数据集一样的格式,格式大致如下图
首先就是按照类别,把自己的视频分门别类,放在不同的文件夹下,然后主要通过两个脚本来提取数据。
第一个自己写的脚本的主要部分如下所示。这个脚本可以说是st-gcn源代码的./processor/demo_old.py中的一部分。主要先对视频数据进行resize至340x256的大小,30fps的帧率。然后调用openpose的进行骨骼点数据的检测和输出。我在其基础上加了一些批量处理各个文件夹下的视频数据的操作。
#!/usr/bin/env python import os import argparse import json import shutil import numpy as np import torch import skvideo.io from .io import IO import tools import tools.utils as utils class PreProcess(IO): """ 利用openpose提取自建数据集的骨骼点数据 """ def start(self): work_dir = './st-gcn-master' ###########################修改处################ type_number = 12 gongfu_filename_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] ################################################# for process_index in range(type_number): gongfu_filename = gongfu_filename_list[process_index] #标签信息 labelgongfu_name = 'xxx_{}'.format(process_index) label_no = process_index #视频所在文件夹 originvideo_file = './mydata/裁剪/{}/'.format(gongfu_filename) #resized视频输出文件夹 resizedvideo_file = './mydata/裁剪/resized/{}/'.format(gongfu_filename) videos_file_names = os.listdir(originvideo_file) #1. Resize文件夹下的视频到340x256 30fps for file_name in videos_file_names: video_path = '{}{}'.format(originvideo_file, file_name) outvideo_path = '{}{}'.format(resizedvideo_file, file_name) writer = skvideo.io.FFmpegWriter(outvideo_path, outputdict={'-f': 'mp4', '-vcodec': 'libx264', '-s': '340x256', '-r':'30'}) reader = skvideo.io.FFmpegReader(video_path) for frame in reader.nextFrame(): writer.writeFrame(frame) writer.close() print('{} resize success'.format(file_name)) #2. 利用openpose提取每段视频骨骼点数据 resizedvideos_file_names = os.listdir(resizedvideo_file) for file_name in resizedvideos_file_names: outvideo_path = '{}{}'.format(resizedvideo_file, file_name) #openpose = '{}/examples/openpose/openpose.bin'.format(self.arg.openpose) openpose = '{}/OpenPoseDemo.exe'.format(self.arg.openpose) video_name = file_name.split('.')[0] output_snippets_dir = './mydata/裁剪/resized/snippets/{}'.format(video_name) output_sequence_dir = './mydata/裁剪/resized/data' output_sequence_path = '{}/{}.json'.format(output_sequence_dir, video_name) label_name_path = '{}/resource/kinetics_skeleton/label_name_gongfu.txt'.format(work_dir) with open(label_name_path) as f: label_name = f.readlines() label_name = [line.rstrip() for line in label_name] # pose estimation openpose_args = dict( video=outvideo_path, write_json=output_snippets_dir, display=0, render_pose=0, model_pose='COCO') command_line = openpose + ' ' command_line += ' '.join(['--{} {}'.format(k, v) for k, v in openpose_args.items()]) shutil.rmtree(output_snippets_dir, ignore_errors=True) os.makedirs(output_snippets_dir) os.system(command_line) # pack openpose ouputs video = utils.video.get_video_frames(outvideo_path) height, width, _ = video[0].shape # 这里可以修改label, label_index video_info = utils.openpose.json_pack( output_snippets_dir, video_name, width, height, labelgongfu_name, label_no) if not os.path.exists(output_sequence_dir): os.makedirs(output_sequence_dir) with open(output_sequence_path, 'w') as outfile: json.dump(video_info, outfile) if len(video_info['data']) == 0: print('{} Can not find pose estimation results.'.format(file_name)) return else: print('{} pose estimation complete.'.format(file_name))
之后就是把提取得到的骨骼点数据的json文件做一下整理,按照上面图中的kinetics-skeleton数据集的格式。kinetics_train文件夹保存训练数据,kinetics_val文件夹保存验证数据。文件夹外两个json文件主要包含了对应文件夹中所有的文件名称、行为标签名和行为标签索引。这两个json文件的生成脚本可以参考如下所示
import json import os if __name__ == '__main__': train_json_path = './mydata/kinetics-skeleton/kinetics_train' val_json_path = './mydata/kinetics-skeleton/kinetics_val' output_train_json_path = './mydata/kinetics-skeleton/kinetics_train_label.json' output_val_json_path = './mydata/kinetics-skeleton/kinetics_val_label.json' train_json_names = os.listdir(train_json_path) val_json_names = os.listdir(val_json_path) train_label_json = dict() val_label_json = dict() for file_name in train_json_names: name = file_name.split('.')[0] json_file_path = '{}/{}'.format(train_json_path, file_name) json_file = json.load(open(json_file_path)) file_label = dict() if len(json_file['data']) == 0: file_label['has_skeleton'] = False else: file_label['has_skeleton'] = True file_label['label'] = json_file['label'] file_label['label_index'] = json_file['label_index'] train_label_json['{}'.format(name)] = file_label print('{} success'.format(file_name)) with open(output_train_json_path, 'w') as outfile: json.dump(train_label_json, outfile) for file_name in val_json_names: name = file_name.split('.')[0] json_file_path = '{}/{}'.format(val_json_path, file_name) json_file = json.load(open(json_file_path)) file_label = dict() if len(json_file['data']) == 0: file_label['has_skeleton'] = False else: file_label['has_skeleton'] = True file_label['label'] = json_file['label'] file_label['label_index'] = json_file['label_index'] val_label_json['{}'.format(name)] = file_label print('{} success'.format(file_name)) with open(output_val_json_path, 'w') as outfile: json.dump(val_label_json, outfile)
这一部分可以参考如下所示的博文中的 第三------第六 部分
st-gcn训练自建行为识别数据集
这部分可以通过改写st-gcn源码中的./processor/demo_old.py脚本来实现。主要需要注意的是,记得修改读取的行为类别的标签文件名,以及修改对应的yaml配置文件中模型名称和类别数量等参数