|
|
|
|
import warnings
|
|
|
|
|
import threading #导入多线程模块
|
|
|
|
|
import cv2
|
|
|
|
|
import mediapipe as mp
|
|
|
|
|
import numpy as np
|
|
|
|
|
from tensorflow.keras.models import load_model
|
|
|
|
|
|
|
|
|
|
# 禁用特定警告
|
|
|
|
|
warnings.filterwarnings("ignore", category=UserWarning, message='SymbolDatabase.GetPrototype() is deprecated')
|
|
|
|
|
|
|
|
|
|
# 初始化 MediaPipe 和 OpenCV
|
|
|
|
|
hands = None
|
|
|
|
|
mp_draw = mp.solutions.drawing_utils
|
|
|
|
|
cap = None
|
|
|
|
|
keep_running = False
|
|
|
|
|
|
|
|
|
|
# 加载手势识别模型
|
|
|
|
|
model_path = 'D:/hand/hand_gesture_model.h5'
|
|
|
|
|
model = load_model(model_path)
|
|
|
|
|
|
|
|
|
|
# 定义手势类别
|
|
|
|
|
gesture_classes = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09']
|
|
|
|
|
|
|
|
|
|
def start_recognition(callback=None):
|
|
|
|
|
global keep_running, cap, hands
|
|
|
|
|
if cap is None or not cap.isOpened():
|
|
|
|
|
cap = cv2.VideoCapture(0)
|
|
|
|
|
if hands is None:
|
|
|
|
|
hands = mp.solutions.hands.Hands(static_image_mode=False, max_num_hands=2,
|
|
|
|
|
model_complexity=1, min_detection_confidence=0.5,
|
|
|
|
|
min_tracking_confidence=0.5)
|
|
|
|
|
keep_running = True
|
|
|
|
|
threading.Thread(target=run_recognition, args=(callback,)).start()
|
|
|
|
|
|
|
|
|
|
def run_recognition(callback=None):
|
|
|
|
|
global keep_running
|
|
|
|
|
last_gesture = None
|
|
|
|
|
|
|
|
|
|
while keep_running and cap.isOpened():
|
|
|
|
|
ret, img = cap.read()
|
|
|
|
|
if not ret:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
img = cv2.flip(img, 1)
|
|
|
|
|
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
|
|
|
results = hands.process(img_rgb)
|
|
|
|
|
|
|
|
|
|
total_raised_fingers = 0
|
|
|
|
|
|
|
|
|
|
if results.multi_hand_landmarks:
|
|
|
|
|
for handLms in results.multi_hand_landmarks:
|
|
|
|
|
mp_draw.draw_landmarks(img, handLms, mp.solutions.hands.HAND_CONNECTIONS)
|
|
|
|
|
_, raised_fingers = detect_gesture_and_fingers(handLms)
|
|
|
|
|
total_raised_fingers += raised_fingers
|
|
|
|
|
|
|
|
|
|
cv2.putText(img, f'Total Raised Fingers: {total_raised_fingers}', (10, 30),
|
|
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2, cv2.LINE_AA,)
|
|
|
|
|
|
|
|
|
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
|
|
|
if callback:
|
|
|
|
|
callback(img)
|
|
|
|
|
|
|
|
|
|
stop_recognition()
|
|
|
|
|
#停止识别
|
|
|
|
|
def stop_recognition():
|
|
|
|
|
global keep_running, cap
|
|
|
|
|
keep_running = False
|
|
|
|
|
if cap is not None and cap.isOpened():
|
|
|
|
|
cap.release()
|
|
|
|
|
cap = None
|
|
|
|
|
cv2.destroyAllWindows()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#释放摄像头资源
|
|
|
|
|
def release_camera():
|
|
|
|
|
global cap
|
|
|
|
|
if cap is not None and cap.isOpened():
|
|
|
|
|
cap.release()
|
|
|
|
|
cap = None
|
|
|
|
|
|
|
|
|
|
def detect_gesture_and_fingers(hand_landmarks):
|
|
|
|
|
# 手势识别
|
|
|
|
|
gesture_image = get_hand_image(hand_landmarks)
|
|
|
|
|
gesture = predict_gesture(gesture_image)
|
|
|
|
|
|
|
|
|
|
# 手指竖起数量检测
|
|
|
|
|
raised_fingers = count_raised_fingers(hand_landmarks)
|
|
|
|
|
|
|
|
|
|
return gesture, raised_fingers
|
|
|
|
|
|
|
|
|
|
def get_hand_image(hand_landmarks):
|
|
|
|
|
# 提取手部区域图像
|
|
|
|
|
# 示例实现,请根据你的需要进行调整
|
|
|
|
|
img = np.zeros((150, 150, 3), dtype=np.uint8) # 示例图像
|
|
|
|
|
return img
|
|
|
|
|
|
|
|
|
|
def predict_gesture(img):
|
|
|
|
|
img = cv2.resize(img, (150, 150))
|
|
|
|
|
img_array = np.expand_dims(img, axis=0) / 255.0
|
|
|
|
|
predictions = model.predict(img_array)
|
|
|
|
|
predicted_class = gesture_classes[np.argmax(predictions)]
|
|
|
|
|
return predicted_class
|
|
|
|
|
|
|
|
|
|
def count_raised_fingers(hand_landmarks):
|
|
|
|
|
fingers_status = [0, 0, 0, 0, 0]
|
|
|
|
|
|
|
|
|
|
# 拇指
|
|
|
|
|
thumb_tip = hand_landmarks.landmark[mp.solutions.hands.HandLandmark.THUMB_TIP]
|
|
|
|
|
thumb_ip = hand_landmarks.landmark[mp.solutions.hands.HandLandmark.THUMB_IP]
|
|
|
|
|
thumb_mcp = hand_landmarks.landmark[mp.solutions.hands.HandLandmark.THUMB_MCP]
|
|
|
|
|
thumb_cmc = hand_landmarks.landmark[mp.solutions.hands.HandLandmark.THUMB_CMC]
|
|
|
|
|
|
|
|
|
|
# 计算拇指的角度
|
|
|
|
|
angle_thumb = calculate_angle(thumb_cmc, thumb_mcp, thumb_tip)
|
|
|
|
|
if angle_thumb > 160: # 如果拇指的角度大于160度,认为拇指竖起
|
|
|
|
|
fingers_status[0] = 1
|
|
|
|
|
|
|
|
|
|
# 其他手指
|
|
|
|
|
for i, finger_tip_id in enumerate([mp.solutions.hands.HandLandmark.INDEX_FINGER_TIP,
|
|
|
|
|
mp.solutions.hands.HandLandmark.MIDDLE_FINGER_TIP,
|
|
|
|
|
mp.solutions.hands.HandLandmark.RING_FINGER_TIP,
|
|
|
|
|
mp.solutions.hands.HandLandmark.PINKY_TIP]):
|
|
|
|
|
finger_tip = hand_landmarks.landmark[finger_tip_id]
|
|
|
|
|
finger_pip = hand_landmarks.landmark[finger_tip_id - 2]
|
|
|
|
|
finger_mcp = hand_landmarks.landmark[finger_tip_id - 3]
|
|
|
|
|
|
|
|
|
|
# 计算手指的角度
|
|
|
|
|
angle_finger = calculate_angle(finger_mcp, finger_pip, finger_tip)
|
|
|
|
|
if angle_finger > 160: # 如果手指的角度大于160度,认为手指竖起
|
|
|
|
|
fingers_status[i + 1] = 1
|
|
|
|
|
|
|
|
|
|
return sum(fingers_status)
|
|
|
|
|
|
|
|
|
|
def calculate_angle(point1, point2, point3):
|
|
|
|
|
# 计算三个点之间的角度
|
|
|
|
|
angle = np.arctan2(point3.y - point2.y, point3.x - point2.x) - np.arctan2(point1.y - point2.y, point1.x - point2.x)
|
|
|
|
|
angle = np.abs(angle)
|
|
|
|
|
if angle > np.pi:
|
|
|
|
|
angle = 2 * np.pi - angle
|
|
|
|
|
return angle * 180 / np.pi
|