手势数字识别,深度学习算法,环境搭建,模型训练等

环境先决条件

装个Anaconda新建个Python3.8环境,这年头不用虚拟环境搞深度学习等于裸奔。核心依赖就这几个:

pip install tensorflow==2.9 opencv-python matplotlib

别纠结版本号,能用就行。要是显卡给力可以装tensorflow-gpu,速度能快个五到十倍,不过笔记本核显也能跑,就是训练的时候泡杯咖啡慢慢等。

数据预处理骚操作

数据集建议用现成的公开手势库,自己拍图训练太费劲。假设已经搞到了几千张手势图,文件夹结构长这样:

dataset/
    ├── 0/
    ├── 1/
    └── .../

上代码加载的时候记得做归一化和数据增强:

from tensorflow.keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    shear_range=0.15,
    validation_split=0.2
)

train_generator = train_datagen.flow_from_directory(
    'dataset',
    target_size=(64, 64),  # 别用太大分辨率,烧显卡
    batch_size=32,
    class_mode='categorical',
    subset='training'
)

重点说下这个shear_range参数,相当于给手势图片加点错切变换,模拟手部摆姿势时的透视畸变。数据不够的时候这招能救命,但别开太大,不然数字3可能被切成8。

模型搭建黑科技

整个轻量级CNN模型足够应付0-9的分类:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout

model = Sequential([
    Conv2D(32, (3,3), activation='relu', input_shape=(64,64,3)),
    MaxPooling2D(2,2),
    Conv2D(64, (3,3), activation='relu'),
    MaxPooling2D(2,2),
    Flatten(),
    Dense(128, activation='relu'),
    Dropout(0.5),  # 防过拟合神器
    Dense(10, activation='softmax')
])

注意第二个卷积层用64个filter,这可不是随便写的数——第一层捕捉边缘特征,第二层需要更复杂的纹理组合。最后一层Dense的10对应0-9十个数字,softmax让概率分布更明显。

训练调参玄学

配置回调函数是门艺术:

from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping

callbacks = [
    ModelCheckpoint('best_model.h5', save_best_only=True),
    EarlyStopping(patience=5, restore_best_weights=True)
]

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

history = model.fit(
    train_generator,
    epochs=50,
    callbacks=callbacks,
    validation_data=val_generator
)

这里有个坑:手势数据中"5"和"3"容易混淆,可以加class_weight调整样本权重。如果验证集准确率在15个epoch后还没提升,基本可以提前收工,别跟死磕。

实战推理脚本

最后写个实时识别脚本,用OpenCV抓摄像头画面:

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
model = tf.keras.models.load_model('best_model.h5')

while True:
    ret, frame = cap.read()
    roi = cv2.resize(frame[100:400, 100:400], (64,64))  # 框出手势区域
    roi_norm = roi / 255.0
    prediction = model.predict(roi_norm[np.newaxis, ...])
    digit = np.argmax(prediction)
    
    cv2.putText(frame, f'Pred: {digit}', (50,50), cv2.FONT_HERSHEY_SIMPLEX, 2, (0,255,0), 3)
    cv2.imshow('Live', frame)
    
    if cv2.waitKey(1) == 27:
        break

重点注意roi区域要跟训练数据尺寸一致,np.newaxis给数据加个batch维度。实际部署时建议做背景分割,或者在暗色背景下操作,识别率能提升30%不止。

遇到手势边界模糊的情况,可以加个高斯滤波预处理。实测发现当预测结果在多个数字间反复横跳时,取最近3帧的移动平均能显著提升稳定性。搞深度学习别死磕模型,工程技巧有时候比算法更管用。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐