Record OpenCV video during Tkinter mainloop Record OpenCV video during Tkinter mainloop tkinter tkinter

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.