发布于 2026-01-06 0 阅读
0

Expressando(第 2 部分):实时手语检测系统

Expressando(第 2 部分):实时手语检测系统

这是我们上一篇文章的后续报道。

在上一篇文章中,我们讨论了“什么是虚拟环境?”“如何使用 OpenCV 配置网络摄像头输入”、“如何检查摄像头输入中的凸性缺陷” 、“什么是凸包?” 、“ 如何显示凸包?”“什么是凸性缺陷?”等概念。今天,你将学习如何使用OpenCV 采集数据数据采集和 TensorFlow 的演示卷积神经网络 (CNN)等等。你还将了解实时预测的工作原理以及其他相关内容。

通过 OpenCV 收集数据并进行标注

collect-data.py在目录内创建一个名为 的文件TDoC-2021。顾名思义,数据收集使用 OpenCV 库收集网络摄像头拍摄的图像。根据输入创建一个或多个数据集,将它们存储在目录中,并根据类别进行处理。

首先,激活你的虚拟环境(这一点非常重要,因为 OpenCV 是安装在虚拟环境内部而不是全局安装的)。然后,分别将 OpenCV 和 OS(包含在 Python 库中)导入为 cv2 和 os。


import cv2

import os

Enter fullscreen mode Exit fullscreen mode

我们将检查数据目录是否存在,该目录将用于存储训练数据和测试数据。如果数据文件夹已存在,则不会创建文件夹,而是将数据以数据集的形式存储,每个数据集代表一个类别。


if not os.path.exists("data"): #True

  os.makedirs("data")

  os.makedirs("data/train") 

  os.makedirs("data/test")

  os.makedirs("data/train/0") 

  os.makedirs("data/train/1")

  os.makedirs("data/train/2")

  os.makedirs("data/train/3")

  os.makedirs("data/train/4")

  os.makedirs("data/train/5")

  os.makedirs("data/test/0")

  os.makedirs("data/test/1")

  os.makedirs("data/test/2")

  os.makedirs("data/test/3")

  os.makedirs("data/test/4")

  os.makedirs("data/test/5")

Enter fullscreen mode Exit fullscreen mode

if not 语句检查目录数据是否存在,而 os.path.exists 方法返回布尔值 &,具体取决于接下来执行哪些代码行。接下来,如果 os.path.exists 返回 False,则 os.makedirs 方法将创建必要的目录。

现在我们将创建一些变量,用于存储图像数据集的文件夹路径。之后,我们需要通过网络摄像头采集所需的图像。为此,我们将使用之前学过的cv2.VideoCapture()初始化方法。

为了让数据采集过程更具互动性和视觉吸引力,我们将在网络摄像头的实时画面中显示一些统计信息。例如,要了解文件夹中已采集的图像数量,我们可以使用这些快捷键,并将它们记录为count对象,并将图像计数保存为一个字典,每个数字对应一个字典。我们可以将这些信息显示在网络摄像头的实时画面中。这可以通过 OpenCV 轻松实现。以下代码即可完成:


cv2.putText(frame, "MODE : "+mode, (30, 50), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (225,255,255), 1)

cv2.putText(frame, "IMAGE COUNT", (10, 100), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (225,255,255), 1)

cv2.putText(frame, "ZERO : "+str(count['zero']), (10, 120), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

cv2.putText(frame, "ONE : "+str(count['one']), (10, 140), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

cv2.putText(frame, "TWO : "+str(count['two']), (10, 160), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

cv2.putText(frame, "THREE : "+str(count['three']), (10, 180), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

cv2.putText(frame, "FOUR : "+str(count['four']), (10, 200), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

cv2.putText(frame, "FIVE : "+str(count['five']), (10, 220), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1

Enter fullscreen mode Exit fullscreen mode

接下来,我们将学习感兴趣区域(ROI)。感兴趣区域(ROI)是指图像中为了进行进一步分析或处理而定义的区域。在这里,感兴趣区域主要包含用于描绘手势的手部区域。我们将使用以下代码定义感兴趣区域:


x1 = int(0.5*frame.shape[1])

y1 = 10

x2 = frame.shape[1]-10

x1 = int(0.5*frame.shape[1])

y1 = 10

x2 = frame.shape[1]-10

y2 = int(0.5*frame.shape[1])

cv2.rectangle(frame, (x1-1, y1-1), (x2+1, y2+1), (255,0,0) ,3)

roi = frame[y1:y2, x1:x2] 

roi = cv2.resize(roi, (200, 200)) 

cv2.putText(frame, "R.O.I", (440, 350), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,225,0), 3)

cv2.imshow("Frame", frame)



roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

_, roi = cv2.threshold(roi, 120, 255, cv2.THRESH_BINARY)

cv2.imshow("ROI", roi)  y2 = int(0.5*frame.shape[1])

cv2.rectangle(frame, (x1-1, y1-1), (x2+1, y2+1), (255,0,0) ,3)

roi = frame[y1:y2, x1:x2] 

roi = cv2.resize(roi, (200, 200)) 

cv2.putText(frame, "R.O.I", (440, 350), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,225,0), 3)

cv2.imshow("Frame", frame)



roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

_, roi = cv2.threshold(roi, 120, 255, cv2.THRESH_BINARY)

cv2.imshow("ROI", roi)

Enter fullscreen mode Exit fullscreen mode

这里,`frame.shape[1]`返回帧或相机输入的形状。接下来,我们将定义一些变量x1, y1, x2, and y2,,它们将作为矩形的对角线(x1,y1)。然后,我们使用`rectangle()`(x2,y2)函数绘制一个围绕 ROI 的矩形,以便在矩形内记录手势。提取后,我们使用`resize()`函数调整并放大感兴趣区域的大小

我们使用模块cv2.COLOR_BGR2GRAY将 ROI 转换为灰度图像。转换完成后,我们将使用函数cv2.threshold()应用一个简单的阈值。我们将使用cv2.THRESH_BINARY模块来应用该阈值。

接下来,我们将根据按键绑定记录数据集中的图像。首先,我们初始化中断变量,这里它每秒返回 10 帧。然后,我们定义所有按键绑定。每当我们按下“0”键时,就会记录“0”键对应的数据。其他数据集也同样适用。

现在你的collect-data.py 文件应该如下所示。


import cv2

import os 



if not os.path.exists("data"): #True

  os.makedirs("data")

  os.makedirs("data/train") 

  os.makedirs("data/test")

  os.makedirs("data/train/0") 

  os.makedirs("data/train/1")

  os.makedirs("data/train/2")

  os.makedirs("data/train/3")

  os.makedirs("data/train/4")

  os.makedirs("data/train/5")

  os.makedirs("data/test/0")

  os.makedirs("data/test/1")

  os.makedirs("data/test/2")

  os.makedirs("data/test/3")

  os.makedirs("data/test/4")

  os.makedirs("data/test/5")





mode = 'train' 

directory = 'data/'+mode+'/' #data/train/



cap=cv2.VideoCapture(0)



while True:

  _, frame = cap.read()

  frame = cv2.flip(frame, 1)



  cv2.putText(frame, "Expressando - TDOC 2021", (175, 450), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (225,255,255), 3)



  count = {'zero': len(os.listdir(directory+"/0")), 

       'one': len(os.listdir(directory+"/1")),

       'two': len(os.listdir(directory+"/2")),

       'three': len(os.listdir(directory+"/3")),

       'four': len(os.listdir(directory+"/4")),

       'five': len(os.listdir(directory+"/5"))} 



  cv2.putText(frame, "MODE : "+mode, (30, 50), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (225,255,255), 1)

  cv2.putText(frame, "IMAGE COUNT", (10, 100), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (225,255,255), 1)

  cv2.putText(frame, "ZERO : "+str(count['zero']), (10, 120), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

  cv2.putText(frame, "ONE : "+str(count['one']), (10, 140), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

  cv2.putText(frame, "TWO : "+str(count['two']), (10, 160), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

  cv2.putText(frame, "THREE : "+str(count['three']), (10, 180), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

  cv2.putText(frame, "FOUR : "+str(count['four']), (10, 200), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)

  cv2.putText(frame, "FIVE : "+str(count['five']), (10, 220), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255,255,255), 1)





  x1 = int(0.5*frame.shape[1])

  y1 = 10

  x2 = frame.shape[1]-10

  y2 = int(0.5*frame.shape[1])

  cv2.rectangle(frame, (x1-1, y1-1), (x2+1, y2+1), (255,0,0) ,3)

  roi = frame[y1:y2, x1:x2] 

  roi = cv2.resize(roi, (200, 200)) 

  cv2.putText(frame, "R.O.I", (440, 350), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,225,0), 3)

  cv2.imshow("Frame", frame)



  roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

  _, roi = cv2.threshold(roi, 120, 255, cv2.THRESH_BINARY)

  cv2.imshow("ROI", roi)



  interrupt = cv2.waitKey(10) 

  if interrupt & 0xFF == 27:

    break

  if interrupt & 0xFF == ord('0'):

    cv2.imwrite(directory+'0/'+str(count['zero'])+'.jpg', roi)

  if interrupt & 0xFF == ord('1'):

    cv2.imwrite(directory+'1/'+str(count['one'])+'.jpg', roi)

  if interrupt & 0xFF == ord('2'):

    cv2.imwrite(directory+'2/'+str(count['two'])+'.jpg', roi)

  if interrupt & 0xFF == ord('3'):

    cv2.imwrite(directory+'3/'+str(count['three'])+'.jpg', roi)

  if interrupt & 0xFF == ord('4'):

    cv2.imwrite(directory+'4/'+str(count['four'])+'.jpg', roi)

  if interrupt & 0xFF == ord('5'):

    cv2.imwrite(directory+'5/'+str(count['five'])+'.jpg', roi)



cap.release()

cv2.destroyAllWindows()

Enter fullscreen mode Exit fullscreen mode

数据采集​​演示及TensorFlow简介

接下来,我们将演示如何更精确地收集数据。这是至关重要的一步,因为它决定了构建模型所需的后续流程。

什么是“数据集”?

数据集是指计算机视为一个整体的数据集合。这意味着数据集包含许多独立的数据/图像片段,但可以用来训练算法,从而在整个数据集中发现可预测的模式。

数据集分为三种类型:

  • 训练数据集- 该数据集包含模型训练所需的所有数据。它包含最大量的数据,主要用于机器的对比测试。

  • 验证数据集- 该数据集用于根据训练数据集验证输入数据的有效性。它是训练数据集的一个子集。它可以排除不必要的输入,从而提高运行速度。

  • 测试数据集- 该数据集用于测试模型,并确定训练过程中产生的准确率和损失。这一点至关重要,因为它作为训练数据的测试集,用户可以验证结果。

替代数据集

现在让我们来看一个如何收集数据的简单例子:

使用以下命令运行 collect-data.py 文件:


python collect-data.py

Enter fullscreen mode Exit fullscreen mode

窗口将打开,并从网络摄像头获取参考输入。它还会在另一个窗口中显示矩形区域(感兴趣区域)的阈值化图像。该图像将被记录在数据集的相应目录中。

  • 我们首先从“零”手势开始,它基本上就是握紧拳头。将手势移到感兴趣区域内,尽可能使其完全包含在矩形框内,并覆盖该区域的大部分面积。

  • 确保背景干净,不要让任何干扰物出现在矩形/感兴趣区域内。尽量采集清晰的数据。确保所有手指都清晰可见。

  • 然后,按下数字键盘上的“0”键开始采集数据。这将捕获图像,这些图像将存储在训练目录下的“0”文件夹中的数据集中。

  • 收集大约100-120 张图像用于训练模型。请确保在矩形区域内改变身体方向的同时收集数据,以便机器能够在你向矩形区域内做出手势输入时识别该手势。

备用零

其他数据集也类似。

现在,数据已经收集完毕,让我们来看看 TensorFlow 能为我们带来什么。

TensorFlow

机器学习的实现是一个复杂的过程,主要涉及实时模型的构建。因此,我们使用端到端的开源框架——TensorFlow,用于收集数据集、通过模型训练系统并基于训练结果提供计算结果。

TensorFlow 是由 Google Creative Labs 开发的开源框架。它支持机器学习,并能帮助用户轻松地用 Python 和 JavaScript(以及 Keras)构建神经网络。TensorFlow 构建了一个网络环境,用于测试机器学习算法,并使用流程图将其可视化。流程图展示了模型中所有节点的执行过程,其中节点代表模型中的操作。

为什么选择 TensorFlow

TensorFlow 提供预构建函数和高级操作 API,简化了构建各种神经网络模型的任务。它提供必要的底层架构和硬件支持,使其成为深度学习领域研究人员和学生广泛使用的领先库之一。

替代 TensorFlow

要开始学习Tensorflow,您可以参考以下教程:

卷积神经网络(CNN)

人工智能正以惊人的速度发展,弥合人类与机器能力之间的差距。研究人员和爱好者们致力于该领域的各个方面,力求创造奇迹。计算机视觉便是其中之一。

该领域的目标是使机器能够像人类一样看待世界,以类似的方式感知世界,甚至利用这些知识来完成图像和视频识别、图像分析和分类、媒体重现、推荐系统、自然语言处理等众多任务。计算机视觉和深度学习的进步是随着时间的推移而构建和完善的,主要基于一种特定的算法——卷积神经网络。

图片描述

要了解更多关于卷积神经网络(CNN)的信息,请访问以下链接:https://deepai.org/machine-learning-glossary-and-terms/convolutional-neural-network

现在让我们来分析一下代码:

在“TDoC-2021”目录下创建一个名为“train_model.py”的文件。顾名思义,它将使用TensorFlowKeras训练模型,其中卷积神经网络将在此基础上进行训练。

首先,我们将从 Keras 导入模型。Keras使用TensorFlow作为后端也就是说,Keras中的函数也使用了TensorFlow中的函数来处理所有结果。

这里我们将使用顺序模型。这种模型适用于一次只有一个输入和一个输出的情况。它本质上是将各个层堆叠起来,并作为一个容器来容纳相互连接的各层。

要了解更多关于顺序模型的信息,请点击此处:

构建卷积神经网络的过程总是包含四个主要步骤。

  • 卷积

  • 池化

  • 扁平化

  • 完全连接

现在,我们将创建以下顺序类的对象:


from keras.models import Sequential

from keras.layers import Convolution2D, MaxPooling2D, Flatten, Dense



classifier = Sequential()

Enter fullscreen mode Exit fullscreen mode

接下来,我们将定义第一个卷积层。它将对图像输入张量进行调制,生成卷积矩阵。生成的矩阵将被合并成一个单一矩阵。该矩阵主要由数学运算数组成,每个运算数都作为一个节点。运算数的选择基于图像的大小、颜色和特征。卷积之后,我们将对矩阵进行最大池化,以减小矩阵的大小,从而提高计算效率。以下代码可以实现这一目标:


classifier.add(Convolution2D(32, (3, 3), input_shape=(64, 64, 1), activation='relu'))

classifier.add(MaxPooling2D(pool_size=(2, 2)))

Enter fullscreen mode Exit fullscreen mode

在这里,add()函数用于在卷积神经网络对象中添加连续层。

我们将使用两种类型的激活函数:

  • relu:全称为修正线性单元(Rectified Linear Unit)。它有助于独立激活层中的神经元/节点。

  • softmax:当存在多个分支时,它有助于激活神经元,并且需要检测同时出现的图形。

想了解更多关于激活函数的信息,请访问:https://www.v7labs.com/blog/neural-networks-activation-functions

同样地,我们将添加第二个卷积层,以提高检测效率。但是,我们不能无限添加层数,因为这会降低速度,而且也可能导致错误的检测结果。

接下来,我们将展平各层,并将它们连接起来,从而构建完整的神经网络。理解展平这一步骤至关重要。我们在这里所做的,实际上是将二维数组(即池化后的图像像素)转换为一维向量。我们使用 `flatten` 函数来执行展平操作,无需添加任何特殊参数,Keras 会自动识别出“classifier”对象已经包含池化后的图像像素,需要对其进行展平。


classifier.add(Flatten())

Enter fullscreen mode Exit fullscreen mode

现在,我们需要创建一个全连接层,并将展平步骤后得到的节点集连接到该层。这些节点将作为全连接层的输入层。由于该层位于输入层和输出层之间,我们可以将其称为隐藏层。

`Dense()`函数用于添加一个全连接层。`Units`参数定义了隐藏层中节点的数量,该值始终介于输入节点数和输出节点数之间。然而,选择最优节点数的技巧只能通过实验摸索。通常的做法是使用 2 的幂次方作为节点数,激活函数则使用整流函数。


classifier.add(Dense(units=128, activation='relu'))

classifier.add(Dense(units=6, activation='softmax'))

Enter fullscreen mode Exit fullscreen mode

模型已经准备好了,接下来需要对其进行编译和组合。


classifier.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

Enter fullscreen mode Exit fullscreen mode

要了解更多关于 Adam 优化的信息,请访问:https://www.geeksforgeeks.org/intuition-of-adam-optimizer/

接下来,我们将导入我们的数据集:训练集和测试集,然后将它们传递给模型进行编译,最终根据输入到模型中的图像来构建模型。


from keras.preprocessing.image import ImageDataGenerator



train_datagen = ImageDataGenerator(

    rescale=1./255,

    shear_range=0.2,

    zoom_range=0.2,

    horizontal_flip=True)



test_datagen = ImageDataGenerator(rescale=1./255)



training_set = train_datagen.flow_from_directory('data/train',

                         target_size=(64, 64),

                         batch_size=5,

                         color_mode='grayscale',

                         class_mode='categorical')



test_set = test_datagen.flow_from_directory('data/test',

                      target_size=(64, 64),

                      batch_size=5,

                      color_mode='grayscale',

                      class_mode='categorical') 

Enter fullscreen mode Exit fullscreen mode

这里我们将使用 ImageDataGenerator 它用于处理图像输入,并使用 CNN 将其转换为机器可读格式。首先,我们将分别定义测试数据和训练数据的生成器,并分别命名为test_datagentrain_datagen。我们将使用 rescale 参数来缩放图像,使用zoom_rangeshear_range来调整图像识别范围,以便在放大倍数达到 0.2 时仍能识别图像。最后,horizo​​ntal_flip参数用于检查图像方向是否正确。

创建数据生成器后,我们需要生成训练集(training_set)测试集(test_set)来构建和测试模型。我们定义目录、色彩空间(灰度)和分类模式(可以是二元分类或类别分类)。我们还将图像的输入尺寸定义为 64 x 64。批次大小指的是每次训练的数据量,这里设置为 5。批次是指连续长度的数据,每次训练都会将这些数据一次性传递给模型。

在准备好输入模型的数据集之后,我们将其拟合到模型层中,以便进行分析和指标计算。


classifier.fit_generator(

    training_set,

    epochs=10,

    validation_data=test_set)

Enter fullscreen mode Exit fullscreen mode

在这里,我们定义之前步骤中生成的数据集。我们将使用训练集(training_set)测试集(test_set)进行测试,并确定准确率和损失。我们将进行 10 个 epoch 的训练。epoch指的是机器学习算法对整个训练数据集的迭代次数。这类似于测试用例,训练集需要通过这些测试用例。这些测试用例用于检查输入是否有效,并测试准确率和损失。

模型准备和测试完成后,需要将其保存为层级数据模型。我们还会将其保存为JSON格式(JavaScript 对象表示法)。之所以采用 JSON 格式,是为了方便用户了解模型的组成和特性。


model_json = classifier.to_json()

with open("model-bw.json", "w") as json_file:

  json_file.write(model_json)

classifier.save_weights('model-bw.h5')

Enter fullscreen mode Exit fullscreen mode

现在你的 train_model.py 文件应该如下所示。


from keras.models import Sequential

from keras.layers import Convolution2D, MaxPooling2D, Flatten, Dense



classifier = Sequential()



classifier.add(Convolution2D(32, (3, 3), input_shape=(64, 64, 1), activation='relu'))

classifier.add(MaxPooling2D(pool_size=(2, 2)))



classifier.add(Convolution2D(32, (3, 3), activation='relu'))

classifier.add(MaxPooling2D(pool_size=(2, 2)))



classifier.add(Flatten())



classifier.add(Dense(units=128, activation='relu'))

classifier.add(Dense(units=6, activation='softmax'))



classifier.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])





from keras.preprocessing.image import ImageDataGenerator



train_datagen = ImageDataGenerator(

    rescale=1./255,

    shear_range=0.2,

    zoom_range=0.2,

    horizontal_flip=True)



test_datagen = ImageDataGenerator(rescale=1./255)



training_set = train_datagen.flow_from_directory('data/train',

                         target_size=(64, 64),

                         batch_size=5,

                         color_mode='grayscale',

                         class_mode='categorical')



test_set = test_datagen.flow_from_directory('data/test',

                      target_size=(64, 64),

                      batch_size=5,

                      color_mode='grayscale',

                      class_mode='categorical') 



classifier.fit_generator(

    training_set,

    epochs=10,

    validation_data=test_set)



model_json = classifier.to_json()

with open("model-bw.json", "w") as json_file:

  json_file.write(model_json)

classifier.save_weights('model-bw.h5')

Enter fullscreen mode Exit fullscreen mode

在 PowerShell/终端中使用以下命令运行代码:


python train_model.py

Enter fullscreen mode Exit fullscreen mode

实时预测定制手语

在“TDoC-2021”目录下创建一个名为“prediction.py”的文件。顾名思义,该文件用于预测我们训练模型时所使用的自定义手势。首先,请激活您的虚拟环境。此外,请确保在运行代码之前已准备好model-bw.h5model-bw.json文件。

接下来,我们将导入cv2operator(Python 标准库中固有的模块)和model_from_json,导入该模块是为了读取JSON文件中的模型内容。


from keras.models import model_from_json

import operator

import cv2

Enter fullscreen mode Exit fullscreen mode

这里,我们将声明对象 json_file,它将解析与 prediction.py 文件位于同一目录下的 model-bw.json 文件。接下来,我们将解析 json_file 的内容,其中已经包含了 model-bw.json 的内容。

然后,我们使用 read() 和 close() 函数将文件中的内容存储到对象 model_json 中。

接下来,我们将分别使用 `load_weights()` 和 `model_from_json()` 函数同时加载数据模型和 JSON 模型。模型加载成功后,终端/PowerShell 将显示“Loaded model from disk”。

接下来,我们初始化了一个名为“cap”的视频捕获对象。然后,我们声明了一个名为“categories”的字典,其键索引为整数。这有助于渲染与键索引对应的字符串值,这些字符串值将显示在预测结果中。


json_file = open("model-bw.json", "r")

model_json = json_file.read()

json_file.close()

loaded_model = model_from_json(model_json)

loaded_model.load_weights("model-bw.h5")

print("Loaded model from disk")

cap = cv2.VideoCapture(0) 



categories = {0: 'ZERO', 1: 'ONE', 2: 'TWO', 3: 'THREE', 4: 'FOUR', 5: 'FIVE'}

Enter fullscreen mode Exit fullscreen mode

然后,我们将初始化一个 while 循环,只要视频正在录制或遇到 break 语句,该循环就会无限运行。接着,我们使用 cap.read() 函数读取视频帧,并使用 flip() 函数反转读取到的帧。


while True:

  _, frame = cap.read()

  frame = cv2.flip(frame, 1)



  x1 = int(0.5*frame.shape[1])

  y1 = 10

  x2 = frame.shape[1]-10

  y2 = int(0.5*frame.shape[1])



  cv2.putText(frame, "Expressando - TDOC 2021", (175, 450), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (225,255,0), 3)

  cv2.rectangle(frame, (x1-1, y1-1), (x2+1, y2+1), (255,255,255) ,3)

  roi = frame[y1:y2, x1:x2]



  roi = cv2.resize(roi, (64, 64)) 

  roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

  cv2.putText(frame, "R.O.I", (440, 350), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,225,0), 3)



  _, test_image = cv2.threshold(roi, 120, 255, cv2.THRESH_BINARY)

  cv2.imshow("ROI", test_image)

Enter fullscreen mode Exit fullscreen mode

接下来,我们将定义感兴趣区域,也就是我们将要展示手势的区域。我们之前的文档中已经讨论过如何定义感兴趣区域。然后,我们将使用 `rectangle()` 函数将感兴趣区域框定在一个矩形框内,以便用户知道手势将被检测到的位置。


  result = loaded_model.predict(test_image.reshape(1, 64, 64, 1))

  prediction = {'ZERO': result[0][0], 

         'ONE': result[0][1], 

         'TWO': result[0][2],

         'THREE': result[0][3],

         'FOUR': result[0][4],

         'FIVE': result[0][5]} 

  prediction = sorted(prediction.items(), key=operator.itemgetter(1), reverse=True)

  cv2.putText(frame, "PREDICTION:", (30, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)

  cv2.putText(frame, prediction[0][0], (80, 130), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)   

  cv2.imshow("Frame", frame)

Enter fullscreen mode Exit fullscreen mode

我们将使用`predict()`函数,它能够基于训练好的模型预测数据值的标签。该函数只接受一个参数,通常是待测试的数据。它会根据模型学习到的训练数据,返回作为参数传递的数据的标签。因此,`predict()` 函数基于训练好的模型运行,并利用学习到的标签来映射和预测待测试数据的标签。我们将把 `test_image` 图像重塑为卷积神经网络的输入尺寸(64 x 64 x 1) ,然后传递给该函数。

然后,我们声明一个名为prediction 的字典,其键为字符串中的整数名称,该字典返回result[0][key]。这里 result[0] 指的是列表中的第一个元素,即类别字典。接下来,我们根据result[0][key]中的键值解析结果

接下来,我们对prediction.items()进行排序,它表示您在感兴趣区域 (ROI) 中显示的输入手势与用于训练模型的图像/数据集相似的概率。operator.itemgetter (1)可以帮助我们对多列进行排序。此外,reverse=True表示按降序排列,使得prediction[0][0]包含概率最大的字符串整数

然后,我们将使用putText()函数在框架上显示字符串,然后使用imshow()函数在名为“Frame”的框架下显示该框架。

接下来,我们初始化中断变量,这里它返回每秒 10 帧。0xFF 收集并识别键盘响应,并将其与Esc 键匹配。然后,检测完成后,我们释放摄像头并释放所有渲染到图像数组向量的内存。这在之前的文档中已有说明。

现在你的 prediction.py 文件应该如下所示。


from keras.models import model_from_json

import operator

import cv2



json_file = open("model-bw.json", "r")

model_json = json_file.read()

json_file.close()

loaded_model = model_from_json(model_json)

loaded_model.load_weights("model-bw.h5")

print("Loaded model from disk")



cap = cv2.VideoCapture(0) 



categories = {0: 'ZERO', 1: 'ONE', 2: 'TWO', 3: 'THREE', 4: 'FOUR', 5: 'FIVE'}



while True:

  _, frame = cap.read()

  frame = cv2.flip(frame, 1)



  x1 = int(0.5*frame.shape[1])

  y1 = 10

  x2 = frame.shape[1]-10

  y2 = int(0.5*frame.shape[1])



  cv2.putText(frame, "Expressando - TDOC 2021", (175, 450), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (225,255,0), 3)

  cv2.rectangle(frame, (x1-1, y1-1), (x2+1, y2+1), (255,255,255) ,3)

  roi = frame[y1:y2, x1:x2]



  roi = cv2.resize(roi, (64, 64)) 

  roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

  cv2.putText(frame, "R.O.I", (440, 350), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,225,0), 3)



  _, test_image = cv2.threshold(roi, 120, 255, cv2.THRESH_BINARY)

  cv2.imshow("ROI", test_image)



  result = loaded_model.predict(test_image.reshape(1, 64, 64, 1))

  prediction = {'ZERO': result[0][0], 

         'ONE': result[0][1], 

         'TWO': result[0][2],

         'THREE': result[0][3],

         'FOUR': result[0][4],

         'FIVE': result[0][5]} 

  prediction = sorted(prediction.items(), key=operator.itemgetter(1), reverse=True) 

  cv2.putText(frame, "PREDICTION:", (30, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)

  cv2.putText(frame, prediction[0][0], (80, 130), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)   

  cv2.imshow("Frame", frame)



  interrupt = cv2.waitKey(10)

  if interrupt & 0xFF == 27:

    break





cap.release()

cv2.destroyAllWindows()

Enter fullscreen mode Exit fullscreen mode

在 PowerShell/终端中使用以下命令运行代码:


python prediction.py

Enter fullscreen mode Exit fullscreen mode

现在,来看看实时手语检测的实际效果吧!!!

另类预测

感谢您阅读本文。希望您在构建这个项目的过程中收获了美好的体验,并且对机器学习有了更深入的了解。

愿源泉与你同在!🐧❤️

文章来源:https://dev.to/nitdgplug/expressando-part-2-a-real-time-sign-language-detection-system-3h1f