我正在尝试使用以下代码创建一个交互式GUI,在点击按钮时更改颜色空间(HSV,RBG,灰度等)。 Display an OpenCV video in tkinter using multiprocessing 作为python的新手,我遇到了多处理问题,我尝试制作GUI会改变按钮点击时的颜色空间会挂起整个系统。任何有关它的实施的帮助将受到高度赞赏。谢谢。 以下是我的代码:
import cv2
from PIL import Image,ImageTk
import Tkinter as tk
import numpy as np
from multiprocessing import Process , Queue
def quit_it(root,process):
root.destroy()
process.terminate()
def black_andwhite(root,process):
process.terminate
p=Process(target=capture_image, args=(5,queue, ))
p.start()
root.after(0, func=lambda: update_all(root, image_label, queue))
def update_image(image_label, queue):
frame = queue.get()
a = Image.fromarray(frame)
b = ImageTk.PhotoImage(image=a)
image_label.configure(image=b)
image_label._image_cache = b
root.update()
def update_all(root, image_label, queue):
update_image(image_label, queue)
root.after(0, func=lambda: update_all(root, image_label, queue))
def capture_image(var,queue):
vidFile = cv2.VideoCapture(0)
while True:
try:
flag, frame=vidFile.read()
if flag==0:
break
if(var==5):
frame1=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
else:
frame1=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
queue.put(frame1)
cv2.waitKey(20)
except:
continue
if __name__ == '__main__':
queue=Queue();
root=tk.Tk()
root.geometry("1500x1200+2+2")
image_label=tk.Label(master=root)
image_label.pack()
p=Process(target=capture_image, args=(7,queue, ))
p.start()
quit_button=tk.Button(master=root, text='Quit', command=lambda:quit_it(root,p))
quit_button.pack()
bandw_button=tk.Button(master=root, text='black_and_white',command=lambda:black_andwhite(root,p))
bandw_button.pack()
root.after(5, func=lambda: update_all(root, image_label, queue,))
root.mainloop()
p.terminate()
答案 0 :(得分:0)
在代码中添加一些日志记录,以查看何时执行哪些部分。多线程代码总是难以调试(因为调试器等待你时会发生事情)。记录将为您提供有关何时发生的事件的报告,这将允许您跟踪意外行为。$
在这种情况下,我看到两个问题:
except: continue
将默默忽略帧捕获循环中的任何问题。因此,如果出现问题,则不会将任何图像推送到队列中。但这应该会导致queue.get()
抛出Empty
例外。
第二个问题是您安装update_all()
两次。因此,您将有一个进程/循环,每N毫秒向队列添加一个映像,但在主事件循环中尝试获取映像的两个回调。这可能导致Python锁定。
再次,使用日志记录来查看进程何时启动,何时将图像放入队列并从中获取,以及注册了多少回调以处理队列中的图像。
[编辑] 如果原始代码有效,请使用其他方法:
而不是使用after()
安装第二个回调设置标志。设置标志后,更改颜色空间。否则,不管它。单击该按钮时,切换标志。