2

下面的脚本打开一个视频文件并将其显示在 tkinter 标签中。帧获取是在另一个过程中进行的。

我的问题是我的quit_()函数在加载视频后调用它时将成功关闭完整脚本(python解释器然后空闲),但如果我在加载视频之前尝试退出,则会破坏根窗口并使程序继续运行(然后python解释器挂起,我必须手动杀死它)。该loadswitch变量是一个tkinter BooleanVar,它检测视频的加载,并导致脚本在进入主循环之前等待其值发生变化。

在我看来,问题在于没有文件路径作为参数的事实会导致某种异常,image_capture()从而导致退出问题。但是,脚本执行不会引发异常。

关于如何quit_()在视频加载之前终止完整脚本的任何想法将不胜感激!

我的脚本:

#!/usr/bin/python

import numpy as np
from multiprocessing import Process, Queue, Pipe
from Queue import Empty
import cv2
import cv2.cv as cv
from PIL import Image, ImageTk
import time
import Tkinter as tk
import tkMessageBox
import tkFileDialog

#tkinter GUI functions----------------------------------------------------------
def quit_(root, process):
   if tkMessageBox.askokcancel(message='Are you sure you want to quit?', icon='question', title='Quit'):
      process.terminate()
      root.destroy()

def load_win(root, loadswitch, con):
   #create child window when 'load video' button is clicked
   win = tk.Toplevel()
   win.resizable(False, False)
   #displays message, radiobuttons to choose data type, and gets the absolute file path if file
   tk.Label(win, text='Please choose video data type:').grid(column=0, row=0)
   videotype = tk.StringVar()
   videostream = tk.Radiobutton(win, text='Video live stream', variable=videotype, value='videostream').grid(column=0, row=1)
   videofile = tk.Radiobutton(win, text='Video file', variable=videotype, value='videofile').grid(column=0, row=2)
   def load_video(root, win, videotype):
      if videotype.get()=='videostream':
         win.destroy()
         #loadswitch.set(True)   #line to activate when stream capture code implemented
      elif videotype.get()=='videofile':
         filepath = tkFileDialog.askopenfilename()
         win.destroy()
         if filepath:
            loadswitch.set(True)
            con.send(filepath)
         else:
            pass
   tk.Button(win, text='OK', command=lambda: load_video(root, win, videotype)).grid(column=0, row=3)
   root.wait_window(win)

def update_image(image_label, queue, waitframe,root,process):
   if queue.get()==None:
      quit_(root,process)
   else:
      frame = queue.get()
      im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
      a = Image.fromarray(im)
      b = ImageTk.PhotoImage(image=a)
      image_label.configure(image=b)
      image_label._image_cache = b  # avoid garbage collection
      root.update()
      time.sleep(waitframe)

def update_all(root, image_label, queue,waitframe,process):
   update_image(image_label, queue, waitframe,root,process)
   root.after(0, func=lambda: update_all(root, image_label, queue,waitframe,process))

#multiprocessing image processing functions-------------------------------------
def image_capture(queue,con):
   videopath = con.recv()
   vidFile = cv2.VideoCapture(videopath)#pour mettre la web cam, changer pour 0 et commenter les ligne passant fps et waitframe
   fps = vidFile.get(cv2.cv.CV_CAP_PROP_FPS)
   waitframe = 1/fps
   con.send(waitframe)#sending waitkey duration through pipe to update_image()
   while True:
      try:
         flag, frame=vidFile.read()
         if flag==0:
            queue.put(None)
            break
         else:
            #image processing code goes here
            queue.put(frame)
            cv2.waitKey(10)
      except:
         continue

if __name__ == '__main__':
#initialize multiprocessing
queue = Queue()
pcon, ccon = Pipe()
#start video procesing
p = Process(target=image_capture, args=(queue,ccon))
p.start()
#GUI of root window (les menus arretent la video, car ils occupent le processus...)
root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", root.iconify)
root.title('FlowMap 0.1')
root.resizable(False, False)
image_label = tk.Label(master=root)# label for the video frame
image_label.grid(column=0, row=0, columnspan=2, rowspan=1)
#fill label with image until video is loaded
bg_im = ImageTk.PhotoImage(file='logo.png')
image_label['image'] = bg_im
# quit button
quit_button = tk.Button(master=root, text='Quit',command=lambda: quit_(root,p))
quit_button.grid(column=1, row=1)
#load video button and a switch to wait for the videopath to be chosen
loadswitch = tk.BooleanVar(master=root, value=False, name='loadswitch')
load_button = tk.Button(master=root, text='Load video',command=lambda: load_win(root, loadswitch, pcon))
load_button.grid(column=0, row=1)
#print an 'about' window
tkMessageBox.showinfo(message="FlowMap 0.1, (c) Raoul SCHORER 2013")
#wait for input to begin processing
root.wait_variable(loadswitch)
waitframe = pcon.recv()
print 'waitframe is: '+ str(waitframe)
# setup the update callback
root.after(0, func=lambda: update_all(root, image_label, queue, waitframe,p))
#exit program
root.mainloop()
print 'mainloop exit'
p.terminate()
print 'image capture process exit'
4

0 回答 0