当前位置: 首页 > 知识库问答 >
问题:

程序未终止(tkinter openCV线程)

鲍向笛
2023-03-14

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

下面的代码作为一个视频流被抓取并正确显示在我的gui窗口中。但是,当我通过单击“x”来调用on_close()方法来关闭gui时,gui将关闭,但程序不会完全终止。最后一次CLI输出将为“Mainloop stopped!”,但该计划并没有像我预期的那样终止。因此,即使我通过stop事件退出threads 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个答案

姬宝
2023-03-14

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

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
 类似资料:
  • 问题内容: 如何使多线程python程序响应Ctrl + C键事件? 编辑: 代码是这样的: 我试图在所有线程上删除join(),但仍然无法正常工作。是否因为每个线程的run()过程中的锁段? 编辑: 上面的代码应该可以工作,但是当当前变量在5,000-6,000范围内并遍历以下错误时,它总是会中断 问题答案: 在启动主线程之前,将除主线程之外的每个线程都设为守护进程(在2.6或更高版本中,在2.

  • 我正在编写一个JavaFX应用程序,我的对象扩展任务提供了JavaFXGUI线程之外的并发性。 我的主要课程是这样的: 我的GUI控制器示例如下(略作抽象): 目前,我的任务只是进行睡眠并打印数字1到10: 我遇到的问题是,一旦任务完成,就好像启动任务的线程继续运行一样。因此,当我按下右上角的“X”退出JavaFX应用程序时,JVM继续运行,我的应用程序不会终止。如果你看一下我的主课,我已经把系统

  • 主要内容:1 什么是Java终止线程,2 Thread类终止线程的方法,3 Java终止线程的例子1,4 Java终止线程的例子2,5 Java终止线程的例子3,6 isInterrupted和interrupted方法1 什么是Java终止线程 如果任何线程处于睡眠或等待状态(即,调用sleep()或wait()方法),则在线程上调用interrupt()方法,会抛出InterruptedException中断睡眠或等待状态。如果线程未处于睡眠或等待状态,则调用interrupt()方法将执行

  • 问题内容: 我有两个线程:主线程和从主线程生成的线程。 当主线程退出时,整个程序会终止吗? 问题答案: 没有。 当所有非守护程序线程完成时,Java程序终止。 该文档指出: Java虚拟机启动时,通常只有一个非守护程序线程(通常调用某些指定类的名为main的方法)。Java虚拟机将继续执行线程,直到发生以下任何一种情况: 类的方法已被调用,安全管理器已允许进行退出操作。 不是守护程序线程的所有线程

  • 问题内容: 当我测试创建子线程的方法的执行时,JUnit测试会在子线程之前终止并杀死它。 我如何强制JUnit等待子线程完成其执行? 谢谢 问题答案: 阅读问题和评论后,似乎您需要的是 一种对异步操作进行单元测试的技术 。doSomething()立即返回,但是您希望测试代码等待其完成,然后进行一些验证。 问题在于该测试无法识别该调用所产生的线程,因此显然它无法等待它们。人们可以想到许多复杂的(可