最近在折腾手势识别,发现用深度学习搞数字手势识别还挺有意思。今天就把整个流程拆开了揉碎了讲讲,从环境配置到模型训练,中间穿插几个代码段子,保准你能边看边撸代码
手势数字识别,深度学习算法,环境搭建,模型训练等
环境先决条件
装个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帧的移动平均能显著提升稳定性。搞深度学习别死磕模型,工程技巧有时候比算法更管用。

更多推荐


所有评论(0)