Tkinter GUI在单击按钮时崩溃

时间:2020-04-16 15:41:31

标签: python user-interface tkinter

我目前正在做一个机器学习项目,我正在尝试制作一个基本的Tkinter UI,以从执行手势识别的文件中调用函数。

当前,我的GUI上有一个按钮,要求手势识别文件中的“主要”功能,每次单击该按钮时,它都会运行该功能,但是GUI变得无响应,因此我无法单击其他任何东西。我想知道这是否与没有任何回报有关?这将停止ui主循环。

我要构建的功能是让UI运行Camera.py中的“主要功能”(我将在下面链接),然后为该主要功能的三个选项分别分配一个按钮“按1可以训练模型,按2可以检测手势”等。而不是手动输入。

我当前的UI代码是

import numpy as np
import matplotlib as plt
from sys import exit
from tkinter import *
from tkinter import ttk
import tkinter.simpledialog as sd
import camera as cam

modelobject = cam.Yolo_Model()

def runTraining():
    modelobject.main()

def getUserInput():
    options = {'minvalue':1, 'maxvalue':4}
    userInput = sd.askinteger('User Input', 'Select an Option', **options)
    print((f'You entered {userInput}'))

window=Tk()
window.title("Gesture Recognition")
window.geometry('600x350')

btn1 = ttk.Button(window, text="Train the Model", command=lambda: runTraining())
btn1.grid(column=0, row=0)


btn2 = ttk.Button(window, text="Detect Hand Gesture", command=lambda: getUserInput())
btn2.grid(column=1, row=0)


btn3 = ttk.Button(window, text="Clear Images Stored From Training")
btn3.grid(column=2, row=0)

def close_window():
    exit(0)
    window.destroy()

exitbtn = ttk.Button(window, text="Exit")
exitbtn.grid(column=0, row=4)
exitbtn.config(command=close_window)

window.mainloop()

我要在UI中运行并调用函数的文件的代码是

import numpy as np
import os
from numpy import expand_dims
import cv2
from trainer import predicter
from keras.preprocessing.image import img_to_array
import time
from im_to_txt import m
from random import random
import shutil


class Yolo_Model:
    # Sets the intial parameters used within the definition of the class.
    def __init__(self):
        # Enables the video capture
        self.cap = cv2.VideoCapture(0)
        # Sets the temporary directory used for the captured frame
        self.filename = "img.jpg"
        # Sets the destination of the training directory
        self.train_dir = "new_training"
        try:
            os.mkdir(self.train_dir)
        except:
            print("directory exists")

    def func(self, curr):
        boo = ""
        image = cv2.imread(self.filename)
        os.remove(self.filename)
        print("Enter 'T' if the label is correct or 'F' is the label is incorrect!")
        boo = input(curr[0] + "\n")
        try:
            if boo == 'T':
                name = str(random()) + '.jpg'
                name = os.path.join(self.train_dir, name)
                try:
                    cv2.imwrite(name, image)
                except:
                    print("Could not save the image to " + str(name))
                m(name, curr)
            image = cv2
        except ValueError as e:
            print(e)
            print("Value not recognised")

    def model_detector(self):
        while (self.cap.isOpened()):
            ret, frame = self.cap.read()
            if ret == True:
                # time.sleep(1)
                frame = cv2.flip(frame, +1)
                cv2.imshow('window', frame)
                try:
                    cv2.imwrite(self.filename, frame)
                except:
                    print("Could not save the image to img.jpg")
                output = predicter(0.6, self.filename)

                os.remove(self.filename)
                # os.remove(photo_filename)
                while (len(output) >= 5):
                    curr = output[0:6]
                    output = output[6:]
                    label = curr[0]
                    try:
                        image = cv2.rectangle(frame, (curr[1], curr[4]), (curr[3], curr[2]), (0, 0, 255), 3)
                        image = cv2.putText(frame, label, (curr[1], (curr[2] - 10)), cv2.FONT_HERSHEY_SIMPLEX, 1,
                                            (0, 255, 0), 2)
                    except:
                        print("Could not annote the image. Please ensure the co-ordinates are correct")
                    cv2.imshow('window', image)

            # Used to detstroy the image capture window
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
            else:
                break
                # This function is used to train the system. It detects a gesture being shown by the user and applies

    # a label. It then prompts the user, asking if the label identified was correct. If yes, the yolo format
    # text file is created, needed for training, and the image is saved into the training directory. The user
    # is also shown the detected image with the label and bounding box.
    def model_trainer(self):
        # Constant loop for capturing frames for the webcam.
        while (True):
            # Captures the image and frame number.
            ret, frame = self.cap.read()
            if ret == True:
                # Additional sleep timer can be used for waiting in between capturing frames. Turned
                # off for real time detection.
                # time.sleep(1)
                # Flips the frame so it appears the right way for the user.
                frame = cv2.flip(frame, +1)
                # Shows the user the frame that has been captured by the camera. This is constantly
                # updated each time a new frame is captured.
                cv2.imshow('window', frame)
                # Try and except block used incase the system cannot write the captured frame. The frame
                # is saved so it can be used by the prediction file.
                try:
                    cv2.imwrite(self.filename, frame)
                except:
                    print("Could not save the image to img.jpg")
                # The predict method from trainer.py is called. This will return the prediction of the captured
                # image along with the the parameters needed for the boudnding box and prediction score. The parameter
                # 0.6 corrosponds to threshold of how confident the model is about the label applied. Any lower and the
                # prediction will be discounted. 0.6 is lower than normal to allow for additonal classifcation to be made
                # during training.
                output = predicter(0.6, self.filename)
                # If the length of the array returned from the model prediction is greater than 5,i.e. a prediction was made
                # then the first 6 values, corrosponding to the length of one prediction, will be upacked until there are no more
                # predictions from that frame.
                while (len(output) >= 5):
                    # The first 6 values corrosponding to the first prediction are extracted
                    curr = output[0:6]
                    output = output[6:]
                    # The predicted label is the first value within the returned array
                    label = curr[0]
                    # A try block is used incase the given parameters for the bounding box are incorrect or cannot be labeled
                    # within the image.
                    try:
                        image = cv2.rectangle(frame, (curr[1], curr[4]), (curr[3], curr[2]), (0, 0, 255), 3)
                        image = cv2.putText(frame, label, (curr[1], (curr[2] - 10)), cv2.FONT_HERSHEY_SIMPLEX, 1,
                                            (0, 255, 0), 2)
                    except:
                        print("Could not annote the image. Please ensure the co-ordinates are correct")
                    cv2.imshow('window', image)
                    # This tunction is called to check if the predicted label was correct and if so use the image for training.
                    self.func(curr)
                    # Used to destroy the image capture window
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
            else:
                break

    # Adds additional ethics and security in removing the training directory
    # from the system.
    def removeFiles(self):
        # Try and except used incase the training directory could not be located.
        try:
            # Removes the training directory.
            shutil.rmtree(self.train_dir, ignore_errors=True)
        # Throws an OS error as the file cannot be found, printing user instructions on the error.
        except OSError as e:
            print("Error: ")
            print(e)

    # The main menu for the user to select the options for the system. This menu calls the functions
    # used for training, detecting, and removing stored images.
    def main(self):
        menu = input(
            "Press 1 to train the model: \nWarning training will store images of you!!\nPress 2 to detect the hand gesture: \nPress 3 to remove any images stored during training\n")
        if menu == '1':
            while (True):
                self.model_trainer()
        elif menu == '2':
            while (True):
                self.model_detector()
        elif menu == '3':
            self.removeFiles()
        # The final else statement catches the program should a unexpected value be entered.
        else:
            print("Error. Correct option not selected")


# Automatically calls the main method within the Yolo_Model class
if __name__ == "__main__":
    model = Yolo_Model()
    # Call the main method
    model.main()
    print("Closing application")
    # Try and except should the camera not have been used within the system.
    try:
        # Stop the frame capture
        cap.release()
        # Destroy the all the CV2 windows
        cv2.destroyAllWindows()
    except:
        print("Image capture not used")

为了澄清,在运行UI时,窗口会弹出,然后,当我单击当前分配给从camera.py运行“ main”的按钮时,它会运行,但是UI变得无响应,所以我必须从控制台完成此过程,这就是我要用UI功能替换的过程。

我希望这很清楚,而且由于我不是很有经验,我缺少一个明显的解决方法。 干杯

1 个答案:

答案 0 :(得分:0)

只要您的runTraining()函数正在运行,您的UI就会一直无响应。 您必须在单独的线程或进程中运行长时间运行的任务。如果要从长期运行的任务中更改UI元素,则必须设置一个在主循环中轮询的队列,并且可以在主循环的上下文中更改UI。

这里是一个示例:http://zetcode.com/articles/tkinterlongruntask/

另请参阅Python Tkinter: How do I make my GUI responsive as long as a thread runs?(评论中有一些指向相关问题的链接)

下面是一个示例,该示例直接使用PySimpleGui而不是TKinter:https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Multithreaded_Long_Tasks.py