如何在python的GUI TKinter中通过同一个ImageLabel从另一个进程调用替换正在进行的图像捕获过程

时间:2015-07-13 14:35:08

标签: python user-interface opencv tkinter multiprocessing

我正在尝试使用以下代码创建一个交互式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()

1 个答案:

答案 0 :(得分:0)

在代码中添加一些日志记录,以查看何时执行哪些部分。多线程代码总是难以调试(因为调试器等待你时会发生事情)。记录将为您提供有关何时发生的事件的报告,这将允许您跟踪意外行为。$

在这种情况下,我看到两个问题:

except: continue

将默默忽略帧捕获循环中的任何问题。因此,如果出现问题,则不会将任何图像推送到队列中。但这应该会导致queue.get()抛出Empty例外。

第二个问题是您安装update_all()两次。因此,您将有一个进程/循环,每N毫秒向队列添加一个映像,但在主事件循环中尝试获取映像的两个回调。这可能导致Python锁定。

再次,使用日志记录来查看进程何时启动,何时将图像放入队列并从中获取,以及注册了多少回调以处理队列中的图像。

[编辑] 如果原始代码有效,请使用其他方法:

而不是使用after()安装第二个回调设置标志。设置标志后,更改颜色空间。否则,不管它。单击该按钮时,切换标志。