我尝试构建一个GUI应用程序来从相机中抓取帧并在Tkinter GUI中显示它们。 Tkinter主循环在主线程中执行,而gui的帧抓取和更新则在一个单独的线程中进行。
以下代码可以在我的gui窗口中正确抓取并显示视频流。但是,当我通过单击" x"来调用on_close()方法时关闭gui,gui将关闭,但程序不会完全终止。最后的CLI输出将是" Mainloop停止!",但程序没有像我期望的那样终止。所以,我怀疑额外的线程继续运行,即使我通过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()导致线程无法正常终止?
答案 0 :(得分:0)
你需要加入线程等待它关闭。
function changeColor() {
if (window.scrollY == sectionClass.offsetTop) {
document.querySelector('.sectionClass').classList.add("newColorClass");
} else {
document.querySelector('.sectionClass').classList.remove("newColorClass");
}
}
此外,您可能需要关闭与相机的开放连接。
def stop(self):
print("T: Stop method called...")
self.stop_event.set()
self.join()