diff --git a/gesture_recognition.py b/gesture_recognition.py index f1bc7b09..335917d9 100644 --- a/gesture_recognition.py +++ b/gesture_recognition.py @@ -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() diff --git a/gui.py b/gui.py index c25edbef..d5988164 100644 --- a/gui.py +++ b/gui.py @@ -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__":