首页 文章

程序没有终止(tkinter openCV线程)

提问于
浏览
0

我尝试构建一个GUI应用程序来从相机中抓取帧并在Tkinter GUI中显示它们 . Tkinter主循环在主线程中执行,而gui的帧抓取和更新在单独的线程中进行 .

下面的代码可以在我的gui窗口中正确抓取和显示视频流 . 但是当我通过单击“x”来关闭gui来调用on_close()方法时,gui将关闭,但程序不会完全终止 . 最后的CLI输出将是“Mainloop stopped!”,但程序没有像我期望的那样终止 . 所以,我怀疑额外的线程继续运行,即使我通过stop事件退出线程run()方法中的while循环 .

这是我的代码:

import threading    
import cv2
import tkinter
from tkinter import ttk
from PIL import Image
from PIL import ImageTk

import camera


class mainThread(threading.Thread):

    def __init__(self, gui):
        threading.Thread.__init__(self)
        self.stop_event = threading.Event()
        self.gui = gui

    def stop(self):
        print("T: Stop method called...")
        self.stop_event.set()

    def run(self):
        print("Connecting to camera...")
        cam = camera.Camera(resolution=(1280, 960), exposure=-3, bit_depth=12)
        cam.connect(device_id=0)

        while (not self.stop_event.is_set()):
            print("running..., stop event = " + str(self.stop_event.is_set()))
            # retrieve frame and frame time
            frame, _, _ = cam.get_frame()

            # display frame
            self.gui.updater(frame)

            # wait for displaying image
            cv2.waitKey(1)


class gui(object):

    def __init__(self, root):

        self.root = root

        # create and start thread running the main loop
        self.main_thread = mainThread(self)
        self.main_thread.start()

        # bind on close callback that executes on close of the main window
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

        # change window title
        self.root.title("MCT Laser Welding Quality Control")

        # set min size of root window and make window non resizable
        self.root.minsize(600, 400)
        self.root.resizable(False, False)

        # configure grid layout
        self.root.rowconfigure(0, weight=1)
        self.root.rowconfigure(1, weight=1)
        self.root.columnconfigure(0, weight=1)

        # create image panel
        self.image_panel = None

    def on_close(self):
        self.main_thread.stop()
        self.root.destroy()

    def updater(self, image):

        # TODO: resize frame first

        # convert image to tkinter image format
        image = Image.fromarray(image)
        image = ImageTk.PhotoImage(image)

        # if the panel does not exist, create and pack it
        if self.image_panel is None:

            # show the image in the panel
            self.image_panel = ttk.Label(self.root, image=image)
            self.image_panel.image = image  # keep reference

            # pack object into grid
            self.image_panel.grid(row=0, column=0)

        # just update the image on the panel
        else:
            self.image_panel.configure(image=image)
            self.image_panel.image = image  # keep reference

    def run(self):
        self.root.mainloop()


if __name__ == "__main__":

    # create a main window
    root = tkinter.Tk()

    # set style
    style = ttk.Style()
    style.theme_use("vista")

    # create gui instance
    user_interface = gui(root)

    # run the user interface
    root.mainloop()

    print("Mainloop stopped!")

编辑:我发现了,那行

image = ImageTk.PhotoImage(image)

防止线程如上所述停止 . 当我删除这一行并简单地用递增的数字更新标签文本时,当我关闭gui窗口时,一切都工作为例外并且线程终止 . 任何想法,为什么ImageTk.PhotoImage()导致线程无法正常终止?

1 回答

  • 0

    您需要加入该线程以等待它关闭 .

    def stop(self):
        print("T: Stop method called...")
        self.stop_event.set()
        self.join()
    

    此外,您可能需要关闭与相机的打开连接 .

    while (not self.stop_event.is_set()):
        ...
    cam.close() # not sure about exact API here
    

相关问题