🍁 作者:知识浅谈,CSDN签约讲师&博客专家,华为云云享专家,阿里云专家博主,InfoQ签约作者
📌 擅长领域:全栈工程师、爬虫、ACM算法,大数据,深度学习
💒 公众号:知识浅谈
本教程将带你实现一个实时手势猜拳游戏识别系统,使用Kaggle公开的「Rock-Paper-Scissors」数据集(包含石头、剪刀、布三种手势),全程仅需CPU即可运行。最终效果可通过摄像头实时识别手势,并与电脑进行猜拳对战!
🎈项目亮点
-
趣味互动:通过摄像头实现真人猜拳对战
-
轻量模型:专为CPU优化的微型卷积神经网络(仅0.5MB)
-
即用数据集:使用TensorFlow官方维护的公开数据集
-
工业级技巧:包含数据泄露预防、类别平衡处理等实战技巧
🎈环境准备
- 打开Pycharm,新建项目文件夹
- 安装所需依赖库
# 安装所需库(Python 3.8+) pip install numpy matplotlib opencv-python tensorflow-cpu
🎈数据集说明
使用TensorFlow Datasets内置的「Rock-Paper-Scissors」数据集:
-
总样本量:2,892张RGB图像(300x300像素)
-
类别分布:
-
Rock(石头): 840张
-
Paper(布): 840张
-
Scissors(剪刀): 1212张
-
-
数据特点:包含不同肤色、手势角度和背景环境
🎈完整实现代码
📍自动下载并加载数据集
import tensorflow as tf
import tensorflow_datasets as tfds
# 自动下载数据集(首次运行需要等待)
dataset, info = tfds.load('rock_paper_scissors',
split=['train', 'test'],
as_supervised=True,
with_info=True,
shuffle_files=True)
# 提取训练集和测试集
train_ds, test_ds = dataset[0], dataset[1]
# 查看数据集信息
print(f"训练集样本数: {info.splits['train'].num_examples}")
print(f"测试集样本数: {info.splits['test'].num_examples}")
📍数据预处理与增强
def preprocess(image, label):
# 统一尺寸 + 归一化
image = tf.image.resize(image, (150, 150))
image = tf.image.rgb_to_grayscale(image) # 转为灰度图减少计算量
return image/255.0, label
# 配置数据管道
BATCH_SIZE = 32
train_ds = train_ds.map(preprocess).cache().shuffle(1000).batch(BATCH_SIZE)
test_ds = test_ds.map(preprocess).batch(BATCH_SIZE)
# 数据增强层(仅在训练时启用)
data_augmentation = tf.keras.Sequential([
tf.keras.layers.RandomRotation(0.1),
tf.keras.layers.RandomZoom(0.1),
tf.keras.layers.RandomContrast(0.1)
])
📍构建微型CNN模型
model = tf.keras.Sequential([
# 输入层
tf.keras.layers.InputLayer(input_shape=(150, 150, 1)),
# 数据增强
data_augmentation,
# 特征提取
tf.keras.layers.Conv2D(16, (3,3), activation='relu'),
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.Dropout(0.5),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(3, activation='softmax')
])
# 编译模型
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.summary() # 查看模型结构(参数总量约5.1万)
📍训练与评估
# 自定义回调(防止过拟合)
early_stop = tf.keras.callbacks.EarlyStopping(
monitor='val_loss',
patience=5,
restore_best_weights=True
)
# 开始训练
history = model.fit(
train_ds,
epochs=30,
validation_data=test_ds,
callbacks=[early_stop]
)
# 评估测试集
loss, accuracy = model.evaluate(test_ds)
print(f"测试集准确率: {accuracy*100:.2f}%") # 约92-95%
📍实时手势对战
import cv2
import numpy as np
# 类别映射
CLASS_MAP = {0: "Rock", 1: "Paper", 2: "Scissors"}
# 游戏逻辑判断
def judge_game(user, computer):
if user == computer:
return "平局!"
elif (user - computer) % 3 == 1:
return "你赢了!"
else:
return "你输了!"
# 初始化摄像头
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 预处理帧
roi = frame[100:400, 100:400] # 捕获300x300区域
preprocessed = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
preprocessed = cv2.resize(preprocessed, (150, 150))
input_tensor = np.expand_dims(preprocessed, axis=(0, -1))
# 预测手势
pred = model.predict(input_tensor)
user_choice = np.argmax(pred[0])
computer_choice = np.random.randint(0,3) # 电脑随机出拳
# 显示结果
cv2.rectangle(frame, (100,100), (400,400), (0,255,0), 2)
cv2.putText(frame, f"You: {CLASS_MAP[user_choice]}",
(10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0,0), 2)
cv2.putText(frame, f"Computer: {CLASS_MAP[computer_choice]}",
(10,70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)
cv2.putText(frame, f"Result: {judge_game(user_choice, computer_choice)}",
(10,110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
cv2.imshow('Rock Paper Scissors', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
🎈性能优化技巧
- 模型量化:使用
tf.lite
转换模型,速度提升2-3倍converter = tf.lite.TFLiteConverter.from_keras_model(model) tflite_model = converter.convert() with open('model.tflite', 'wb') as f: f.write(tflite_model)
- 背景扣除:使用OpenCV的GrabCut算法提取手部区域
- 帧率优化:设置预测间隔,每5帧进行一次识别
🎈扩展玩法
- 战绩统计:记录胜负历史并显示胜率
- 特效增强:检测到剪刀手势时添加刀光动画
- 多人模式:通过左右分屏实现双人对战
- 手势扩展:添加蜥蜴、史波克手势(扩展为5类)
🎈常见问题解决
问题现象 | 解决方案 |
---|---|
摄像头延迟高 | 降低输入分辨率至100x100 |
背景干扰大 | 在纯色背景前操作 |
同一手势误判 | 增加训练时的旋转增强幅度 |
模型体积过大 | 使用深度可分离卷积 |
🎈项目总结
通过本教程你已掌握:
- 使用TensorFlow Datasets加载标准数据集
- 构建CPU友好的微型CNN架构
- 预防数据泄露的缓存技巧
- 实时视频流处理与游戏逻辑整合
下一步挑战:尝试添加「动态手势识别」功能,比如检测挥手动作触发游戏开始!
🍚干饭干饭
大功告成,撒花致谢🎆🎇🌟,关注我不迷路,带你起飞带你富。
Writted By 知识浅谈