parent 7343b861a3
commit 244d4a197e

@ -4,13 +4,12 @@ import cv2
import mediapipe as mp
import numpy as np
from tensorflow.keras.models import load_model
from tkinter import Tk, Canvas, Button, Label, LEFT, RIGHT, NW
from PIL import Image, ImageTk
import os
# 设置环境变量以关闭oneDNN自定义操作
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
# 忽略SymbolDatabase.GetPrototype()弃用警告
warnings.filterwarnings("ignore", category=UserWarning, message='SymbolDatabase.GetPrototype() is deprecated')
# 初始化全局变量
@ -19,26 +18,31 @@ mp_draw = mp.solutions.drawing_utils
cap = None
keep_running = False
paused = False
popup_open = 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(root, callback=None):
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=(root, callback)).start()
# 启动识别线程
threading.Thread(target=run_recognition, args=(callback,)).start()
def run_recognition(root, callback=None):
def run_recognition(callback=None):
"""运行手势识别"""
global keep_running, paused
while keep_running and cap.isOpened():
@ -46,8 +50,8 @@ def run_recognition(root, callback=None):
if not ret:
break
img = cv2.flip(img, 1)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.flip(img, 1) # 翻转图像
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换颜色空间
if not paused:
results = hands.process(img_rgb)
@ -59,42 +63,47 @@ def run_recognition(root, callback=None):
gesture, raised_fingers = detect_gesture_and_fingers(handLms)
total_raised_fingers += raised_fingers
if total_raised_fingers > 0:
handle_finger_detection(total_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 total_raised_fingers == 5: # 如果检测到五根手指,调用回调函数传递手指数
if callback:
callback(total_raised_fingers)
if callback:
root.after(0, callback, img_rgb)
callback(img_rgb) # 调用回调函数传递图像数据
def stop_recognition():
global keep_running, cap
"""停止手势识别"""
global keep_running, cap, paused
keep_running = False
paused = 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)
@ -102,6 +111,7 @@ def predict_gesture(img):
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]
@ -128,120 +138,9 @@ def count_raised_fingers(hand_landmarks):
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
def handle_finger_detection(finger_count):
global paused, popup_open
if not popup_open:
if finger_count == 5:
paused = True
popup_open = True
show_stop_recognition_window()
# if finger_count == 1:
# paused = True
# popup_open = True
# show_stop_recognition_window()
# if finger_count == 1:
# paused = True
# popup_open = True
# show_stop_recognition_window()
# if finger_count == 1:
# paused = True
# popup_open = True
# show_stop_recognition_window()
# if finger_count == 1:
# paused = True
# popup_open = True
# show_stop_recognition_window()
def show_finger_window(message):
def on_continue():
global paused, popup_open
paused = False
popup_open = False # 关闭弹窗后将标志设置为False
finger_window.destroy()
start_recognition(show_frame)
finger_window = Tk()
finger_window.title("手指检测")
label = Label(finger_window, text=message, font=('Helvetica', 24, 'bold'))
label.pack(pady=20)
continue_button = Button(finger_window, text="继续识别", command=on_continue)
continue_button.pack(pady=10)
finger_window.protocol("WM_DELETE_WINDOW", on_continue)
finger_window.mainloop()
def show_stop_recognition_window():
def on_continue():
global paused, popup_open
paused = False
popup_open = False # 关闭弹窗后将标志设置为False
stop_window.destroy()
start_recognition(show_frame)
def on_stop():
global popup_open
stop_recognition()
popup_open = False # 关闭弹窗后将标志设置为False
stop_window.destroy()
stop_window = Tk()
stop_window.title("停止识别")
label = Label(stop_window, text="您竖起了五根手指,是否停止识别?", font=('Helvetica', 24, 'bold'))
label.pack(pady=20)
continue_button = Button(stop_window, text="继续识别", command=on_continue)
continue_button.pack(side=LEFT, padx=10, pady=10)
stop_button = Button(stop_window, text="停止识别", command=on_stop)
stop_button.pack(side=RIGHT, padx=10, pady=10)
stop_window.protocol("WM_DELETE_WINDOW", on_continue)
stop_window.mainloop()
def show_frame(img=None):
global paused, canvas
if keep_running and cap.isOpened():
if img is not None:
frame_rgb = img
else:
ret, frame = cap.read()
if not ret:
return
frame = cv2.flip(frame, 1)
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = Image.fromarray(frame_rgb)
imgtk = ImageTk.PhotoImage(image=img)
canvas.create_image(0, 0, anchor=NW, image=imgtk)
canvas.image = imgtk
if not paused:
root.after(10, show_frame)
else:
root.update_idletasks()
root.update()
if __name__ == "__main__":
root = Tk()
root.title("手势识别")
canvas = Canvas(root, width=640, height=480)
canvas.pack()
start_button = Button(root, text="开始识别", command=lambda: start_recognition(show_frame))
start_button.pack(side=LEFT, padx=10, pady=10)
stop_button = Button(root, text="停止识别", command=stop_recognition)
stop_button.pack(side=RIGHT, padx=10, pady=10)
root.mainloop()

@ -2,6 +2,7 @@ import threading
from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
import numpy as np # 导入 numpy
from gesture_recognition import start_recognition, stop_recognition, release_camera, keep_running
WINDOW_WIDTH = 800
@ -9,10 +10,12 @@ WINDOW_HEIGHT = 705
def main():
"""显示欢迎屏幕"""
show_welcome_screen()
def set_window_position(window, width, height):
"""设置窗口位置居中"""
screen_width = window.winfo_screenwidth()
screen_height = window.winfo_screenheight()
x = (screen_width - width) // 2
@ -21,6 +24,7 @@ def set_window_position(window, width, height):
def show_welcome_screen():
"""显示欢迎界面"""
welcome = Tk()
welcome.title("欢迎使用")
set_window_position(welcome, WINDOW_WIDTH, WINDOW_HEIGHT)
@ -44,8 +48,10 @@ def show_welcome_screen():
def show_main_screen():
global window, canvas
"""显示主界面"""
global window, canvas, root, paused, popup_open, status_label
window = Tk()
root = window
window.title("手势识别")
set_window_position(window, WINDOW_WIDTH, WINDOW_HEIGHT)
style = ttk.Style(window)
@ -63,7 +69,7 @@ def show_main_screen():
status_label = Label(frame_controls, text="等待开始...", font=('Helvetica', 14), bg='lightgray')
status_label.pack(side=LEFT, padx=(10, 20))
btn_start = ttk.Button(frame_controls, text="开始", command=lambda: start_thread(window, canvas, status_label))
btn_start = ttk.Button(frame_controls, text="开始", command=lambda: start_thread(root, canvas, status_label))
btn_start.pack(side=LEFT, padx=10)
btn_stop = ttk.Button(frame_controls, text="停止", command=lambda: stop_recognition_with_label(status_label))
@ -79,31 +85,87 @@ def show_main_screen():
def start_thread(root, canvas, status_label):
global keep_running
"""启动识别线程"""
global keep_running, paused, popup_open
if not keep_running:
status_label.config(text="正在识别...")
paused = False
popup_open = False
threading.Thread(
target=lambda: start_recognition(root, callback=lambda img: update_canvas(canvas, img))).start()
target=lambda: start_recognition(callback=lambda data: root.after(0, update_canvas, canvas, data))).start()
def stop_recognition_with_label(status_label):
"""停止识别并更新状态标签"""
stop_recognition()
status_label.config(text="已停止")
def exit_program():
"""退出程序"""
global window
stop_recognition()
release_camera()
window.destroy()
def update_canvas(canvas, img):
img = Image.fromarray(img)
imgtk = ImageTk.PhotoImage(image=img)
canvas.create_image(320, 240, image=imgtk)
canvas.image = imgtk
canvas.update()
def update_canvas(canvas, data):
"""更新画布显示图像或处理手指数"""
if isinstance(data, np.ndarray): # 确保传入的data是图像数据
img = Image.fromarray(data)
imgtk = ImageTk.PhotoImage(image=img)
canvas.create_image(0, 0, anchor=NW, image=imgtk)
canvas.image = imgtk
canvas.update()
else:
handle_finger_detection(data)
def handle_finger_detection(finger_count):
"""处理检测到的手指数"""
global paused, popup_open
if not popup_open:
if finger_count == 5:
paused = True
popup_open = True
show_stop_recognition_window()
elif finger_count == 0:
paused = True
popup_open = True
def show_stop_recognition_window():
"""显示停止识别确认窗口"""
def on_continue():
"""继续识别"""
global paused, popup_open
paused = False
popup_open = False # 关闭弹窗后将标志设置为False
stop_window.destroy()
start_thread(root, canvas, status_label)
def on_stop():
"""停止识别"""
global popup_open
stop_recognition()
popup_open = False # 关闭弹窗后将标志设置为False
stop_window.destroy()
stop_window = Tk()
stop_window.title("停止识别")
label = Label(stop_window, text="您竖起了五根手指,是否停止识别?", font=('Helvetica', 24, 'bold'))
label.pack(pady=20)
continue_button = Button(stop_window, text="继续识别", command=on_continue)
continue_button.pack(side=LEFT, padx=10, pady=10)
stop_button = Button(stop_window, text="停止识别", command=on_stop)
stop_button.pack(side=RIGHT, padx=10, pady=10)
stop_window.protocol("WM_DELETE_WINDOW", on_continue)
stop_window.mainloop()
if __name__ == "__main__":

Loading…
Cancel
Save