我使用tkinter
对cv2
编程GUI,使用Thread
从计算机相机中提取视频流。为此,Locks
使用while循环重新加载图像。
我一直在使用Threads
,因此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()
(主要的和辅助的)都按预期结束了他们的流程。但是,由于我无法识别死锁,我无法做到这一点。
代码如下:
flatMap
答案 0 :(得分:0)
这里最可能出现的问题是你正在尝试从后台线程中创建一个新的tk.Label
Tkinter,而且这是不允许的。
我的第一个猜测是,正在发生的事情是后台线程上的Tk代码只是悬挂 - 这实际上并不是一个死锁,但是因为你有一个线程在持有锁的情况下永远挂起,所以没有其他人会永远获得那个锁,所以它的效果大致相同。
解决这个问题的唯一方法是让你的后台线程将消息发布到队列,请求GUI内容为他们完成,并让主线程每次通过事件循环轮询该队列(例如,通过一个after
函数。)
旧的mttkinter
项目透明地包装了它,但遗憾的是它从未针对现代Python进行更新。几年前,我打了一个快速端口(https://github.com/abarnert/mttkinter),但是我从来没有严格测试过,而且我不知道是否有人曾用它来做任何严肃的事情。
但你可以试试这个至少是为了快速测试。如果它没有任何区别,那么你可能已经排除了Tk线程问题;如果它有所作为,那就太好了(虽然这种差异可能是“现在它没有冻结,但它会在50%的时间内崩溃 - 在这种情况下你没有完成,并且不能相信mttkinter
原样,但至少你知道Tk线程是你必须解决的问题。)