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

Test 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的卷积核,步长为1
    tf.keras.layers.Conv2D(6, (5,5), activation='relu', input_shape=(28, 28, 1), padding='valid'),
    # 第一层平均池化层,使用2x2的池化窗口,步长为2
    tf.keras.layers.AveragePooling2D(pool_size=(2, 2), strides=(2, 2), padding='valid'),
    # 第二层卷积层,使用16个5x5的卷积核,步长为1
    tf.keras.layers.Conv2D(16, (5,5), activation='relu', padding='valid'),
    # 第二层平均池化层,使用2x2的池化窗口,步长为2
    tf.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 = filters
    X_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 axis
    X = 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 axis
    X = 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 axis
    
    X = 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 = filters
    X_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 axis
    X = 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 axis
    X = 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 axis
    
    X_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

附:英文字母手语表

手语表

写在后面

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

333333333333

一、Map 接口 接下来讲的都是基于 jdk8 来开展的。 1.1 特点 1、Map 与 Collection 并列存在。Map 是用于保存具有映射关系的数据,即 key-value。 2、Map 中的 key 和 value 可以是任何引用类型的数据类型。 3、Map 中的 key 不允许重复,原因和 HashSet…

动态路由协议OSPF项目部署(二)

1. 静态和动态路由的区别; 2. OSPF协议通信过程与部署; 3. OSPF协议在项目上的应用场景 - OSPF - 开放式最短路径优先 - 一个动态路由协议 - 路由器转发数据 - 路由器需要一张地图 - 路由表 - 路由表如何构建的? - 依靠手动 或…

API接口加密,解决自动化中登录问题

一、加密方式 AES:对称加密,快RAS:非对称加密,慢AESRAS:安全高效 加密过程:字符串》字节流》加密的字节流(算法),解密有可能出现乱码,所以不能直接转成字符…

【LeetCode】剑指 Offer Ⅱ 第8章:树(12道题) -- Java Version

题库链接:https://leetcode.cn/problem-list/e8X3pBZi/ 类型题目解决方案二叉树的深搜剑指 Offer II 047. 二叉树剪枝递归(深搜):二叉树的后序遍历 (⭐)剑指 Offer II 048. 序列化和反序列化二叉树递归&…

吴恩达《机器学习》4-1->4-5:多变量线性回归

一、引入多维特征 在多维特征中,我们考虑的不再是单一的特征,而是一组特征,例如房价模型中可能包括房间数、楼层等多个特征。这些特征将组成一个向量,表示为(𝑥₁, 𝑥₂, . . . , 𝑥ₙ)&#x…

【腾讯云HAI域探秘】速通腾讯云HAI

速览HAI 产品简介 腾讯云高性能应用服务(Hyper Application lnventor,HA),是一款面向 Al、科学计算的 GPU 应用服务产品,为开发者量身打造的澎湃算力平台。无需复杂配置,便可享受即开即用的GPU云服务体验。在 HA] 中,…

配置git并把本地项目连接github

一.配置git 1.下载git(Git),但推荐使用国内镜像下载(CNPM Binaries Mirror) 选好64和版本号下载,全部点下一步 下载完成后打开终端,输入 git --version 出现版本号则说明安装成功 然后继续…

Redis统计大法:挖掘数据的四重宝藏【redis第五部分】

Redis统计大法:挖掘数据的四重宝藏 前言第一:redis集合统计简介第二:聚合统计->数据的综合分析总和(Sum):平均值(Average)中位数(Median) 第三&#xff1a…

【C++】多态 ⑪ ( 纯虚函数和抽象类 | 纯虚函数语法 | 抽象类和实现 | 代码示例 )

文章目录 一、纯虚函数和抽象类1、纯虚函数2、纯虚函数语法3、抽象类和实现 二、完整代码示例 一、纯虚函数和抽象类 1、纯虚函数 纯虚函数 : 在 C 语言中 , " 纯虚函数 " 是 特殊类型的 虚函数 , " 纯虚函数 " 在 父类 中 声明 , 但是没有实现 ; 抽象类 …

从瀑布模式到水母模式:ChatGPT引领软件研发的革新之路

ChatGPT引领软件研发的革新之路 概述操作建议本书优势 内容简介作者简介专家推荐读者对象目录直播预告写在末尾: 主页传送门:📀 传送 概述 计算机技术的发展和互联网的普及,使信息处理和传输变得更加高效,极大地改变了…

Azure 机器学习 - 使用 AutoML 和 Python 训练物体检测模型

目录 一、Azure环境准备二、计算目标设置三、试验设置四、直观呈现输入数据五、上传数据并创建 MLTable六、配置物体检测试验适用于图像任务的自动超参数扫描 (AutoMode)适用于图像任务的手动超参数扫描作业限制 七、注册和部署模型获取最佳试用版注册模型配置联机终结点创建终…

JUL 日志

JUL日志级别 日志分为7个级别,详细信息我们可以在Level类中查看: SEVERE(最高值)- 一般用于代表严重错误WARNING - 一般用于表示某些警告,但是不足以判断为错误INFO (默认级别) - 常规消息CON…

Hadoop HDFS(分布式文件系统)

一、Hadoop HDFS(分布式文件系统) 为什么要分布式存储数据 假设一个文件有100tb,我们就把文件划分为多个部分,放入到多个服务器 靠数量取胜,多台服务器组合,才能Hold住 数据量太大,单机存储能力有上限,需要…

QT在线安装5.15之前的版本(下载速度飞快)

使用最新的QT在线安装器,安装QT版本时只能安装5.15以及之后的版本,安装QT5.15之前的版本只能通过离线安装的方式,离线安装后还要自己去配置QT,离线安装还有个问题的,后续维护比较麻烦,QT的维护工具还要自己…

springboot2.x使用@RestControllerAdvice实现通用异常捕获

文章目录 demo地址实现效果引入基础类准备1.通用枚举与错误状态枚举2.定义通用返回结果3.自定义业务异常 统一异常捕获测试 demo地址 demo工程地址 实现效果 当我们输入1时,正常的返回通用的响应结果当我们输入2时,抛出异常,被捕获然后返回…

macOS 安装brew

参考链接: https://mirrors4.tuna.tsinghua.edu.cn/help/homebrew/ https://www.yii666.com/blog/429332.html 安装中科大源的: https://zhuanlan.zhihu.com/p/470873649

《TCP/IP详解 卷一:协议》第5章的IPv4数据报的Checksum(校验和)字段的计算(这里才能解开你的困惑)

首先,我当你看过书,但是比较懵。 1,实例说明Checksum(校验和)的计算步骤 直奔主题,分析一下这个Checksum(校验和)怎么算出来的。 先用Wireshark随便抓一个UDP或TCP包分析一下。 如上面,我们得…

Python数据分析:在职场中的竞争优势

前言 在职场中,技能的重要性是不言而喻的。越来越多的职位要求员工具备数据分析能力,而Python作为一种强大的数据分析工具,正在成为职场中的“利器”。然而,尽管Python数据分析提供了巨大的优势,许多人依然未能掌握这…

团队表 -多级团队设计

团队表 -多级团队设计 user_team团队表 ,如果存在子团队 1.我们可以通过每一个团队字段加一个parentid (相当于一对多的关系) 2.还可以设置一个字段CodingNum,比如这样: //系统为了管理查询团队自动生成的有序编号 可以使用3位数代表一个…

06.Oracle数据备份与恢复

Oracle数据备份与恢复 一、通过RMAN方式备份二、使用emp/imp和expdb/impdb工具进行备份和恢复三、使用Data guard进行备份与恢复 一、通过RMAN方式备份 通过 RMAN(Oracle 数据库备份和恢复管理器)方式备份 Oracle 数据库,可以使用以下步骤&a…