基于视频/摄像头的简单行为动作识别模型的训练步骤

基于视频序列对于各种动作的检测方法即对视频中不同行为动作做分类识别

神经网络使用的是这两个月开源的实时动作序列强分类神经网络:Real Time Sensenet

它是对视频中的动作序列作强分类的网络,可以实时检测分类,即在一段时间内将帧间图像组合成一个序列,送到网络中进行分类,它无需大量的标注, 同时解决了行为动作在时间上下文的问题

本文虽然是关于视频(摄像头)中简单动作的分类,但是该开源模型其实可以应用在各种人体姿势分类识别如手语识别、摔倒识别、运动分析等,即但凡关于动作的都可以才用这个方案来训练得到推理模型。

因为我的是简单动作所以我只是训练了十几个数据几个轮次也能有挺好的识别效果,如果过于复杂性的动作,可能要有足够多的数据才好,没试过。

我只讲怎么成功跑通代码,具体的代码省略(我也没仔细看)

目前代码已开源至Githubhttps://github.com/CVUsers/CV-Action 欢迎star~

下载代码,参照下文的的做法,视频数据我没有提供,你可以手机拍摄十几个放到对应的目录下就行

数据准备:

我在根目录下的tools/sense_studio 文件夹里面新建一个文件夹gesture_lau(名字任意取);

然后在gesture_lau文件夹下再新建两个文件夹:videos_train 和videos_valid;

videos_train 文件夹里面存放的是训练集,如果你想对视频(或摄像头)中的序列动作分成5类(多少类取决于你)的话,videos_train 文件夹中就需要再新建5个名字不同的文件夹(文件夹名字最好是那5类动作的类别名称,我做时略随便)

videos_train 文件夹中的名为1的文件夹中是我事先存放的人物“身体扭动”动作的几个视频(因此如果你要跟着做的话,也需要先往里面准备视频,注意不是图片)

2文件夹中实现存放有人物“拳击运动”动作的几个视频

3文件夹中实现存放有人物“头部运动”动作的几个视频

4文件夹中实现存放有人物“扩胸运动”动作的几个视频

5文件夹中实现存放有人物“其他运动”动作的几个视频

其中每个视频也就平均5、6秒钟,不需很久,可以是mp4或者avi格式,视频文件的名称随便不重要,主要是同一个文件夹下的所有视频要都属于同一类(如下4文件夹下的所有图片必须全部是4类的人物“扩胸运动”动作,即那个文件夹名称4其实就是这类视频共有的标签,因此你也可以把4改成这类动作的英文名,我是为了图方便)

(文章有修改,漏了验证集的说明)验证集videos_valid的结构和上述训练集videos_train结构其实一样,就是也在videos_valid下新建5个文件夹:1、2、3、4、nothing,其中每个文件夹里面放几个相应的动作,如我在2文件夹就放了1个‘拳击运动’视频mp4,其他文件夹也都只放了一个mp4,具体多少随意。简而言之,训练集和验证集相同结构,只是后者数据少点。

另外还有个必须的json文件,它是关于数据的配置文件,你们可以根据自己的数据修改,如“1”类对应“身体扭动”动作等,即1文件夹中所有视频都属于“身体扭动”这类的;

该文件需要新建,并且放在tools\sense_studio\gesture_lau里面(每个文件放到哪个文件夹都必须严格执行)

如我的project_config.json

{
  "name": "cver",
  "date_created": "2021-02-03",
  "classes": {
    "1": [
      "身体扭动"
    ],
    "2": [
      "拳击运动"
    ],
    "3": [
      "头部运动"
    ],
    "4": [
      "扩胸运动"
    ],
    "nothing": [
      "其他运动"
    ]
  }
}

模型准备:

我在resources文件夹下新建一个backbone文件夹,并将预训练模型放在里面,由于官网被封下不了,大家可以扫描我的微信获取预训练模型:

训练:

打开tools目录下的train_classifier.py,找到

if __name__ == "__main__":

修改里面这一行,变成我们数据存放的文件夹gesture_lau

path_in = './sense_studio/gesture_lau/'

就能直接训练!

训练时,会在gesture_lau文件夹中生成一些过程中产生文件夹或文件,其实都不用管的;其中classifier.checkpoint就是经过训练过我们的动作视频数据的强分类模型,在后面的测试中程序只需稍加改动就会自动从gesture_lau找到并使用

测试:

下面就是看看模型的效果了

打开tools/run_custom_classifier.py,找到

if __name__ == "__main__":

同理,修改里面这一行:

custom_classifier = './sense_studio/gesture_lau/'

并且将 其中的‘classifier.checkpoint’变成我们重新训练好模型,这样的'best_classifier.checkpoint'

# Load custom classifier
    checkpoint_classifier = torch.load(os.path.join(custom_classifier, 'classifier.checkpoint'))

这里的代码让我们也可以检查看看加载的预训练模型是什么

# Load original feature extractor
feature_extractor = feature_extractors.StridedInflatedEfficientNet()feature_extractor.load_weights_from_resources('../resources/backbone/strided_inflated_efficientnet.ckpt')

很明显,就是我们之前放在backbone中的strided_inflated_efficientnet.ckpt,如果不是,需要替换成这样的预训练模型

这样就能直接运行测试了

正常测试时,我在摄像头前做刚才的几类动作就能得到实时分类识别了(但是比如我在做扩胸运动时检测结果显示的是4,虽然4就是‘扩胸运动’的类名,不是直接说明的‘扩胸运动’,这点暂时不知跟源码的哪里有关系,或者可能取文件夹名称的时候直接是‘扩胸运动’可能就直接显示了,你们可自行测试一下)

附 制作小视频的脚本:

最后,我这附上一个脚本,是关于如何快速制作动作视频的,当然,你们也可以用手机拍摄;无论是用脚本生成还是手机拍摄的视频都有存放到前面说到的文件夹中,一类的视频放到同一个文件夹中,不能乱放的,所以还是要像前面说到那样提取建好文件夹的

如果你想用脚本生成小视频的话,在根目录中新建一个py脚本,复制我下面的代码运行就行;跑通它之后你对着摄像头做一下你的相关动作,按q退出就会保存你刚刚的动作视频了;

# coding:utf-8
import random
import time
import cv2
import os
writedir='xinjian'
n=input('请输入类名') #1,2,3
# str和str之间才能相加
name=str(random.randint(1,1000))
houzhui='.mp4'
# 保存的视频的文件名
# 连接两个或更多的路径名组件:如果各组件名首字母不包含’/’,则函数会自动加上
savepath=os.path.join(writedir,n,name+houzhui)
print(savepath)
# 如果类名文件夹不存在要事先创建,否则最后保存视频的时候会无法保存
os.makedirs(os.path.join(writedir,n),exist_ok=True)
time1=time.time()


# VideoCapture()函数读取视频文件,实质是按照一帧一帧循环读取的,
# 它在读到视频文件最后一帧之前,可以利用read()函数来读取新的帧,一帧一帧循环读取。每一帧都是一幅BGR格式的图像。
cap = cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)
cap.set(1, 10.0)
#定义关于视频保存的解码器
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
# VideoWriter()函数,其参数里必须有保存的视频名称,还有上面定义的fourcc参数,帧速率fps,帧大小;
# 另外,fps10为正常,小于10为慢镜头
#定义保存工具为out
out = cv2.VideoWriter(savepath, fourcc,10,(640,480))

while True:
    #若图片读取到最后一帧读完了,此时再用read()来读的时候,ret为0或者False,表明没有图片可以读取了,也就不会进入while循环了
    ret,frame = cap.read()
    if ret == True:
        frame = cv2.flip(frame, 1) #水平翻转
        a = out.write(frame)  #保存
        cv2.imshow("frame", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

        break
cap.release()
out.release()
cv2.destroyAllWindows()

猜你喜欢

转载自blog.csdn.net/qq_46098574/article/details/123958193