当前位置:   article > 正文

带你开发一个视频动态手势识别模型

带你开发一个视频动态手势识别模型

本文分享自华为云社区《CNN-VIT 视频动态手势识别【玩转华为云】》,作者: HouYanSong。

cke_127.gif

人工智能的发展日新月异,也深刻的影响到人机交互领域的发展。手势动作作为一种自然、快捷的交互方式,在智能驾驶、虚拟现实等领域有着广泛的应用。手势识别的任务是,当操作者做出某个手势动作后,计算机能够快速准确的判断出该手势的类型。本文将使用ModelArts开发训练一个视频动态手势识别的算法模型,对上滑、下滑、左滑、右滑、打开、关闭等动态手势类别进行检测,实现类似华为手机隔空手势的功能。

算法简介

CNN-VIT 视频动态手势识别算法首先使用预训练网络InceptionResNetV2逐帧提取视频动作片段特征,然后输入Transformer Encoder进行分类。我们使用动态手势识别样例数据集对算法进行测试,总共包含108段视频,数据集包含无效手势、上滑、下滑、左滑、右滑、打开、关闭等7种手势的视频,具体操作流程如下:

cke_128.png

首先我们将采集的视频文件解码抽取关键帧,每隔4帧保存一次,然后对图像进行中心裁剪和预处理,代码如下:

  1. def load_video(file_name):
  2. cap = cv2.VideoCapture(file_name)
  3. # 每隔多少帧抽取一次
  4. frame_interval = 4
  5. frames = []
  6. count = 0
  7. while True:
  8. ret, frame = cap.read()
  9. if not ret:
  10. break
  11. # 每隔frame_interval帧保存一次
  12. if count % frame_interval == 0:
  13. # 中心裁剪
  14. frame = crop_center_square(frame)
  15. # 缩放
  16. frame = cv2.resize(frame, (IMG_SIZE, IMG_SIZE))
  17. # BGR -> RGB [0,1,2] -> [2,1,0]
  18. frame = frame[:, :, [2, 1, 0]]
  19. frames.append(frame)
  20. count += 1
  21. return np.array(frames)

然后我们创建图像特征提取器,使用预训练模型InceptionResNetV2提取图像特征,代码如下:

  1. def get_feature_extractor():
  2. feature_extractor = keras.applications.inception_resnet_v2.InceptionResNetV2(
  3. weights = 'imagenet',
  4. include_top = False,
  5. pooling = 'avg',
  6. input_shape = (IMG_SIZE, IMG_SIZE, 3)
  7. )
  8. preprocess_input = keras.applications.inception_resnet_v2.preprocess_input
  9. inputs = keras.Input((IMG_SIZE, IMG_SIZE, 3))
  10. preprocessed = preprocess_input(inputs)
  11. outputs = feature_extractor(preprocessed)
  12. model = keras.Model(inputs, outputs, name = 'feature_extractor')
  13. return model

接着提取视频特征向量,如果视频不足40帧就创建全0数组进行补白:

  1. def load_data(videos, labels):
  2. video_features = []
  3. for video in tqdm(videos):
  4. frames = load_video(video)
  5. counts = len(frames)
  6. # 如果帧数小于MAX_SEQUENCE_LENGTH
  7. if counts < MAX_SEQUENCE_LENGTH:
  8. # 补白
  9. diff = MAX_SEQUENCE_LENGTH - counts
  10. # 创建全0的numpy数组
  11. padding = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))
  12. # 数组拼接
  13. frames = np.concatenate((frames, padding))
  14. # 获取前MAX_SEQUENCE_LENGTH帧画面
  15. frames = frames[:MAX_SEQUENCE_LENGTH, :]
  16. # 批量提取特征
  17. video_feature = feature_extractor.predict(frames)
  18. video_features.append(video_feature)
  19. return np.array(video_features), np.array(labels)

最后创建VIT Model,代码如下:

  1. # 位置编码
  2. class PositionalEmbedding(layers.Layer):
  3. def __init__(self, seq_length, output_dim):
  4. super().__init__()
  5. # 构造从0~MAX_SEQUENCE_LENGTH的列表
  6. self.positions = tf.range(0, limit=MAX_SEQUENCE_LENGTH)
  7. self.positional_embedding = layers.Embedding(input_dim=seq_length, output_dim=output_dim)
  8. def call(self,x):
  9. # 位置编码
  10. positions_embedding = self.positional_embedding(self.positions)
  11. # 输入相加
  12. return x + positions_embedding
  13. # 编码器
  14. class TransformerEncoder(layers.Layer):
  15. def __init__(self, num_heads, embed_dim):
  16. super().__init__()
  17. self.p_embedding = PositionalEmbedding(MAX_SEQUENCE_LENGTH, NUM_FEATURES)
  18. self.attention = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, dropout=0.1)
  19. self.layernorm = layers.LayerNormalization()
  20. def call(self,x):
  21. # positional embedding
  22. positional_embedding = self.p_embedding(x)
  23. # self attention
  24. attention_out = self.attention(
  25. query = positional_embedding,
  26. value = positional_embedding,
  27. key = positional_embedding,
  28. attention_mask = None
  29. )
  30. # layer norm with residual connection
  31. output = self.layernorm(positional_embedding + attention_out)
  32. return output
  33. def video_cls_model(class_vocab):
  34. # 类别数量
  35. classes_num = len(class_vocab)
  36. # 定义模型
  37. model = keras.Sequential([
  38. layers.InputLayer(input_shape=(MAX_SEQUENCE_LENGTH, NUM_FEATURES)),
  39. TransformerEncoder(2, NUM_FEATURES),
  40. layers.GlobalMaxPooling1D(),
  41. layers.Dropout(0.1),
  42. layers.Dense(classes_num, activation="softmax")
  43. ])
  44. # 编译模型
  45. model.compile(optimizer = keras.optimizers.Adam(1e-5),
  46. loss = keras.losses.SparseCategoricalCrossentropy(from_logits=False),
  47. metrics = ['accuracy']
  48. )
  49. return model

模型训练

完整体验可以点击Run in ModelArts一键运行我发布的Notebook

cke_129.png

最终模型在整个数据集上的准确率达到87%,即在小数据集上训练取得了较为不错的结果。

视频推理

首先加载VIT Model,获取视频类别索引标签:

  1. import random
  2. # 加载模型
  3. model = tf.keras.models.load_model('saved_model')
  4. # 类别标签
  5. label_to_name = {0:'无效手势', 1:'上滑', 2:'下滑', 3:'左滑', 4:'右滑', 5:'打开', 6:'关闭', 7:'放大', 8:'缩小'}

然后使用图像特征提取器InceptionResNetV2提取视频特征:

  1. # 获取视频特征
  2. def getVideoFeat(frames):
  3. frames_count = len(frames)
  4. # 如果帧数小于MAX_SEQUENCE_LENGTH
  5. if frames_count < MAX_SEQUENCE_LENGTH:
  6. # 补白
  7. diff = MAX_SEQUENCE_LENGTH - frames_count
  8. # 创建全0的numpy数组
  9. padding = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))
  10. # 数组拼接
  11. frames = np.concatenate((frames, padding))
  12. # 取前MAX_SEQ_LENGTH
  13. frames = frames[:MAX_SEQUENCE_LENGTH,:]
  14. # 计算视频特征 N, 1536
  15. video_feat = feature_extractor.predict(frames)
  16. return video_feat

最后将视频序列的特征向量输入Transformer Encoder进行预测:

  1. # 视频预测
  2. def testVideo():
  3. test_file = random.sample(videos, 1)[0]
  4. label = test_file.split('_')[-2]
  5. print('文件名:{}'.format(test_file) )
  6. print('真实类别:{}'.format(label_to_name.get(int(label))) )
  7. # 读取视频每一帧
  8. frames = load_video(test_file)
  9. # 挑选前帧MAX_SEQUENCE_LENGTH显示
  10. frames = frames[:MAX_SEQUENCE_LENGTH].astype(np.uint8)
  11. # 保存为GIF
  12. imageio.mimsave('animation.gif', frames, duration=10)
  13. # 获取特征
  14. feat = getVideoFeat(frames)
  15. # 模型推理
  16. prob = model.predict(tf.expand_dims(feat, axis=0))[0]
  17. print('预测类别:')
  18. for i in np.argsort(prob)[::-1][:5]:
  19. print('{}: {}%'.format(label_to_name[i], round(prob[i]*100, 2)))
  20. return display(Image(open('animation.gif', 'rb').read()))

模型预测结果:

  1. 文件名:hand_gesture/woman_014_0_7.mp4
  2. 真实类别:无效手势
  3. 预测类别:
  4. 无效手势: 99.82%
  5. 下滑: 0.12%
  6. 关闭: 0.04%
  7. 左滑: 0.01%
  8. 打开: 0.01%

点击关注,第一时间了解华为云新鲜技术~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/552724
推荐阅读
相关标签
  

闽ICP备14008679号