Record OpenCV video during Tkinter mainloop
Handling this via multiprocessing
is easier than you think:
import multiprocessingimport Tkinter as tkimport cv2e = multiprocessing.Event()p = None# -------begin capturing and saving videodef 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: breakdef start_recording_proc(): global p p = multiprocessing.Process(target=startrecording, args=(e,)) p.start()# -------end video capture and stop tkdef 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()
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
.
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.