✊🤚✌️ Raspberry Pi 5 + PiCamera2 + MediaPipe 手勢辨識遊戲:「剪刀、石頭、布」
利用 MediaPipe Hands 偵測 21 個手部關鍵點,自行判斷使用者的手勢屬於哪一種。
🧰 一、環境與需求
✅ 硬體
-
Raspberry Pi 5(64-bit OS)
-
Raspberry Pi Camera Module v2/v3(已接上 CSI)
✅ 軟體
-
Python 3.9+
-
OpenCV
-
PiCamera2
-
MediaPipe 0.10.9(可於 ARM 安裝)
🛠️ 二、環境安裝
sudo apt update
sudo apt install -y python3-opencv python3-picamera2 libatlas-base-dev
pip install mediapipe==0.10.9
確認安裝成功:
python3 -c "import mediapipe as mp; print(mp.__version__)"
🧠 三、手勢分類邏輯(簡單版)
我們使用 MediaPipe 偵測手部的 21 個關鍵點(landmarks),然後依據以下規則簡單分類:
| 手勢 | 判斷邏輯(簡化) |
|---|---|
| ✊ 石頭 | 所有手指都彎曲 |
| ✋ 布 | 所有手指打開 |
| ✌️ 剪刀 | 只有食指與中指伸直,其餘彎曲 |
📸 四、完整程式碼
🔹 檔名:rps_game_picamera2.py
import cv2
import mediapipe as mp
from picamera2 import Picamera2
import time
# 初始化 MediaPipe Hands 與 Drawing 工具
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
hands = mp_hands.Hands(static_image_mode=False,
max_num_hands=1,
min_detection_confidence=0.5,
min_tracking_confidence=0.5)
# 初始化 PiCamera2
picam2 = Picamera2()
picam2.preview_configuration.main.size = (640, 480)
picam2.preview_configuration.main.format = "RGB888"
picam2.configure("preview")
picam2.start()
time.sleep(2)
# 判斷手勢的函數(簡單版)
def classify_hand_sign(landmarks):
finger_states = []
# 拇指判斷(橫向)
if landmarks[4].x > landmarks[3].x:
finger_states.append(1)
else:
finger_states.append(0)
# 其餘手指(縱向)
for tip_id in [8, 12, 16, 20]: # 食指、中指、無名指、小指
if landmarks[tip_id].y < landmarks[tip_id - 2].y:
finger_states.append(1)
else:
finger_states.append(0)
# 根據 finger_states 決定結果
if finger_states == [0, 0, 0, 0, 0]:
return "Rock ✊"
elif finger_states == [1, 1, 1, 1, 1]:
return "Paper ✋"
elif finger_states[1] == 1 and finger_states[2] == 1 and all(f == 0 for i, f in enumerate(finger_states) if i != 1 and i != 2):
return "Scissors ✌️"
else:
return "Unknown"
# 主迴圈
while True:
frame = picam2.capture_array()
image = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
result = hands.process(image)
if result.multi_hand_landmarks:
for hand_landmarks in result.multi_hand_landmarks:
mp_drawing.draw_landmarks(image, hand_landmarks, mp_hands.HAND_CONNECTIONS)
# 判斷手勢
sign = classify_hand_sign(hand_landmarks.landmark)
# 顯示文字
cv2.putText(image, sign, (10, 50), cv2.FONT_HERSHEY_SIMPLEX,
1.5, (0, 255, 0), 3)
cv2.imshow("RP5 - Rock Paper Scissors", image)
if cv2.waitKey(1) & 0xFF == 27:
break
cv2.destroyAllWindows()
picam2.stop()
✅ 執行方式
python3 rps_game_picamera2.py
👁️ 將你的手伸向攝影機!畫面上會顯示:
-
✊ Rock
-
✋ Paper
-
✌️ Scissors
-
或
Unknown(辨識不到)
📌 提升辨識準確度建議
| 方法 | 建議 |
|---|---|
| 環境光源 | 使用充足但不刺眼的光線 |
| 相機高度 | 設定攝影機與使用者手勢齊平 |
| 多角度資料 | 可增加不同手勢角度的訓練與測試資料 |
| 模型改進 | 改用分類器(KNN/SVM)分類 landmarks 可提升準確率 |
💡 延伸功能建議
| 功能 | 敘述 |
|---|---|
| 玩家 vs 電腦 | 隨機生成電腦手勢,進行對戰 |
| 加入倒數計時 | 用 OpenCV 畫出 3-2-1 計時圖示 |
| 配合聲音提醒 | 使用 pygame.mixer 播放音效 |
| 加上 Flask UI | 做成網頁版互動平台(可結合 WebSocket) |
📚 相關資源
文章標籤
全站熱搜
