Day07 偵測手部是否有拍打的動作


🟡 先看看程式的效果

今天的程式是利用 OpenCV 和 MediaPipe 進行即時手部偵測, 並估算手部與攝影機之間的距離, 當偵測到類似拍打的動作, 手掌的顏色便會由藍色變成綠色。

Today’s program uses OpenCV and MediaPipe for real-time hand detection and estimates the distance between the hand and the camera. When a slapping motion is detected, the color of the palm changes from blue to green.


🟡 學習目標

學習估算手掌的大小, 猜測手掌正在進行的動作。


🟡 程式碼

請先下載 “偵測手部是否有拍打的動作.py”
請按此下載

'''

Python + AI in 21 days
https://jasonworkshop.com/python

Designed by Jason Workshop

[請勿修改以上內容]

---

預備工作:

首先,請確保已安裝 opencv-python, mediapipe 模組
如不確定可直接在 Windows 的 cmd prompt 執行以下指定
pip install opencv-python mediapipe

'''

import cv2
import mediapipe as mp
import time

# 初始化 MediaPipe 手部偵測模組
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(min_detection_confidence=0.7, min_tracking_confidence=0.5)
mp_drawing = mp.solutions.drawing_utils

# 開啟攝影機
cap = cv2.VideoCapture(0)

def calculate_hand_size(hand_landmarks):
    # 簡單估算手部大小,使用手掌根部和中指指尖之間的距離
    wrist = hand_landmarks.landmark[mp_hands.HandLandmark.WRIST]
    middle_finger_tip = hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP]
    hand_size = ((wrist.x - middle_finger_tip.x) ** 2 + (wrist.y - middle_finger_tip.y) ** 2) ** 0.5
    return hand_size

# 儲存上一次的距離和時間
previous_distance = None
previous_time = time.time()
green_start_time = None

while cap.isOpened():
    success, image = cap.read()
    if not success:
        print("忽略空幀")
        continue

    # 翻轉影像以獲得鏡像效果
    image = cv2.flip(image, 1)

    # 將影像轉換為 RGB
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

    # 偵測手部
    results = hands.process(image_rgb)

    current_time = time.time()

    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # 計算手部大小
            hand_size = calculate_hand_size(hand_landmarks)

            # 假設手的實際大小大約為 20 cm,並估計距離
            distance_to_camera = 20 / hand_size if hand_size != 0 else 0

            # 比較當前距離和之前的距離
            if previous_distance is not None and (current_time - previous_time) >= 0.5:
                if previous_distance - distance_to_camera >= 1:
                    green_start_time = current_time  # 記錄開始變綠的時間

                # 更新上一次的距離和時間
                previous_distance = distance_to_camera
                previous_time = current_time
            else:
                previous_distance = distance_to_camera

            # 決定顏色
            if green_start_time is not None and (current_time - green_start_time) <= 1:
                color = (0, 255, 0)  # 綠色
            else:
                color = (255, 0, 0)  # 藍色

            # 繪製手部標記
            mp_drawing.draw_landmarks(image, hand_landmarks, mp_hands.HAND_CONNECTIONS,
                                      mp_drawing.DrawingSpec(color=color, thickness=2, circle_radius=2),
                                      mp_drawing.DrawingSpec(color=color, thickness=2))

            # 顯示手部與攝影機之間的距離
            #cv2.putText(image, f'Distance: {distance_to_camera:.2f} cm', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

    # 顯示影像
    cv2.imshow('Hand Detection', image)

    # 按下 ESC 鍵退出
    if cv2.waitKey(1) & 0xFF == 27: 
        break

cap.release()
cv2.destroyAllWindows()

🟡 小小挑戰一下

大家可以嘗試進行一些修改或改良喔! 例如:
✌️提高這個程式的辨識準繩度吧

😁 明天見!

按這裏回到 Python + AI 的 21 天挑戰