我正在开发一个心理学实验,分析用户在完成行为任务时所做的面部表情。该应用程序主要通过Tkinter运行,我正在使用openCV来捕获视频。
在极少数情况下,我需要根据用户的反应开始和停止录制。例如,在下面的代码中,我希望用户使用鼠标指定何时开始和停止录制视频按钮。
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循环,用户无法继续。 如何同时录制视频和收听用户回复?
我研究过并行处理(例如Display an OpenCV video in tkinter using multiprocessing),但这听起来似乎是一项比看似必要的更大的努力。
我也研究过使用root.after命令(例如Show webcam sequence TkInter),但是使用它看起来你只能捕获一个帧,而我想要一个视频。
还有其他方法吗?我需要使用两个处理流吗?
答案 0 :(得分:3)
通过multiprocessing
处理此问题比您想象的要容易:
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.Process
的调用,以便您的视频捕获代码在子进程中运行,并且在捕获完成到该进程时也移动代码进行清理。与单进程版本相比,唯一的额外皱纹是使用multiprocessing.Event
在关闭时间时向子进程发出信号,这是必要的,因为父进程无法访问{{ 1}}或out
。
您可以尝试使用cap
代替(只需将threading
替换为multiprocessing.Process
,将threading.Thread
替换为multiprocessing.Event
),但我怀疑GIL会绊倒你起来并损害了GUI线程的性能。出于同样的原因,我认为值得尝试通过threading.Event
将读取/写入流集成到您的事件循环中 - 它只会损害性能,并且从那时起你并没有试图将你正在做的事情整合到GUI本身中,没有理由试图将它与事件循环保持在同一个线程/进程中。