利用 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
補充 5
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)
📚 相關資源
MediaPipe Hands 官方說明
Picamera2 教學文件
OpenCV putText 教學