当前位置: 首页 > news >正文

深度学习实战:基于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

附:英文字母手语表

手语表

写在后面

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

相关文章:

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

文章目录 写在前面基于TensorFlow与OpenCV的手语识别系统安装环境一、导入工具库二、导入数据集三、数据预处理四、训练模型基于CNN基于LeNet5基于ResNet50 五、模型预测基于OpenCV 写在后面 写在前面 本期内容:基于TensorFlow与OpenCV的手语识别系统 实验环境&…...

学习整理nginx常用屏蔽规则,让网站更安全

学习整理nginx常用屏蔽规则,让网站更安全 注意一、防止文件被下载二、屏蔽非常见蜘蛛(爬虫)三、禁止某个目录执行脚本四、屏蔽某个IP或IP段 注意 在开始之前,希望您已经熟悉的Nginx常用命令(如停止,重启等…...

四十一、【进阶】索引使用SQL提示

1、SQL提示使用情景 在使用MySQL时,当一个字段参在于多个索引中时,默认情况下,MySQL会自动选择一个索引,但我们可以指定索引吗?可以忽略某一种索引吗? 答案是可以的。 前提:profession字段已经…...

AI智能分析网关高空抛物算法如何实时检测高楼外立面剥落?

高楼外立面剥落是一种十分危险的行为,会造成严重的人身伤害和财产损失。TSINGSEE青犀智能分析网关利用高楼外立面剥落的信息,结合高空抛物算法来进行处理就可很好解决此问题。 1. 数据收集 首先,需要收集关于高楼外立面剥落的数据。这可以通…...

微信小程序 - 页面继承(非完美解决方案)

微信小程序 - 面页继承(非完美解决方案) 废话思路首页 indexindex.jsindex.jsonindex.wxml 父页面 page-basepage-base.jspage-base.wxml 子页面 page-apage-a.jspage-a.wxml 子页面 page-bpage-b.jspage-b.wxml 其它app.jsapp.jsonapp.wxss 参考资料 废…...

智能配件管理系统有什么用?企业如何实现管理数字化转型?

在当今高度信息化的时代,企业运营的各个环节都离不开准确及时的数据支持。特别是在制造业中,生产数据的记录和管理对于提高生产效率、降低成本、优化资源配置等方面具有至关重要的作用。然而,许多企业仍在采用纸质流转卡来记录生产数据&#…...

@SuppressWarnings注解使用说明

在Java编程中,我们常常会遇到一些警告(warnings),这些警告通常是对某些潜在问题的提示,虽然这些问题可能不会立即影响程序的运行,但可能会在将来引发问题。为了消除这些警告,我们可以使用Suppre…...

算法从入门到入土cpp版

1. 排序 1. 快速排序 # include<iostream> using namespace std;const int N 100010;int q[N];void quick_sort(int q[], int l, int r) {if(l>r) return;int il-1,jr1,tempq[l];while(i<j){do i;while(q[i]<temp);do j--;while(q[j]>temp);if(i<j)swa…...

没有PDF密码,如何解密文件?

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。想要解密&#xff0c;我们需要输入正确的密码&#xff0c;但是有时候我们可能会出现忘记密码的情况&#xff0c;或者网上下载P…...

Sqlyog 无法连接 8 版本的mysql caching_sha2_password could not be loaded

Sqlyog 无法连接 8 版本的mysql caching_sha2_password could not be loaded 1.问题背景 近期系统对Mysql 版本进行了升级&#xff0c;由原来的 5.7升至 8版本&#xff0c;在现场使用Sqlyog 作为数据库连接软件时&#xff0c;发现连接失败。 2.问题现象 使用Sqlyog配置完连…...

学习笔记三十三:准入控制

ResourceQuota准入控制器 ResourceQuota准入控制器限制cpu、内存、pod、deployment数量限制存储空间大小 LimitRanger准入控制器在limit名称空间创建pod&#xff0c;不指定资源&#xff0c;看看是否会被limitrange规则自动附加其资源限制创建pod&#xff0c;指定cpu请求是100m&…...

Unix/Linux C语言 获取控制台窗口尺寸

在Unix/Linux控制台编程&#xff0c;为了能输出好看一些&#xff0c;需要知道窗口宽度&#xff0c;当然使用支持很宽的窗口的终端也是个办法&#xff0c;但是实在没有很宽的终端怎么办呢&#xff0c;还是要从程序上想办法的。 判断控制台窗口宽度需要两个函数&#xff1a; isa…...

界面控件DevExpress WinForms Gauge组件 - 实现更高级别数据可视化

DevExpress WinForms控件包含了超过150个随时可用的仪表盘预设&#xff0c;包括圆形&#xff0c;数字&#xff0c;线性和状态指示器等&#xff0c;来帮助用户实现更高级的数据可视化。 DevExpress WinForms有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业…...

vivo 自研蓝河操作系统 BlueOS 发布:支持大模型、BlueXlink 协议实现万物互联

大家好&#xff0c;我是 Lorin , 2023 年 11 月 1 日&#xff0c;在今天的 2023 年 vivo 开发者大会上&#xff0c;vivo 自主研发的蓝河操作系统&#xff08;BlueOS&#xff09;正式亮相。这款操作系统被宣传为一款面向未来的智能操作系统&#xff0c;具备出色的支持能力&#…...

opencv复习(很乱)

2-高斯与中值滤波_哔哩哔哩_bilibili 1、均值滤波 2、高斯滤波 3、中值滤波 4、腐蚀操作 卷积核不都是255就腐蚀掉 5、膨胀操作 6、开运算 先腐蚀再膨胀 7、闭运算 先膨胀再腐蚀 8、礼帽 原始数据-开运算结果 9、黑帽 闭运算结果-原始数据 10、Sobel算子 左-右&#x…...

于璠访谈录 | AI 框架应该和而不同?

点击以下链接收听本期 “大咖访谈” 播客&#xff0c;与大咖面对面&#xff1a; 大咖访谈链接&#xff1a;于璠 | AI 框架应该和而不同&#xff1f; 刘天栋&#xff1a;访谈主持&#xff0c;开源雨林社区顾问、开源社联合创始人、ASF member 于璠&#xff1a;访谈嘉宾&#xf…...

基于Springboot+MYSQL+Maven实现的宠物医院管理系统(源码+数据库+运行指导文档+项目运行指导视频)

一、项目简介 本项目是一套基于springboot框架实现的宠物医院管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单…...

【数据结构二叉树】先序层序建立、递归非递归遍历层序遍历、树高、镜面、对称、子树、合并、目标路径、带权路径和等等

二叉树 文章目录 二叉树1. 二叉树的建立&#xff08;递归创建&#xff0c;结构体指针形式&#xff09;1.1. 先序建立1.2. 层序建立 2. 递归遍历(结构体指针)2.1. 先序遍历2.2. 中序遍历2.3. 后序遍历 3. 非递归遍历(结构体指针)3.1. 层次遍历3.2. 后序遍历(非递归) 4. 求树的高…...

Mybatis延迟加载(缓存)

延迟加载 分步查询的优点&#xff1a;可以实现延迟加载&#xff0c;但是必须在核心配置文件中设置全局配置信息&#xff1a;lazyLoadingEnabled&#xff1a;延迟加载的全局开关。当开启时&#xff0c;所有关联对象都会延迟加载 aggressiveLazyLoading&#xff1a;当开启时&…...

我对美团的看法,作为美团的股东,我都有点懵

我是美团的股东&#xff0c;你看股价&#xff0c;我都想骂人了。 这帖子就一句话。足以表明我的无奈。...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...