ST-GCN 自建kinetics数据集

简介: ST-GCN 自建kinetics数据集

image.png

目前我遇到过的,基于骨骼点的动作识别三种办法:

  1. 根据关节角度
  2. 跟踪算法
  3. 输入动作识别网络

该部分内容介绍的是自建动作识别网络数据集,达到自己想要的效果:

  1. 准备项目
  2. 准备视频
  3. 做视频水平翻转,增加训练集的数量(非必须)
  4. 提取骨骼点和置信度(一个视频一个生成json格式文件)
  5. 根据骨骼点和置信度文件生成label文件

1 项目部署

拉取最新版的openpose的cpu版本:https://github.com/CMU-Perceptual-Computing-Lab/openpose/releases

gpu版本我遇到的问题是最少需要四块gpu才能运行,没找到修改这部分的源码

解压,运行models文件夹中的两个bat文件

2 准备视频

c2b30b0a7f3144e280f6e94a2ff4fede.png

格式如下:每一类动作的视频放到一个文件夹下

3 水平翻转

原本这里用的是skvideo,我换成了cv2(主要我当时看到这里的时候skvideo有4.1节介绍的问题还没有解决)

import os
import cv2
if __name__ == '__main__':
    type_number = 4  # 修改,有几类动作
    typename_list = ["left", "right", "up", "down"]  # 修改,动作类别名/动作视频文件夹名
    for type_index in range(type_number):
        type_filename = typename_list[type_index]
        # 视频所在文件夹
        originvideo_file = './{}'.format(type_filename)
        # 得到文件夹内所有文件名
        videos_file_names = os.listdir(originvideo_file)
        # 左右镜像翻转视频
        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)  # 输出视频文件路径
            cap = cv2.VideoCapture(video_path)
            width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            # 定义编解码器并创建VideoWriter对象
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(outvideo_path, fourcc, 30.0, (width, height))
            while cap.isOpened():
                ret, frame = cap.read()
                if not ret:
                    print("Cant receive frame...............")
                    break
                frame = cv2.flip(frame, 1)
                out.write(frame)
                cv2.imshow("frame", frame)
                if cv2.waitKey(1) == ord("q"):
                    break
            cap.release()
            out.release()
            cv2.destroyAllWindows()

4 提取骨骼点和置信度

这是处理一个视频文件夹下的视频,比如动作为向左的文件夹下的视频1,视频2…

import os
import argparse
import json
import shutil
import skvideo
skvideo.setFFmpegPath('D:/ffmpeg/bin')
import skvideo.io
# st_gcn项目下的文件
import st_gcn_tools
import st_gcn_tools.utils as utils
label_name, label_no = 'running', 0
class PreProcess():
    """
        利用openpose提取自建数据集的骨骼点数据
    """
    def start(self):
        # 视频所在文件夹
        originvideo_file = './Data/hs'
        # resized视频输出文件夹
        resizedvideo_file = './Data/resize'
        os.makedirs(resizedvideo_file, exist_ok=True)
        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={'-s': '340x256'})
            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:
            if not file_name.endswith('mp4'):
                continue
            outvideo_path = '{}/{}'.format(resizedvideo_file, file_name)
            # 拉取的项目的openPoseDemo.exe文件
            openpose = f'E:/Code/BehaviorRecognition/openpose_cpu/bin/OpenPoseDemo.exe'
            video_name = os.path.splitext(file_name)[0]
            # 下面路径下存放的是每个视频的独立一帧的骨骼坐标和置信度
            output_snippets_dir = './Data/resize/snippets/{}'.format(video_name)
            # 下面文件夹一个文件存放的是一个视频的所有帧的骨骼坐标和置信度
            output_sequence_dir = './data/resize/data'
            os.makedirs(output_snippets_dir, exist_ok=True)
            os.makedirs(output_sequence_dir, exist_ok=True)
            output_sequence_path = '{}/{}.json'.format(output_sequence_dir, video_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()])
            # D:/Pycharm_project/Pose/openpose_all/openpose/bin/OpenPoseDemo.exe --video &outvideo_path \
            # --write_json &output_snippets_dir
            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, label_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))
if __name__ == '__main__':
    p = PreProcess()
    p.start()

从上往下总结几个需要注意的地方:

4.1 skvideo库的经典错误

报错

    assert _HAS_FFMPEG, "Cannot find installation of real FFmpeg (which comes with ffprobe)."
AssertionError: Cannot find installation of real FFmpeg (which comes with ffprobe).

解决办法

网络上下载ffmpeg,并导入import skvideo.io之前输入以下代码

import skvideo
skvideo.setFFmpegPath('D:/ffmpeg/bin')  # 参数是解压的ffmpeg/bin的路径

4.2 额外文件的准备

import st_gcn_tools
import st_gcn_tools.utils as utils

从上面导入来看,我们需要st-gcn项目中的一些文件来完成目前的工作,大概如下:

e5e5ed26eab344ce874113452294b18f.png

5 生成label文件

##  json2kinetics.py
import json
import os
if __name__ == '__main__':
    train_json_path = './Data/resize/data'    # './mydata/kinetics-skeleton/kinetics_train'
    # val_json_path = 'D:/VIDEOS/mydata/kinetics-skeleton/kinetics_val'  # './mydata/kinetics-skeleton/kinetics_val'
    output_train_json_path = './Data/output/1.json'
    # output_val_json_path = 'D:/VIDEOS/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 = os.path.splitext(file_name)[0]
        json_file_path = '{}/{}'.format(train_json_path, file_name)
        # D:/VIDEOS/mydata/kinetics-skeleton/kinetics_train/{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)

注释掉的部分是测试集的部分,如果需要把注释去掉

6 另一种尝试

上面提取骨骼点用的是OpenPoseDemo.exe文件,理论上直接使用源码也是可以的。经过尝试确定了需要解决的问题,记录一下

  1. 源码输出的置信度只有两种,检测到的节点为2,检测不到的节点为0,这样归一化后任何检测到的点的值应该也是一样的,但是kinetics数据集中是不同的,不知道是哪里出了问题
  2. 我们输入到st-gcn中的骨骼坐标是经过归一化的
    因为是学习为主,重点还是用源码
相关文章
|
机器学习/深度学习 算法 网络架构
ST-GCN原理总结
ST-GCN原理总结
276 0
|
6月前
|
数据可视化
R语言nlme、nlmer、lme4用(非)线性混合模型non-linear mixed model分析藻类数据实例(上)
R语言nlme、nlmer、lme4用(非)线性混合模型non-linear mixed model分析藻类数据实例
|
6月前
|
资源调度 安全
R语言nlme、nlmer、lme4用(非)线性混合模型non-linear mixed model分析藻类数据实例(下)
R语言nlme、nlmer、lme4用(非)线性混合模型non-linear mixed model分析藻类数据实例
|
6月前
|
机器学习/深度学习 人工智能 数据可视化
【视频】R语言支持向量回归SVR预测水位实例讲解|附代码数据
【视频】R语言支持向量回归SVR预测水位实例讲解|附代码数据
|
SQL 存储 分布式计算
HA3 SQL样本实验:一种混合计算查询的全新样本解决方案
HA3(对外开源代号:Havenask )是阿里智能引擎团队自研的大规模分布式检索系统,广泛应用于阿里内部的搜索业务,是十多年来阿里在电商领域积累下来的核心竞争力产品。Ha3 SQL 是在原有Ha3引擎基础上,新增的SQL查询功能,引擎内置了SQL形式的的查询语法,允许用户通过写SQL语句来构造引擎查询。
|
机器学习/深度学习 数据可视化 计算机视觉
0参数量 + 0训练,3D点云分析方法Point-NN刷新多项SOTA(1)
0参数量 + 0训练,3D点云分析方法Point-NN刷新多项SOTA
127 0
|
机器学习/深度学习 数据可视化 数据挖掘
0参数量 + 0训练,3D点云分析方法Point-NN刷新多项SOTA(2)
0参数量 + 0训练,3D点云分析方法Point-NN刷新多项SOTA
276 0
|
机器学习/深度学习 人工智能 自然语言处理
多模态再次统一!Meta发布自监督算法data2vec 2.0:训练效率最高提升16倍!
多模态再次统一!Meta发布自监督算法data2vec 2.0:训练效率最高提升16倍!
262 0
|
机器学习/深度学习 PyTorch Serverless
假设测试数据集test_data为随机生成的,并设置小批次。model神经网络已经训练好了,怎么用MSE来做测试
其中,model表示已经训练好的PyTorch模型,torch.rand()函数用于生成测试数据集,torch.split()函数用于将测试数据集分成小批次,model(batch)用于对小批次的输入数据进行预测,torch.cat()函数用于将所有小批次的预测值拼接在一起,最后使用mean_squared_error()函数计算均方误差。注意,在计算均方误差之前,需要将测试数据集和预测值转换为NumPy数组并将它们从GPU中移动到CPU上。
159 0
|
机器学习/深度学习 PyTorch 算法框架/工具
如何用torch写一个Bi-LSTM网络
上述代码中,我们定义了一个名为BiLSTM的神经网络类,它继承自nn.Module。在__init__函数中,我们初始化了Bi-LSTM的参数,包括输入层大小、隐藏层大小、LSTM层数、类别数等。我们使用nn.LSTM构造了一个双向LSTM层,并在forward函数中将输入张量x传递给它,同时传入初始化的隐藏状态和单元状态。然后我们从Bi-LSTM的最终输出中提取最后一层的前向和反向LSTM的输出,并将它们连接起来。最后,我们将连接后的张量传递给全连接层,得到网络的输出。
309 0