在Tkinter主循环中录制OpenCV视频 [英] Record OpenCV video during Tkinter mainloop

查看:260
本文介绍了在Tkinter主循环中录制OpenCV视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一项心理学实验,可以分析用户在完成行为任务时做出的面部表情.该应用程序主要通过Tkinter运行,我正在使用openCV捕获视频.

I am developing an psychology experiment that analyzes facial expressions made by users while completing a behavioral task. The application mostly runs through Tkinter, and i'm using openCV to capture video.

在最小的情况下,我需要根据用户的响应来开始和停止记录.例如,在下面的代码中,我希望用户指定何时使用鼠标按下按钮来开始和停止录制视频.

In a minimal case, i need to start and stop recording based on user responses. For example, in the code below, i want the user to specify when to start and stop recording video using the mouse to press a button.

import Tkinter as tk
import cv2

# -------begin capturing and saving video
def startrecording():
    cap = cv2.VideoCapture(0)
    fourcc = cv2.cv.CV_FOURCC(*'XVID')
    out = cv2.VideoWriter('output.avi',fourcc,  20.0, (640,480))

    while(cap.isOpened()):
        ret, frame = cap.read()
        if ret==True:
            out.write(frame)
        else:
            break

# -------end video capture and stop tk
def stoprecording():
    cap.release()
    out.release()
    cv2.destroyAllWindows()

    root.quit()
    root.destroy()

# -------configure window
root = tk.Tk()
root.geometry("%dx%d+0+0" % (100, 100))
startbutton=tk.Button(root,width=10,height=1,text='START',command = startrecording)
stopbutton=tk.Button(root,width=10,height=1,text='STOP', command = stoprecording)
startbutton.pack()
stopbutton.pack()

# -------begin
root.mainloop()

问题在于OpenCV使用循环来录制视频,在此期间Tkinter无法收听用户响应.程序卡在OpenCV循环中,用户无法继续. 我如何同时录制视频并收听用户回复?

The problem is that OpenCV uses a loop to record video, during which Tkinter is unable to listen for user responses. The program gets stuck in the OpenCV loop and the user is unable to continue. How can i simultaneously record video and listen for user responses?

我已经研究了并行处理(例如,使用多重处理在tkinter中显示OpenCV视频),但这听起来像是比看似必要的更大的努力.

I have looked into parallel processing (e.g., Display an OpenCV video in tkinter using multiprocessing), but this sounds like a larger endeavor than seems necessary.

我也研究过使用root.after命令(例如,显示网络摄像头序列TkInter ),但是使用它会出现你只能捕捉一个画面,而我想要一个视频.

I have also looked into using root.after command (e.g., Show webcam sequence TkInter), but using this it appears that you can only capture a single frame, whereas i want a video.

还有另一种方法吗?我需要使用两个处理流吗?

Is there another way? will i need to use two processing streams?

推荐答案

通过multiprocessing处理此问题比您想象的要容易:

Handling this via multiprocessing is easier than you think:

import multiprocessing
import Tkinter as tk
import cv2

e = multiprocessing.Event()
p = None

# -------begin capturing and saving video
def startrecording(e):
    cap = cv2.VideoCapture(0)
    fourcc = cv2.cv.CV_FOURCC(*'XVID')
    out = cv2.VideoWriter('output.avi',fourcc,  20.0, (640,480))

    while(cap.isOpened()):
        if e.is_set():
            cap.release()
            out.release()
            cv2.destroyAllWindows()
            e.clear()
        ret, frame = cap.read()
        if ret==True:
            out.write(frame)
        else:
            break

def start_recording_proc():
    global p
    p = multiprocessing.Process(target=startrecording, args=(e,))
    p.start()

# -------end video capture and stop tk
def stoprecording():
    e.set()
    p.join()

    root.quit()
    root.destroy()

if __name__ == "__main__":
    # -------configure window
    root = tk.Tk()
    root.geometry("%dx%d+0+0" % (100, 100))
    startbutton=tk.Button(root,width=10,height=1,text='START',command=start_recording_proc)
    stopbutton=tk.Button(root,width=10,height=1,text='STOP', command=stoprecording)
    startbutton.pack()
    stopbutton.pack()

    # -------begin
    root.mainloop()

我们所做的只是添加了对 ,以便您的视频捕获代码在子进程中运行,并在捕获完成后将其移动以清理代码.与单进程版本相比,唯一的额外皱纹是使用 multiprocessing.Event 通知子进程何时关闭,这是必需的,因为父进程无权访问outcap.

All we've done is added a call to multiprocessing.Process so that your video capture code runs in a child process, and moved the code to clean up when the capturing is done into that process as well. The only additional wrinkle compared to the single-process version is the use of a multiprocessing.Event to signal the child process when its time to shut down, which is necessary because the parent process doesn't have access to out or cap.

您可以尝试使用threading代替(只需将multiprocessing.Process替换为threading.Thread,并将multiprocessing.Event替换为threading.Event),但是我怀疑GIL会使您绊倒并损害GUI线程的性能.出于同样的原因,我认为不值得尝试通过root.after将读取/写入流集成到事件循环中-这只会损害性能,并且因为您不打算集成正在执行的操作进入GUI本身,没有理由尝试将其保持在与事件循环相同的线程/进程中.

You could try using threading instead (just replace multiprocessing.Process with threading.Thread, and multiprocessing.Event with threading.Event), but I suspect the GIL will trip you up and hurt the performance of the GUI thread. For the same reason, I don't think it's worth trying to integrate reading/writing the streams into your event loop via root.after - it's only going to hurt performance, and since you're not trying to integrate what you're doing into the GUI itself, there's no reason to try to keep it in the same thread/process as the event loop.

这篇关于在Tkinter主循环中录制OpenCV视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆