• 3
    回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

【 DigiKey DIY原创大赛】树莓派5实现简单手势识别

物料清单:树莓派5,usb相机、显示器

前言:自己项目上需要用到ai识别缺陷,后续准备把ai识别移植到现有的程序中,而整个的流程虽然看了不少但是还是不清楚具体该咋做,就想着借此次机会顺便把整个流程跑一遍,后续就是换个识别物体,也大同小异。

选择树莓派5的原因:一方面跑ai需要性能比较高,再参考树莓派5的参数,感觉性能还挺强悍,跟我们现在用的rk3588就差四个小核,就决定在得捷官网买回来一块跑跑试试。

树莓派5:是采用Broadcom 新推出的一款四核 64 位 Arm Cortex-A76 处理器:BCM2712 ,主频为 2.4GHz,每核二级缓存为 512KB,共享三级缓存为 2MB。Cortex-A76 在微体系结构上比 Cortex-A72 进步了三代,更好的制造工艺使 Raspberry Pi 5 的速度更快,工作功耗更低(但是看官方数据,推荐适配器功率从15W变成了27W)。

硬件连接:外接一个显示屏,因为桌面太乱就不拍显示屏了

操作流程:

安装tensorflow

下载tensorflow时发现树莓派4/5架构都是aarch64了,通过uname -a来查看

树莓派5python版本:3.11.2

通过链接1:https://github.com/PINTO0309/Tensorflow-bin 查看树莓派5对应文件tensorflow-2.15.0.post1-cp311-none-linux_aarch64.whl

下载地址:Release v2.15.0.post1 · PINTO0309/Tensorflow-bin (github.com)

安装依懒项,这个都可以根据上面链接中的内容进行配置,这里就不在贴了,字数超限了

安装OpenCV:

最后想实时检测就需要用到OpenCV来打开相机

pip install opencv-python

配置好后如下图:

到这步,运行检测的环境基本就配置完成。

pip安装的时候错误警告:

error: externally-managed-environment
This environment is externally managed
To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.

大概意思就是:错误消息表明您正在尝试在一个由系统管理的环境中安装 Python 包,而不允许直接在系统范围内执行此类操作。

可以用个建虚拟环境进行运行:

python3 -m venv myenv  #创建虚拟环境
source myenv/bin/activate # 激活虚拟环境(在使用虚拟环境之前,您需要激活它)
pip install tensorflow-2.15.0.post1-cp311-none-linux_aarch64.whl  #安装 TensorFlow cv2

如果你还是想装在系统环境,可以直接运行在命令后面加上--break-system-packages 如下:

pip install tensorflow-2.15.0.post1-cp311-none-linux_aarch64.whl --break-system-packages
deactivate #退出虚拟环境

图像采集、模型训练

因为树莓派的存储空间和性能有限,我训练就在别的机器上训练了。

构建自己的数据集
因为时间关系,我直接从网上找的数据集,然后通过TensorFlow的data augmentation(数据增强)神器了,通过旋转,平移,拉伸 等操作每张图片生成100张,这样图片就变成了21500张。
 data augmentation 的代码:
from keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
import os

datagen = ImageDataGenerator(
    rotation_range=20,
    width_shift_range=0.15,
    height_shift_range=0.15,
    zoom_range=0.15,
    shear_range=0.2,
    horizontal_flip=True,
	fill_mode='nearest')

dirs = os.listdir("../picture")
print(len(dirs))
for filename in dirs:
    img = load_img("../picture//{}".format(filename))
    x = img_to_array(img)
    # print(x.shape)
    x = x.reshape((1,) + x.shape) #datagen.flow要求rank为4
    # print(x.shape)
    datagen.fit(x)
    prefix = filename.split('.')[0]
    print(prefix)
    counter = 0
    for batch in datagen.flow(x, batch_size=4 , save_to_dir='../generater_pic', save_prefix=prefix, save_format='jpg'):
        counter += 1
        if counter > 50:
            break

数据集的处理

把图片转成 .h5文件

import os
from PIL import Image
import numpy as np
import h5py
import tensorflow as tf
import time

# 把图片压缩成64*64的
def resize_img():
    dirs = os.listdir("generater_pic")
    for filename in dirs:
        # 使用 tf.io.gfile 读取文件
        filepath = os.path.join("generater_pic", filename)
        im = tf.io.read_file(filepath) 
        img_data = tf.image.decode_jpeg(im)
        image_float = tf.image.convert_image_dtype(img_data, tf.float32)
        resized = tf.image.resize(image_float, [64, 64])  # 使用 tf.image.resize
        resized_im = resized.numpy()  # 将 Tensor 转换为 NumPy 数组
        # 使用 PIL 保存图像
        Image.fromarray((resized_im * 255).astype(np.uint8)).save(os.path.join("resized_img", filename))

# 图片转 h5 文件
def image_to_h5():
    dirs = os.listdir("resized_img")
    Y = []  # label
    X = []  # data
    print(len(dirs))
    
    for filename in dirs:
        label = int(filename.split('_')[0])
        Y.append(label)
        im = Image.open(os.path.join("resized_img", filename)).convert('RGB')
        mat = np.asarray(im)
        X.append(mat)

    file = h5py.File("dataset/data.h5", "w")
    file.create_dataset('X', data=np.array(X))
    file.create_dataset('Y', data=np.array(Y))
    file.close()

if __name__ == "__main__":
    print("start.....: " + str((time.strftime('%Y-%m-%d %H:%M:%S'))))
    resize_img()
    print("end....: " + str((time.strftime('%Y-%m-%d %H:%M:%S'))))
    image_to_h5()

训练模型

在后续贴上,提示字数超限

在树莓派上进行测试

import os
import numpy as np
import tensorflow as tf
from PIL import Image
from keras.models import load_model
import cv2

# 加载模型
model = load_model("model_500_200_c3/cnn_model.keras")

# 准备输入数据
def load_single_image(frame):
    # TF读取和处理图像
    image_tensor = tf.convert_to_tensor(frame)  # 将帧转换为 Tensor
    image_tensor = tf.image.convert_image_dtype(image_tensor, tf.float32)  # 转换为 float32
    resized = tf.image.resize(image_tensor, [64, 64])  # 调整大小
    img_array = resized.numpy()  # 转换为数组
    img_array = np.expand_dims(img_array, axis=0)  # 添加批次维度
    return img_array

# 使用模型进行预测
def predict_image(model, frame):
    img_array = load_single_image(frame)
    predictions = model.predict(img_array)
    predicted_class = np.argmax(predictions, axis=1)
    return predicted_class[0]

import cv2
cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
     # 进行预测
     predicted_class = predict_image(model, frame)
     cv2.putText(frame, f'Predicted class: {predicted_class}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
    cv2.imshow('Hand Gesture Recognition', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

测试结果:

全部回复(3)
正序查看
倒序查看
米修儿
LV.4
2
10-08 15:44

训练模型代码:

import h5pyimport numpy as npfrom sklearn.model_selection import train_test_splitfrom keras.utils import to_categoricalimport tensorflow as tffrom tensorflow.keras import layers, modelsimport time

# Load datasetdef load_dataset():    data = h5py.File("dataset/data.h5", "r")    X_data = np.array(data['X'])    Y_data = np.array(data['Y'])        X_train, X_test, y_train, y_test = train_test_split(X_data, Y_data, train_size=0.9, test_size=0.1, random_state=22)        X_train = X_train / 255.  # Normalize    X_test = X_test / 255.        y_train = to_categorical(y_train, num_classes=11)    y_test = to_categorical(y_test, num_classes=11)

    return X_train, X_test, y_train, y_test

# Define CNN model using Kerasdef cnn_model(input_shape, num_classes):    model = models.Sequential()        # Convolutional layers    model.add(layers.Conv2D(32, (5, 5), activation='relu', input_shape=input_shape))    model.add(layers.MaxPooling2D(pool_size=(2, 2)))        model.add(layers.Conv2D(64, (5, 5), activation='relu'))    model.add(layers.MaxPooling2D(pool_size=(2, 2)))

    # Flatten    model.add(layers.Flatten())    model.add(layers.Dense(200, activation='relu'))    model.add(layers.Dropout(0.2))  # Dropout layer for regularization    model.add(layers.Dense(num_classes, activation='softmax'))

    # Compile model    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])        return model

if __name__ == "__main__":    print("Loading dataset: " + str(time.strftime('%Y-%m-%d %H:%M:%S')))    X_train, X_test, y_train, y_test = load_dataset()        print("Starting training: " + str(time.strftime('%Y-%m-%d %H:%M:%S')))        # Define model    model = cnn_model(input_shape=(64, 64, 3), num_classes=11)        # Train model    model.fit(X_train, y_train, epochs=500, batch_size=16, validation_data=(X_test, y_test))        # Save model    model.save("model_500_200_c3/cnn_model.keras")

0
回复
米修儿
LV.4
3
10-08 15:44

最后测试结果不是太满意,能识别但是识别率有点低,重新训练了几次还是识别率低,不知道是因为我训练的图片不是测试相机拍的原因,还是我的流程有问题,后续准备用pytorch和YOLOv5试试,因为是测试,所以实在是不想花太多的时间去标注。

总结:

之前简单测试树莓派4感觉用sd卡速度上跟不上,这次用树莓派5跑视频感觉跟机载存储差别不是很大,虽然有点延迟,但是级别能接受,也可能我显示的分辨率比较低也有原因

0
回复
米修儿
LV.4
4
10-08 15:56

再说说树莓派5是在得捷官网下单购买,国内发货,几天就到了,方便快捷

0
回复