深度学习实战:基于TensorFlow与OpenCV的手语识别系统

文章目录

  • 写在前面
  • 基于TensorFlow与OpenCV的手语识别系统
    • 安装环境
    • 一、导入工具库
    • 二、导入数据集
    • 三、数据预处理
    • 四、训练模型
      • 基于CNN
      • 基于LeNet5
      • 基于ResNet50
    • 五、模型预测
      • 基于OpenCV
  • 写在后面

写在前面

本期内容:基于TensorFlow与OpenCV的手语识别系统

实验环境:
python(3.11.4)
tensorflow(2.13.0)
cv2(4.8.0)

注:本专栏内所有文章都包含完整代码以及数据集

基于TensorFlow与OpenCV的手语识别系统

安装环境

pip install tensorflow
pip install cv2

一、导入工具库

# 导入工具库
import pandas as pd
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import warnings
from tensorflow import keras
warnings.filterwarnings("ignore")

这些是Python中的标准库及第三方库及其相关的模块。

具体来说,这个代码导入了以下库:

  • Pandas:数据分析和数据处理库。
  • NumPy:科学计算库,用于处理多维数组和矩阵。
  • TensorFlow:机器学习和深度学习框架。
  • Matplotlib:绘图库,用于可视化数据。
  • Warnings:警告管理模块,用于忽略警告。
  • Keras:高层神经网络API,可以使用多种深度学习框架作为后端。

二、导入数据集

# 读取数据
test = pd.read_csv("sign_mnist/sign_mnist_test.csv")
train = pd.read_csv("sign_mnist/sign_mnist_train.csv")# 输出基本信息
print("训练集维度", train.shape)
print("测试集维度", train.shape)
训练集维度 (27455, 785)
测试集维度 (27455, 785)

这段代码使用 Pandas 库中的 read_csv 函数读取了两个 CSV 文件:sign_mnist_train.csv(训练集)和 sign_mnist_test.csv(测试集),分别存储在 train 和 test 变量中。

接下来使用 shape 属性分别输出了训练集和测试集的维度信息,即行数和列数。train.shape 输出结果为训练集的行数和列数,test.shape 输出结果为测试集的行数和列数。可以看到 train 和 test 数据集都有 7,995 行和 785 列,其中前 784 列是图片的像素信息,最后一列是标签信息,标识了每个手语图片所表示的字母。

三、数据预处理

# 切分特征与标签
train_x = train.drop(labels = "label", axis = 1)
train_y = train["label"]
test_x = test.drop(labels = "label", axis = 1)
test_y = test["label"]# 转为numpy格式
train_x = train_x.to_numpy()
test_x = test_x.to_numpy()
train_y = train_y.to_numpy()
test_y = test_y.to_numpy()# 把数据转为3维图像数据(图片数量*宽*高*通道)
train_x = train_x.reshape(-1,28,28,1)
test_x = test_x.reshape(-1,28,28,1)# 输出基本信息
train_x.shape, train_y.shape, test_x.shape, test_y.shape
((27455, 28, 28, 1), (27455,), (7172, 28, 28, 1), (7172,))

这段代码将训练集和测试集的特征和标签分别切分成 train_x、train_y 和 test_x、test_y 四个变量。

train_x 和 test_x 存储了训练集和测试集的特征信息,即手语图片的像素信息,这些信息被存储在 CSV 文件中的前 784 列。这里使用了 pandas 库的 drop 函数删除了每个样本的标签信息,axis = 1 表示删除列。

train_y 和 test_y 存储了训练集和测试集的标签信息,即每个手语图片所代表的字母。

接下来,使用 Pandas 库的 to_numpy 函数将 train_x、test_x、train_y、test_y 四个变量转换为 NumPy 数组。

由于卷积神经网络需要输入 3 维的图片数据,所以将 train_x 和 test_x 从 2 维重塑为 3 维,分别代表图片数量、宽度、高度和通道数(这里的通道数为 1)。

最后,使用 shape 属性输出 train_x、train_y、test_x、test_y 这四个变量的维度信息。可以看到 train_x 和 test_x 变为了 4 维的数组(图片数量、宽度、高度和通道数为 1),而 train_y 和 test_y 仍然是 1 维的数组(标签数)。

四、训练模型

基于CNN

卷积神经网络(CNN)是一种非常强大的深度学习算法,广泛应用于图像处理、计算机视觉和自然语言处理等领域。它是一种基于神经网络的监督学习算法,可以有效地识别和分类图像。

CNN算法的主要思想是通过卷积核从图像中提取重要的特征,然后将这些特征传递给全连接层进行分类。卷积核是一种模板,它可以应用于输入图像中的每个像素,并计算出一个新的特征图。通过不断应用卷积核,可以提取出图像中的多种特征。

CNN的结构主要由卷积层、池化层、全连接层三部分组成。卷积层是CNN中最重要的层,它通过不断应用卷积核来提取图像的特征,得到多个特征图。池化层主要用于减少特征图的维度,通过选择最大值或平均值来进行下采样。全连接层用于对特征进行分类,将特征图展开成向量,然后将其传递给一个或多个全连接层来输出分类结果。最后在输出层使用softmax函数进行分类输出。

程序设计

# CNN
def CNN():model = tf.keras.models.Sequential([# 卷积层tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)),# 池化层tf.keras.layers.MaxPooling2D(2,2),# 卷积层tf.keras.layers.Conv2D(32, (3,3), activation='relu'),# 池化层tf.keras.layers.MaxPooling2D(2,2),# 展平tf.keras.layers.Flatten(),# 全连接层tf.keras.layers.Dense(512, activation='relu'),# softmax分类tf.keras.layers.Dense(26, activation='softmax')])model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) #评估准则return model# 初始化
cnn = CNN()
# 配置
cnn.compile(optimizer="adam",metrics=["accuracy"],loss = "sparse_categorical_crossentropy")
# 训练
cnn.fit(train_x, train_y, validation_data = (test_x, test_y), epochs =10)
# 保存模型
cnn.save_weights("CNN_weights.h")# 评估模型
cnn = CNN()
cnn.load_weights("CNN_weights.h")
cnn.compile(optimizer="adam",metrics=["accuracy"],loss = "sparse_categorical_crossentropy")
score = cnn.evaluate(test_x, test_y, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])

这段代码定义了一个卷积神经网络模型。该模型包含了两个卷积层、两个最大池化层、一个全连接层和一个 softmax 分类层。

接下来,使用 compile 函数对模型进行配置。这里使用了 Adam 优化器、稀疏分类交叉熵损失函数和 accuracy 准确率评估指标。然后使用 fit 函数对模型进行训练。在训练过程中,使用了训练集和测试集进行验证,并设置了 epochs 参数为 10,即训练 10 轮。训练完毕后,使用 save_weights 函数保存训练好的模型权重。

接下来,重新加载保存的模型,使用 evaluate 函数对模型进行评估,并输出测试集的损失和准确率。

最后值得注意的是,代码中定义了一个 CNN 函数,用于返回模型对象。这样做的好处是,如果想要调整模型结构或者参数,只需要修改该函数即可,而不需要改动其他代码。

运行结果

Epoch 1/10
858/858 [==============================] - 13s 15ms/step - loss: 0.5334 - accuracy: 0.8840 - val_loss: 0.6763 - val_accuracy: 0.8371
Epoch 2/10
858/858 [==============================] - 13s 15ms/step - loss: 0.0507 - accuracy: 0.9848 - val_loss: 0.6326 - val_accuracy: 0.8595
Epoch 3/10
858/858 [==============================] - 14s 16ms/step - loss: 4.3012e-04 - accuracy: 1.0000 - val_loss: 0.6390 - val_accuracy: 0.8756
Epoch 4/10
858/858 [==============================] - 14s 17ms/step - loss: 1.2322e-04 - accuracy: 1.0000 - val_loss: 0.6612 - val_accuracy: 0.8779
Epoch 5/10
858/858 [==============================] - 14s 17ms/step - loss: 6.9371e-05 - accuracy: 1.0000 - val_loss: 0.6816 - val_accuracy: 0.8826
Epoch 6/10
858/858 [==============================] - 14s 17ms/step - loss: 4.1090e-05 - accuracy: 1.0000 - val_loss: 0.6932 - val_accuracy: 0.8784
Epoch 7/10
858/858 [==============================] - 13s 16ms/step - loss: 2.5985e-05 - accuracy: 1.0000 - val_loss: 0.7071 - val_accuracy: 0.8836
Epoch 8/10
858/858 [==============================] - 14s 16ms/step - loss: 1.6751e-05 - accuracy: 1.0000 - val_loss: 0.7241 - val_accuracy: 0.8837
Epoch 9/10
858/858 [==============================] - 15s 18ms/step - loss: 1.0805e-05 - accuracy: 1.0000 - val_loss: 0.7379 - val_accuracy: 0.8813
Epoch 10/10
858/858 [==============================] - 15s 17ms/step - loss: 7.0634e-06 - accuracy: 1.0000 - val_loss: 0.7716 - val_accuracy: 0.8823Test loss: 0.7715592384338379
Test accuracy: 0.8823201060295105

基于LeNet5

LeNet5是一种经典的卷积神经网络结构,是Yann LeCun等人于1998年提出的,是图像识别领域中最早的深度学习算法之一。它将卷积层、池化层以及全连接层结合在一起,能够有效地处理图像数据。这个网络被广泛应用于手写数字识别、人脸识别和车牌识别等方面,并开创了卷积神经网络应用的新时代。

LeNet5网络结构的主要特点是由两个卷积层、两个池化层和三个全连接层组成,包含大约6万个权重和6百多个神经元。相比于其他深度学习算法,它非常小巧,并且便于实现和理解。

LeNet5的第一个卷积层是用于提取输入图像的低级特征的,第二个卷积层用于提取高级特征。两个池化层用于减小特征图的大小,以降低网络参数的数量,并增加网络的鲁棒性。全连接层用于将特征向量分类为不同的类别。

LeNet5的训练方式是基于误差反向传播算法。在训练的过程中,网络通过不断的迭代优化权重和偏置,以最小化损失函数。误差反向传播算法的本质是通过比较网络输出与实际标签之间的差异来计算损失,然后将损失反向传播到网络中,以调整权重和偏置的值,从而使网络的输出更接近实际标签。

LeNet5在当时的手写数字识别领域中取得了良好的效果,并开创了卷积神经网络应用的新时代。随着深度学习的发展,LeNet5逐渐被更加先进的卷积神经网络所取代。但是,它作为深度学习早期的里程碑之一,仍然是学习和了解卷积神经网络发展历史的重要基础。

程序设计

# LeNet5
def LeNet5():model = tf.keras.models.Sequential([# 第一层卷积层,使用6个5x5的卷积核,步长为1tf.keras.layers.Conv2D(6, (5,5), activation='relu', input_shape=(28, 28, 1), padding='valid'),# 第一层平均池化层,使用2x2的池化窗口,步长为2tf.keras.layers.AveragePooling2D(pool_size=(2, 2), strides=(2, 2), padding='valid'),# 第二层卷积层,使用16个5x5的卷积核,步长为1tf.keras.layers.Conv2D(16, (5,5), activation='relu', padding='valid'),# 第二层平均池化层,使用2x2的池化窗口,步长为2tf.keras.layers.AveragePooling2D(pool_size=(2, 2), strides=(2, 2), padding='valid'),# 展平tf.keras.layers.Flatten(),# 第一层全连接层,输出120维向量tf.keras.layers.Dense(units=120, activation='relu'),# 第二层全连接层,输出84维向量tf.keras.layers.Dense(units=84, activation='relu'),# softmax分类tf.keras.layers.Dense(units=26, activation='softmax')])model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])return model

这段代码定义了一个 LeNet-5 模型。与 CNN 模型相似,该模型包含了两个卷积层、两个平均池化层、两个全连接层和一个 softmax 分类层。与 CNN 模型不同的是,该模型使用了不同的卷积核大小和步长,且加入了平均池化层。

接下来,使用 compile 函数对模型进行配置。这里使用了 Adam 优化器、稀疏分类交叉熵损失函数和 accuracy 准确率评估指标。然后使用 LeNet5 函数返回模型对象。

可以发现,该模型是经典的 LeNet-5 模型,是早期卷积神经网络的代表。虽然该模型相对简单,但其依然可以在手写数字识别等问题上取得相对良好的表现。

# 初始化
lenet5 = LeNet5()
# 配置
lenet5.compile(optimizer="adam",metrics=["accuracy"],loss = "sparse_categorical_crossentropy")
# 训练
lenet5.fit(train_x, train_y, validation_data = (test_x, test_y), epochs =10)
# 保存模型
lenet5.save_weights("LeNet5_weights.h")
Epoch 1/10
858/858 [==============================] - 6s 6ms/step - loss: 0.8555 - accuracy: 0.7541 - val_loss: 0.6739 - val_accuracy: 0.8066
Epoch 2/10
858/858 [==============================] - 5s 6ms/step - loss: 0.0495 - accuracy: 0.9863 - val_loss: 0.6888 - val_accuracy: 0.8318
Epoch 3/10
858/858 [==============================] - 5s 6ms/step - loss: 0.0479 - accuracy: 0.9858 - val_loss: 0.8006 - val_accuracy: 0.8101
Epoch 4/10
858/858 [==============================] - 5s 6ms/step - loss: 0.0194 - accuracy: 0.9945 - val_loss: 0.5524 - val_accuracy: 0.8567
Epoch 5/10
858/858 [==============================] - 5s 6ms/step - loss: 1.8097e-04 - accuracy: 1.0000 - val_loss: 0.5774 - val_accuracy: 0.8707
Epoch 6/10
858/858 [==============================] - 6s 7ms/step - loss: 6.7714e-05 - accuracy: 1.0000 - val_loss: 0.6000 - val_accuracy: 0.8713
Epoch 7/10
858/858 [==============================] - 7s 8ms/step - loss: 3.6441e-05 - accuracy: 1.0000 - val_loss: 0.6284 - val_accuracy: 0.8696
Epoch 8/10
858/858 [==============================] - 6s 7ms/step - loss: 2.2162e-05 - accuracy: 1.0000 - val_loss: 0.6540 - val_accuracy: 0.8681
Epoch 9/10
858/858 [==============================] - 7s 8ms/step - loss: 1.3525e-05 - accuracy: 1.0000 - val_loss: 0.6863 - val_accuracy: 0.8684
Epoch 10/10
858/858 [==============================] - 6s 7ms/step - loss: 8.3553e-06 - accuracy: 1.0000 - val_loss: 0.6980 - val_accuracy: 0.8674
# 评估模型
resnet50 = LeNet5()
resnet50.load_weights("LeNet5_weights.h")
resnet50.compile(optimizer="adam",metrics=["accuracy"],loss = "sparse_categorical_crossentropy")
score = resnet50.evaluate(test_x, test_y, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])
Test loss: 0.6979857087135315
Test accuracy: 0.8674010038375854

基于ResNet50

ResNet50是一种深度卷积神经网络,由Microsoft Research的Kaiming He等人于2015年提出。ResNet50是ResNet系列中的一个重要成员,需要训练的参数数量很大,但是具有非常高的准确性。

ResNet50网络结构包含50个卷积层,因此得名ResNet50。相对于传统的卷积神经网络,ResNet50通过引入残差模块来解决深度神经网络中梯度消失和梯度爆炸等问题。残差模块可以帮助神经网络在训练过程中更加容易地学习到有效的特征表征,从而提高网络的准确性。

ResNet50的残差模块主要包含了残差连接和批量标准化两个部分。残差连接是指在卷积层和全连接层之间添加一个旁路,使得输入的特征可以直接通过此旁路被输出到下一层,从而提高训练效率。批量标准化是指对网络的特征图进行归一化,减少特征之间的耦合,从而帮助神经网络更快更好地学习到有效的特征表征。

ResNet50的训练方式是基于端到端的误差反向传播算法,也就是通过比较网络输出与实际标签之间的差异来计算损失,然后通过反向传播算法不断优化网络权重和偏置,从而使得网络输出更加接近实际标签。

ResNet50在计算机视觉领域中取得了很好的效果,在ImageNet图像分类竞赛中获得了很高的排名,并且在其他各种图像处理任务中也获得了很好的表现。它的应用场景非常广泛,包括人脸识别、物体检测、图像分割等各种领域。

总之,ResNet50是一种非常有效的深度卷积神经网络结构,在图像识别领域取得了很好的表现。它通过引入残差模块来解决深度神经网络中的问题,并以其高精度、高鲁棒性和高可靠性成为了深度学习领域的经典之作。

程序设计

# 定义ResNet-50模型的标识块
def identity_block(X, f, filters, training=True):f1,f2,f3 = filtersX_shortcut = X X = tf.keras.layers.Conv2D(filters = f1, kernel_size = 1, strides = (1,1), padding = 'valid')(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axisX = tf.keras.layers.Activation('relu')(X)X = tf.keras.layers.Conv2D(filters = f2, kernel_size = f, strides = (1,1), padding = 'same')(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axisX = tf.keras.layers.Activation('relu')(X)X = tf.keras.layers.Conv2D(filters = f3, kernel_size = 1, strides = (1,1), padding = 'valid')(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axisX = tf.keras.layers.Add()([X_shortcut,X])X = tf.keras.layers.Activation('relu')(X)return X# 定义ResNet-50模型的卷积块 
def convolutional_block(X, f, filters, s=2,training=True):# filter of the three convs f1,f2,f3 = filtersX_shortcut = X X = tf.keras.layers.Conv2D(filters = f1, kernel_size = 1, strides = (1,1), padding = 'valid')(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axisX = tf.keras.layers.Activation('relu')(X)X = tf.keras.layers.Conv2D(filters = f2, kernel_size = f, strides = (s,s), padding = 'same')(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axisX = tf.keras.layers.Activation('relu')(X)X = tf.keras.layers.Conv2D(filters = f3, kernel_size = 1, strides = (1,1), padding = 'valid')(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axisX_shortcut =tf.keras.layers.Conv2D(filters = f3, kernel_size = 1, strides = (s,s), padding = 'valid')(X_shortcut)X_shortcut = tf.keras.layers.BatchNormalization(axis = 3)(X_shortcut, training = training)X = tf.keras.layers.Add()([X_shortcut,X])X = tf.keras.layers.Activation('relu')(X)X = tf.keras.layers.Add()([X, X_shortcut])X = tf.keras.layers.Activation('relu')(X)return X# 使用标识块和卷积块定义修改的ResNet-50模型
def ResNet50(input_shape = (28, 28, 1), classes = 26):X_input = tf.keras.Input(input_shape)X = tf.keras.layers.ZeroPadding2D((3, 3))(X_input)X = tf.keras.layers.Conv2D(64, (5, 5), strides = (1, 1))(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X)X = tf.keras.layers.Activation('relu')(X)X = tf.keras.layers.MaxPooling2D((3, 3), strides=(2, 2))(X)X = convolutional_block(X, f = 3, filters = [64, 64, 256], s = 1)X = identity_block(X, 3, [64, 64, 256])X = identity_block(X, 3, [64, 64, 256])X = tf.keras.layers.AveragePooling2D((2,2))(X)X = tf.keras.layers.Flatten()(X)X = tf.keras.layers.Dense(classes, activation='softmax')(X)model = tf.keras.Model(inputs = X_input, outputs = X)return model

这段代码定义了 ResNet-50 模型的标识块、卷积块和整个模型。ResNet-50 模型是在传统的卷积神经网络模型基础上增加了残差链接,可以更好地解决梯度消失等问题,进而训练更深的网络。

在这里,定义了 identity_block 函数和 convolutional_block 函数分别对应 ResNet-50 模型中的标识块和卷积块。标识块中,使用了三次卷积操作,中间加入了批量归一化层和激活函数层,并在最后添加了残差链接,输出结果为输入加上残差,并过激活函数。卷积块与标识块相似,但在第一层卷积操作中使用了步长,以降低输出的空间尺寸。

最终,使用定义好的标识块和卷积块以及其他常见的卷积神经网络模型层(如卷积层、全连接层等),组成了修改版的 ResNet-50 模型。在该模型中,使用了一个卷积层、一个最大池化层、一个卷积块、两个标识块和一个全局平均池化层,并使用 Dense 函数作为分类层,输出最终结果。

# 初始化模型
resnet50 = ResNet50()# 配置
resnet50.compile(optimizer="adam",metrics=["accuracy"],loss = "sparse_categorical_crossentropy")# 训练
resnet50.fit(train_x, train_y, validation_data = (test_x, test_y), epochs = 20)
Epoch 1/20
858/858 [==============================] - 172s 197ms/step - loss: 0.8110 - accuracy: 0.9030 - val_loss: 0.6665 - val_accuracy: 0.8830
Epoch 2/20
858/858 [==============================] - 167s 194ms/step - loss: 0.1136 - accuracy: 0.9795 - val_loss: 0.7510 - val_accuracy: 0.8900
Epoch 3/20
858/858 [==============================] - 163s 190ms/step - loss: 0.0304 - accuracy: 0.9949 - val_loss: 0.3036 - val_accuracy: 0.9582
Epoch 4/20
858/858 [==============================] - 173s 201ms/step - loss: 0.1140 - accuracy: 0.9867 - val_loss: 0.5101 - val_accuracy: 0.9561
Epoch 5/20
858/858 [==============================] - 172s 201ms/step - loss: 7.6016e-04 - accuracy: 0.9998 - val_loss: 0.3638 - val_accuracy: 0.9554
Epoch 6/20
858/858 [==============================] - 175s 205ms/step - loss: 1.2263e-05 - accuracy: 1.0000 - val_loss: 0.3518 - val_accuracy: 0.9597
Epoch 7/20
858/858 [==============================] - 178s 207ms/step - loss: 3.8450e-05 - accuracy: 1.0000 - val_loss: 0.4060 - val_accuracy: 0.9561
Epoch 8/20
858/858 [==============================] - 185s 216ms/step - loss: 3.8043e-06 - accuracy: 1.0000 - val_loss: 0.3811 - val_accuracy: 0.9583
Epoch 9/20
858/858 [==============================] - 184s 214ms/step - loss: 7.3366e-07 - accuracy: 1.0000 - val_loss: 0.3785 - val_accuracy: 0.9594
Epoch 10/20
858/858 [==============================] - 174s 203ms/step - loss: 1.2010e-06 - accuracy: 1.0000 - val_loss: 0.4261 - val_accuracy: 0.9573
Epoch 11/20
858/858 [==============================] - 169s 198ms/step - loss: 1.3640e-06 - accuracy: 1.0000 - val_loss: 0.4166 - val_accuracy: 0.9583
Epoch 12/20
858/858 [==============================] - 177s 206ms/step - loss: 1.7177e-07 - accuracy: 1.0000 - val_loss: 0.4165 - val_accuracy: 0.9578
Epoch 13/20
858/858 [==============================] - 175s 204ms/step - loss: 1.5472e-07 - accuracy: 1.0000 - val_loss: 0.4170 - val_accuracy: 0.9579
Epoch 14/20
858/858 [==============================] - 178s 208ms/step - loss: 2.2307e-07 - accuracy: 1.0000 - val_loss: 0.4177 - val_accuracy: 0.9583
Epoch 15/20
858/858 [==============================] - 178s 207ms/step - loss: 9.6281e-08 - accuracy: 1.0000 - val_loss: 0.4099 - val_accuracy: 0.9584
Epoch 16/20
858/858 [==============================] - 181s 211ms/step - loss: 9.0053e-08 - accuracy: 1.0000 - val_loss: 0.4162 - val_accuracy: 0.9576
Epoch 17/20
858/858 [==============================] - 179s 209ms/step - loss: 5.3058e-08 - accuracy: 1.0000 - val_loss: 0.4095 - val_accuracy: 0.9578
Epoch 18/20
858/858 [==============================] - 183s 214ms/step - loss: 6.8558e-08 - accuracy: 1.0000 - val_loss: 0.4065 - val_accuracy: 0.9579
Epoch 19/20
858/858 [==============================] - 183s 213ms/step - loss: 2.2604e-08 - accuracy: 1.0000 - val_loss: 0.4065 - val_accuracy: 0.9583
Epoch 20/20
858/858 [==============================] - 179s 208ms/step - loss: 2.4879e-08 - accuracy: 1.0000 - val_loss: 0.3946 - val_accuracy: 0.9587
# 保存模型
resnet50.save_weights("ResNet50_weights.h")
# 评估模型
model = ResNet50()
model.load_weights("ResNet50_weights.h")
model.compile(optimizer="adam",metrics=["accuracy"],loss = "sparse_categorical_crossentropy")
score = model.evaluate(test_x, test_y, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])
Test loss: 0.4331090748310089
Test accuracy: 0.9584495425224304

五、模型预测

基于OpenCV

OpenCV是一种基于开源代码的计算机视觉和机器学习库,由英特尔公司开发并维护。它是一种跨平台的库,可以在Windows、Linux、Mac OS等操作系统上运行,支持多种编程语言,包括C++、Python、Java等,为计算机视觉和机器学习研究提供了强大的工具。在计算机视觉领域中,OpenCV是一种非常重要的工具,可以帮助开发人员更方便地实现各种计算机视觉算法,包括目标检测、人脸识别、图像分割等。

OpenCV提供了很多的图像处理函数,包括图像读取、显示、保存、转换、操作等。其中最常用的功能是图像读取和显示。使用OpenCV可以快速地读取图像文件,可以是常见的图像格式,如JPEG、PNG、BMP等。一旦读入图像,就可以使用OpenCV的显示函数在屏幕上显示它们。除此之外,OpenCV还提供了一些常用的图像处理函数,如图像增强、滤波器、边缘检测等等。

在机器学习领域中,OpenCV可以用来进行特征提取、特征匹配、分类和检测等任务。其中最常见的任务是特征提取和特征匹配。在特征提取方面,OpenCV提供了一些常用的特征提取方法,如SIFT、SURF、ORB等。这些方法可以帮助我们从图像中提取出一些具有独特性质的特征,用于后续的特征匹配、分类等任务。在特征匹配方面,OpenCV提供了一些基于特征的匹配方法,如FLANN、BFMatcher等。这些方法可以帮助我们进行图像配准、目标跟踪等任务。

OpenCV在计算机视觉和机器学习领域有着广泛的应用。其中比较重要的应用场景包括人脸识别、物体检测、图像分割等。在人脸识别方面,OpenCV提供了一些人脸检测和识别算法,能够从图像或视频中快速准确地识别出人脸并进行特征提取。在物体检测方面,OpenCV可以用于训练、优化和运行各种物体检测算法。在图像分割方面,OpenCV提供了多种图像分割算法,能够将一张图像分成多个不同的区域,用于识别和分析。

总之,OpenCV是一种非常重要的计算机视觉和机器学习库,在计算机视觉和机器学习领域中有着广泛的应用。它丰富的功能库和跨平台的特性,使得开发人员能够快速地构建各种计算机视觉和机器学习应用程序,并为开源和商业应用提供了很好的支持。

程序设计

# 导入OpenCV
import cv2
import string# 设定维度
dim = (28, 28) # 图像维度
letters = list(string.ascii_lowercase) # 识别的字母x0,x1,y0,y1 = 0, 300, 0, 200# 初始化视频捕获
video = cv2.VideoCapture(0)cv2.namedWindow('Webcam', cv2.WINDOW_NORMAL) # 构建1个窗口
cv2.resizeWindow('Webcam', 500, 400) 
cv2.moveWindow('Webcam',500,200) # 放置窗口while video.isOpened(): # 只要没有关掉实时摄像头ret,capture = video.read() # 抓取每个视频帧cropped = capture[y0:y1, x0:x1] # 截取plt.figure(figsize=(4, 3)) plt.imshow(cropped) # 可视化展示图片plt.axis("off")plt.show() # 展示img = cv2.cvtColor(cropped, cv2.COLOR_BGR2GRAY) # 转成灰度图img = cv2.GaussianBlur(img, (5, 5), 0) # 图像平滑img = cv2.resize(img, dim) # 图像大小缩放img = np.reshape(img, (1,img.shape[0],img.shape[1], 1))img = tf.cast(img, tf.float32)pred=resnet50.predict(img)# 可视化实时效果cv2.rectangle(capture, (x0,y0),(x1,y1), (255,0,0) ,2) # 为图片添加矩形框cv2.putText(capture,'This is {}'.format(letters[np.argmax(pred[0])]), (x0+25,y0+50), cv2.FONT_HERSHEY_SIMPLEX, 1,(0, 0, 255),1) # 预测字母cv2.imshow('Webcam', capture) # 展示视频# 输出预测结果print("This is " + letters[np.argmax(pred[0])])# 退出视频输入key = cv2.waitKey(1)if key == ord('w'):break
video.release()
cv2.destroyAllWindows()

程序分析

这段代码主要功能是利用OpenCV库实现对实时摄像头捕获到的图像进行识别,判断出图像中手势所表示的字母,并进行可视化展示。

具体实现时,代码首先导入了OpenCV库,并设定了图像的维度和识别的字母集合。然后初始化视频捕获,并构建一个窗口展示实时捕获的视频。

这段代码主要的循环语句是:

while video.isOpened():ret,capture = video.read()# ... cv2.imshow('Webcam', capture)# ...

主要是通过一个while循环不断读取视频帧,然后对读取到的图像进行预测和展示。

其中,代码通过一些图像处理技术,如图像平滑、大小缩放等,对图像进行预处理,并使用ResNet50模型对处理后的图像进行预测。同时,代码还添加了一个矩形框,并在上面展示预测出的字母,以便观察效果。最后,通过waitKey函数获取按键输入,当按下’w’键时退出程序。

总体上,这段代码实现了实时图像识别的功能,可以应用于很多场景,如拍照APP、安防监控等。但是需要注意的是,代码的准确率和效率并不高,因此可以根据实际需求进行优化。

运行结果

y

1/1 [==============================] - 0s 22ms/step
This is y

v

1/1 [==============================] - 0s 22ms/step
This is v

w

1/1 [==============================] - 0s 22ms/step
This is w

附:英文字母手语表

手语表

写在后面

我是一只有趣的兔子,感谢你的喜欢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/177802.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PFMEA详解结构分析——Sun FMEA软件

FMEA从1949年诞生到今天已经发生过多次更新,最新版本是2019年6月发布的《AIAG VDA FMEA手册》。新手册借鉴了AIAG的方框图、参数图、流程图等工具的运用,也借鉴了VDA的五步过程导向法,并在此基础上头尾各增加一步,形成了FMEA七步法…

云原生安全日志审计

记得添加,把配置文件挂载进去 - mountPath: /etc/kubernetes/auditname: audit-policyreadOnly: true.....- hostPath:path: /etc/kubernetes/audit/type: DirectoryOrCreatename: audit-policy/etc/kubernetes/manifests/kube-apiserver.yaml 具体配置文件如下 a…

阿里云2023年双11大促活动优惠券领取与使用及特惠云服务器产品购买规则汇总

2023年阿里云双11大促活动正在火热进行中,今年的双11活动还是延续了去年金秋云创季的活动名称,对于大部分用户来说,最为关心的是活动优惠券与云服务器的优惠政策,在我们领取双11优惠券和购买双11活动云服务器的时候,应…

京东大数据平台(京东数据分析):9月京东牛奶乳品排行榜

鲸参谋监测的京东平台9月份牛奶乳品市场销售数据已出炉! 9月份,牛奶乳品市场销售呈大幅上涨。鲸参谋数据显示,今年9月,京东平台牛奶乳品市场的销量为2000万,环比增长约65%,同比增长约3%;销售额为…

HT3163 免电感滤波 音频功率放大器工作原理

HT3163是一款G效AB/D类音频功率放大器。在D类模式,18V供电、THDN10%条件下,能够持续提供40W/4Ω功率输出。在AB类模式,12V供电、THDN10%条件下,能够持续输出17W/4Ω功率。 HT3163具有防削顶失真(ACF)输出控…

ASO优化之Google Play评分评论的重要性

应用程序的成果不仅仅是拥有功能齐全且无错误的产品,评分和评论会影响谷歌应用商店的排名算法,好评和差评都会影响应用在商店中的排名,这是关于与用户建立信任的一个环节。 1、积极主动地管理评论。 定期监控评论、解决用户问题以及根据反馈…

【嵌入式项目应用】__UART自定义通信协议代码实现方法

目录 前言 一、什么是通信协议 二、简单通信协议的问题 三、通信协议的常见内容 1. 帧头 2. 设备地址/类型 3. 命令/指令 4. 命令类型/功能码 5. 数据长度 6. 数据 7.帧尾 8.校验码 四、通信协议代码实现 1. 消息数据发送 a. 通过串口直接发送每一个字节 b. 通过…

进程地址空间

一 先前问题解释 1 #include<stdio.h>2 #include<unistd.h>3 int g_val 200;4 int main()5 {6 printf("begin");7 int id fork();8 if(id 0)9 {10 g_val 100;11 printf("我是子进程,pid: %d, 父进程:%d, g_v…

急求!录屏在哪里找?看这里就够了

“电脑的录屏在哪里找呀&#xff1f;已经找了一上午了&#xff0c;真的找不到&#xff0c;有哪位大神知道录屏在哪的&#xff0c;帮帮我&#xff0c;非常感谢&#xff01;” 随着社会的发展&#xff0c;录制电脑屏幕的需求变得越来越普遍。无论是在线教学、游戏直播还是远程会…

【Linux】Linux网络总结图详解

网络是进行分层管理的应用层HTTPHTPPS 传输层&#xff08;UDP、TCP&#xff09;UDPTCPTCP和UDP对比 网络层IP 数据链路层&#xff08;MAC&#xff09;/物理层&#xff08;以太网&#xff09;以太网通信&#xff08;负责网卡之间&#xff09; 网络是进行分层管理的 应用层 HTTP…

HarmonyOS开发:开源一个刷新加载组件

前言 系统Api中提供了下拉刷新组件Refresh&#xff0c;使用起来也是非常的好用&#xff0c;但是风格和日常的开发&#xff0c;有着巨大的出入&#xff0c;效果如下&#xff1a; 显然上面的效果是很难满足我们实际的需求的&#xff0c;奈何也没有提供的属性可以更改&#xff0c;…

nodejs+vue+elementui+python家电销售分析系统设计与实现-计算机毕业设计

系统按照用户的实际需求开发而来&#xff0c;贴近生活。从管理员通过正确的账号的密码进入系统&#xff0c;可以使用相关的系统应用。管理员总体负责整体系统的运行维护&#xff0c;统筹协调。 我们可以利用计算机技术来取代传统的管理模式&#xff0c;实现家电销售分析系统的…

LInux之在同一Tomcat下使用不同的端口号访问不同的项目

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《LInux实战开发》。&#x1f3af;&#x1f3af; …

【RP-RV1126】配置一套简单的板级配置

文章目录 官方配置新建一套新配置新建板级pro-liefyuan-rv1126.mk配置文件新建一个Buildroot的defconfigs文件 吐槽&#xff1a;RP-RV1126 的SDK奇怪的地方make ARCHarm xxx_defconfig 生成的.config文件位置不一样savedefconfig命令直接替换原配置文件坑爹的地方 Buildroot上增…

91 前K个高频元素

前K个高频元素 题解1 大根堆(STL) 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2] 示例 2: 输入: nums [1], k 1 输出: [1] 提示&#xff1a;…

机器人连杆惯量参数辨识(估计)

杆的转动惯量的计算公式是Imr^2。在经典力学中&#xff0c;转动惯量&#xff08;又称质量惯性矩&#xff0c;简称惯矩&#xff09;通常以I 或J表示&#xff0c;SI 单位为 kgm。对于一个质点&#xff0c;I mr&#xff0c;其中 m 是其质量&#xff0c;r 是质点和转轴的垂直距离。…

使用Java与Jsoup库构建有趣的爬虫项目

目录 一、网络爬虫的概念和应用 二、Jsoup库的功能和优势 三、使用Java与Jsoup库编写网络爬虫 四、网络爬虫的法律和道德问题 五、注意事项 六、总结 本文将深入探讨如何使用Java与Jsoup库构建一个实际且有趣的网络爬虫项目。我们将首先简要介绍网络爬虫的概念和应用&…

基于51单片机的智能手机充电器设计

**单片机设计介绍&#xff0c;1660【毕设课设】基于51单片机和MAX1898的智能手机充电器设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 51单片机智能手机充电器设计介绍 51单片机智能手机充电器是一种可以实现智能快速充电的…

华为认证H12-811题库

在VRP平台上&#xff0c;可以通过下面哪种方式返回到上一条历史命令&#xff1f;&#xff08; &#xff09; A、Ctr1U B、Ctr1P C、左光标 D、上光标 试题答案&#xff1a;BD 试题解析&#xff1a;在VRP系统中&#xff0c;ctrlU为自定义快捷键&#xff0c;ct…

Kubernetes 访问控制 - RBAC 鉴权

Author&#xff1a;rab 目录 前言一、Role二、ClusterRole三、RoleBinding四、ClusterRoleBinding总结 前言 API 访问控制有很多&#xff0c;比如 RBAC 鉴权、ABAC 鉴权、Node 鉴权等。自 Kubernetes 1.6 版本以后&#xff0c;RBAC 成为 Kubernetes 的默认访问控制机制。RBAC …