深度学习实战:基于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.mzph.cn/news/131732.shtml

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

相关文章

lv9 嵌入式开发 数据库sqlite

1 数据库基本概念 数据(Data) 能够输入计算机并能被计算机程序识别和处理的信息集合 数据库 (Database) 数据库是在数据库管理系统管理和控制之下,存放在存储介质上的数据集合 2 常用的数据库 大型数据库…

过了面试,后面的在线测评还会刷人吗?

过了面试,后面的在线测评还会刷人吗?完全有可能刷,如果不是为了刷,何必要给你做线上测评,我说的有道理不? 好吧,说到为什么在线测评要刷人,怎么刷? 怎么才能确保不被刷&…

Idea 对容器中的 Java 程序断点远程调试

第一种:简单粗暴型 直接在java程序中添加log.info(),根据需要打印信息然后打包覆盖,根据日志查看相关信息 第二种:远程调试 在IDEA右上角点击编辑配置设置相关参数在Dockerfile中加入 "-jar", "-agentlib:jdwp…

【移远QuecPython】EC800M物联网开发板的硬件PWM和PWM输出BUG

【移远QuecPython】EC800M物联网开发板的硬件PWM和PWM输出BUG 文章目录 导入库初始化PWM开启PWMPWM硬件BUG附录:列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 导入库 from misc import PWM_V2或者 from misc import PWM但我觉得PWM_V2好用 初…

Adobe:受益于人工智能,必被人工智能反噬

来源:猛兽财经 作者:猛兽财经 总结: (1)Adobe(ADBE)受益于生成式人工智能的兴起,其一直能实现两位数的收入增长就证明了这一点。 (2)在生成式人工智能兴起时,该公司就快…

基于若依的ruoyi-nbcio流程管理系统增加仿钉钉流程设计(六)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 这节主要讲条件节点与并发节点的有效性检查,主要是增加这两个节点的子节点检查,因为…

【从零开始学习Redis | 第五篇】基于布隆过滤器解决Redis的穿透问题

前言: 在如今的开发中,使用缓存中间件Redis已经成为一项很广泛的技术,Redis的高性能大大优化了我们的服务器性能,缓解了在高并发的情况下服务器的压力。它基于缓存的形式,在内存中保存数据,减少对磁盘的IO操…

听GPT 讲Rust源代码--library/std(15)

题图来自 An In-Depth Comparison of Rust and C[1] File: rust/library/std/src/os/wasi/io/fd.rs 文件路径:rust/library/std/src/os/wasi/io/fd.rs 该文件的作用是实现与文件描述符(File Descriptor)相关的操作,具体包括打开文…

✔ ★【备战实习(面经+项目+算法)】 11.5学习

✔ ★【备战实习(面经项目算法)】 坚持完成每天必做如何找到好工作1. 科学的学习方法(专注!效率!记忆!心流!)2. 每天认真完成必做项,踏实学习技术 认真完成每天必做&…

MFC 基础篇(一)

目录 一.SDK编程 二.为什么要学MFC? 三.MFC能做什么? 四.MFC开发环境搭建 五.MFC项目创建 六.消息映射机制 一.SDK编程 Application Programming Interface 应用程序编程接口。 Software Development Kit 软件开发工具包,一般会包括A…

【入门Flink】- 04Flink部署模式和运行模式【偏概念】

部署模式 在一些应用场景中,对于集群资源分配和占用的方式,可能会有特定的需求。Flink为各种场景提供了不同的部署模式,主要有以下三种:会话模式(Session Mode)、单作业模式(Per-Job Mode&…

小程序如何设置用户同意服务协议并上传头像和昵称

为了保护用户权益和提供更好的用户体验,设置一些必填项和必读协议是非常必要的。首先,用户必须阅读服务协议。服务协议是明确规定用户和商家之间权益和义务的文件。通过要求用户在下单前必须同意协议,可以确保用户在使用服务之前了解并同意相…

分析:如何多线程运行测试用例

这是时常被问到的问题,尤其是UI自动化的运行,过程非常耗时,所以,所以多线程不失为一种首先想到的解决方案。 多线程是针对的测试用例,所以和selenium没有直接关系,我们要关心的是单元测试框架。 unittest …

[GDOUCTF 2023]<ez_ze> SSTI 过滤数字 大括号{等

SSTI模板注入-中括号、args、下划线、单双引号、os、request、花括号、数字被过滤绕过(ctfshow web入门370)-CSDN博客 ssti板块注入 正好不会 {%%}的内容 学习一下 经过测试 发现过滤了 {{}} 那么我们就开始吧 我们可以通过这个语句来查询是否存在ss…

免费亲人微信聊天记录提取软件新版本v1.1,使用说明,注意事项 2023.11.06

V 1.1 优化了备份速度,新增了备份消息类型的选型,可以选择仅仅备份文本,或者文本与音频,或者文本音频视频图片。 有什么办法可以导出与某个人的微信聊天记录? 只想导出与某个微信好友的聊天记录,有办法做到…

运维知识点-MySQL从小白到入土

MySQL从小白到入土 mysql 服务器安装windows mysql 服务漏洞复现-mysql jdbc反序列化-权限绕过 mysql 服务器安装 https://dev.mysql.com/downloads/mysql/https://www.cnblogs.com/xiaostudy/p/12262804.html 点餐小程序腾讯云服务器安装mysql8 windows mysql 服务 net sta…

1.UML面向对象类图和关系

文章目录 4种静态结构图类图类的表示类与类之间的关系依赖关系(Dependency)关联关系(Association)聚合(Aggregation)组合(Composition)实现(Realization)继承/泛化(Inheritance/Generalization)常用的UML工具reference欢迎访问个人网络日志🌹🌹知行空间🌹🌹 4种静态结构…

cp没有--exclude选项!Linux复制文件夹时如何排除一些文件?

之前使用tar命令压缩文件将时,使用了–exclude选项排除了一些不需要的文件。现在我想复制一个文件夹,但是其中一些文件不需要复制,此时注意到cp命令居然没有–exclude选项。 rsync可以快速地帮助我们完成相同的事情,命令如下&…

【Java 进阶篇】JSP 简单入门

在现代Web开发中,JavaServer Pages(JSP)是一项非常重要的技术。JSP允许开发者将Java代码嵌入HTML页面,以实现动态内容的生成和呈现。本文将详细介绍JSP的概念、原理以及如何使用JSP来构建Web应用程序。 第一部分:JSP …

如何将 XxlJob 集成达梦数据库

1. 前言 在某些情况下,你的项目可能会面临数据库选择的特殊要求,随着国产化的不断推进,达梦数据库是一个常见的选择。本篇博客将教你如何解决 XxlJob 与达梦数据库之间的 SQL 兼容性问题,以便你的任务调度系统能够在这个数据库中…