You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
5.2 KiB

import warnings
import threading
import cv2
import mediapipe as mp
import numpy as np
from tensorflow.keras.models import load_model
import os
# 设置环境变量以关闭oneDNN自定义操作
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
# 忽略SymbolDatabase.GetPrototype()弃用警告
warnings.filterwarnings("ignore", category=UserWarning, message='SymbolDatabase.GetPrototype() is deprecated')
# 初始化全局变量
hands = None
mp_draw = mp.solutions.drawing_utils
cap = None
keep_running = False
paused = 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)
# 初始化Hand对象
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, paused
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) # 转换颜色空间
if not paused:
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_rgb, handLms, mp.solutions.hands.HAND_CONNECTIONS)
gesture, raised_fingers = detect_gesture_and_fingers(handLms)
total_raised_fingers += raised_fingers
cv2.putText(img_rgb, f'Total Raised Fingers: {total_raised_fingers}', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2, cv2.LINE_AA)
if callback:
callback(total_raised_fingers, img_rgb) # 调用回调函数传递手指数和图像数据
def stop_recognition():
"""停止手势识别"""
global keep_running, cap, paused
keep_running = False
paused = False
if cap is not None:
cap.release()
cap = None
cv2.destroyAllWindows()
def release_camera():
"""释放摄像头资源"""
global cap
if cap is not None:
cap.release()
cap = None
def reset_hand_detection():
"""重置手部检测状态"""
global hands
hands = 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:
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:
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