带有Tkinter和线程崩溃的OpenCV视频

时间:2014-09-08 17:33:21

标签: python opencv tkinter python-multithreading

我试图用Python,OpenCV和Tkinter创建一个多线程程序。 我的计划有一些普遍意义。

  • 从文件加载视频
  • 创建2个帖子
  • 从捕获对象获取帧并将其放入python Queue
  • 的第一个线程
  • 从队列中获取帧的第二个线程
  • 最后,如果可能,启动和停止捕获对象

然而,我的剧本似乎表现得很奇怪。有时它可以完成播放视频直到结束,但有时它也会在视频的某个时刻崩溃。这是我到目前为止所做的。

from Tkinter import Tk, Text
from Tkinter import PhotoImage
from ttk import Frame, Scrollbar, Button, Label
from PIL import Image, ImageTk
import cv
import time
import Queue
import threading

def writeToLog(log, msg):
    numlines = log.index('end - 1 line').split('.')[0]
    if log.index('end-1c')!='1.0': log.insert('end', '\n')
    log.insert('end', msg)
    log.see('end')

def GetIplImageMode(img):
    orientation = 1 if img.origin == 0 else -1
    mode_list = {(1, cv.IPL_DEPTH_8U)  : ("L", "L", 1),\
                 (3, cv.IPL_DEPTH_8U)  : ("BGR", "RGB", 3),\
                 (1, cv.IPL_DEPTH_32F) : ("F", "F", 4)}
    key = (img.nChannels, img.depth)
    modes = mode_list[key]
    return [modes[0], modes[1], orientation]

def IplImage2PIL(img, mode):
    return Image.fromstring(mode[1], (img.width, img.height),\
                            img.tostring(), "raw", mode[0],\
                            img.width * img.channels,\
                            mode[2])

def ResizePILImage(pil, width = 260, height = 180):
    return pil.resize((width, height), Image.ANTIALIAS)

def PIL2TkImage(pil):
    return ImageTk.PhotoImage(pil)

def setImageLabelFromIplImage(label, img_ipl):
    mode = GetIplImageMode(img_ipl)
    img_pil = IplImage2PIL(img_ipl, mode)
    img_resized = ResizePILImage(img_pil)
    img_tk = PIL2TkImage(img_resized)
    label.configure(image = img_tk)
    label.image = img_tk

def setImageLabelFromFile(label, szFileName):
    img_ipl = cv.LoadImage(szFileName)
    setImageLabelFromIplImage(label, img_ipl)

def mat_from_ipl(ipl):
    return cv.GetMat(ipl)

def ipl_from_mat(mat):
    ipl = cv.CreateImageHeader((mat.width, mat.height),\
                               cv.IPL_DEPTH_8U, mat.channels)
    cv.SetData(ipl, mat.tostring())
    return ipl

class asdf(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.pack(fill='both', expand=True)
        self.parent = parent
        self.variables()
        self.ui()
    def variables(self):
        self.ctr = 0
        self.fps = 0
        self.video = None
        self.image = None
        self.putProc = None
        self.getProc = None
        self.isRunning = False
        self.queue = Queue.Queue()
    def ui(self):
        f1 = Frame(self)
        frm1 = Frame(f1)
        self.lbl1 = Label(frm1, image=None)
        setImageLabelFromFile(self.lbl1, '../image.bmp')
        self.txt1 = Text(frm1, width=30, height=8)
        sb1 = Scrollbar(frm1, orient='vertical', command=self.txt1.yview)
        self.txt1.configure(yscrollcommand = sb1.set)
        self.lbl1.pack()
        self.txt1.pack(side='left')
        sb1.pack(side='left', fill='y')
        frm1.pack(side='left')
        frm2 = Frame(f1)
        self.lbl2 = Label(frm2, image=None)
        setImageLabelFromFile(self.lbl2, '../image.bmp')
        self.txt2 = Text(frm2, width=30, height=8)
        sb2 = Scrollbar(frm2, orient='vertical', command=self.txt2.yview)
        self.txt2.configure(yscrollcommand = sb2.set)
        self.lbl2.pack()
        self.txt2.pack(side='left')
        sb2.pack(side='left', fill='y')
        frm2.pack(side='left')
        f1.pack()
        f2 = Frame(self)
        Button(f2, text='Run', command=self.run).pack(side='left')
        Button(f2, text='Stop', command=self.stop).pack(side='left')
        f2.pack()
    def put_to_queue(self):
        while self.isRunning:
            self.ctr = self.ctr + 1
            self.image = cv.QueryFrame(self.video)
            time.sleep(1 / self.fps)
            try:
                writeToLog(self.txt1, '\nPut to queue .. %d' % (self.ctr))
                temp1 = cv.CloneImage(self.image)
                setImageLabelFromIplImage(self.lbl1, temp1)
                temp2 = mat_from_ipl(temp1)
                self.queue.put([self.ctr, temp2])
            except:
                writeToLog(self.txt1, '\nReach end of video ..')
                break
    def get_from_queue(self):
        while self.isRunning:
            from_queue = self.queue.get()
            self.ctr_fr = from_queue[0]
            if self.ctr_fr == self.ctr: time.sleep(30 / self.fps)
            temp1 = ipl_from_mat(from_queue[1])
            setImageLabelFromIplImage(self.lbl2, temp1)
            writeToLog(self.txt2, '\nGet from queue .. %d' % (self.ctr_fr))
            time.sleep(1 / self.fps)
    def run(self):
        self.isRunning = True
        self.video = cv.CreateFileCapture('../video.avi')
        self.fps = cv.GetCaptureProperty(self.video, cv.CV_CAP_PROP_FPS)
        writeToLog(self.txt1, '\nStart put_queue ..')
        self.putProc = threading.Thread(target=self.put_to_queue)
        self.putProc.start()
        time.sleep(1)
        writeToLog(self.txt2, '\nStart get_queue ..')
        self.getProc = threading.Thread(target=self.get_from_queue)
        self.getProc.start()
    def stop(self):
        self.isRunning = False
        if self.putProc.isAlive():
            self.putProc._Thread__stop()
            writeToLog(self.txt1, '\nputProc still alive, stopping ..')
            self.putProc = None
        if self.getProc.isAlive():
            self.getProc._Thread__stop()
            writeToLog(self.txt2, '\ngetProc still alive, stopping ..')
            self.getProc = None
        self.ctr_fr = 0
        self.ctr = 0

if __name__ == '__main__':
    root = Tk()
    c = asdf(root)
    root.mainloop()

我做错了吗?

任何想法都将非常感激。

由于

0 个答案:

没有答案