我正在用tkinter编写一个图形用户界面,它使用cv2从计算机摄像机中提取视频流。为此,Thread使用while循环重新加载映像。
我一直在使用Locks,所以Threads (主Threads和auxiliar)都按照预期结束了它们的过程。但是,由于一个无法识别的DeadLock,我无法做到这一点。
守则如下:
import tkinter as tk
import cv2
import time
import sys
import threading
from PIL import ImageTk, Image
class Application:
gui_root = None
gui_panel = None
frame = None
video_capture = None
stop_event = None
thread = None
thread_lock = None
def __init__(self):
self.gui_root = tk.Tk()
self.gui_root.geometry("640x480")
self.gui_root.resizable(False, False)
self.video_capture = cv2.VideoCapture(0)
self.stop_event = threading.Event()
self.thread_lock = threading.Lock()
self.thread = threading.Thread(target=self.load_frame, args=())
self.thread.start()
self.gui_root.wm_protocol("WM_DELETE_WINDOW", self.on_close)
def start(self):
self.gui_root.mainloop()
def load_frame(self):
print('Starting load_frame')
while self.thread_lock.acquire() and not self.stop_event.is_set():
_, self.frame = self.video_capture.read()
self.frame = cv2.resize(self.frame, (640, 480))
c_image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
c_image_tk = ImageTk.PhotoImage(Image.fromarray(c_image))
if self.gui_panel is None:
self.gui_panel = tk.Label(image=c_image_tk)
self.gui_panel.place(width=640, height=480, x=0, y=0)
else:
self.gui_panel.configure(image=c_image_tk)
self.thread_lock.release()
print("End of while")
self.thread_lock.release()
print('End of Process 2')
def on_close(self):
self.stop_event.set()
print("Event set")
with self.thread_lock:
self.video_capture.release()
self.gui_root.destroy()
app = Application()
app.start()发布于 2018-03-08 00:38:15
这里最可能的问题是,您试图从后台线程创建一个新的tk.Label,这是不允许的。
我的第一个猜测是后台线程上的Tk代码只是挂起的--这并不是真正的死锁,但是既然在持有锁的时候会永远挂起一个线程,那么没有其他人会获得这个锁,所以它的效果几乎是一样的。
解决这一问题的唯一方法是让后台线程将消息发布到队列中,请求为它们完成GUI任务,并让主线程轮询每次通过事件循环排队(例如,通过after函数)。
旧的mttkinter项目以透明的方式结束了这个过程,但不幸的是,它从未为现代Python进行过更新。几年前,我组装了一个快速端口(在https://github.com/abarnert/mttkinter),但是我从来没有对它进行严格的测试,我也不知道是否有人用它来做任何严肃的事情。
但你可以试试这个,至少是为了一个快速的测试。如果这没有什么区别,那么您可能已经排除了Tk线程问题;如果它产生了很大的影响,那么很好(尽管这种区别可能是“现在它没有冻结,但是它崩溃了50%的时间--在这种情况下,您没有完成任务,并且不能相信mttkinter的原样,但至少您知道Tk线程是您必须解决的问题)。
https://stackoverflow.com/questions/49162990
复制相似问题