showing video on the entire screen using OpenCV and Tkiner showing video on the entire screen using OpenCV and Tkiner tkinter tkinter

showing video on the entire screen using OpenCV and Tkiner


It's not a hard task if you don't care about execution time! We knew that resizing of an image isn't a rocket science for common user, but under the hood it takes some time to resize each frame. And if you really wonder about time and options - there're many options to play around from numpy/scipy to skimage/skvideo.

But let's try to do something with your code "as is" so we have two options to play with: cv2 and Image. For testing I grabbed 20 secs of "Keyboard Cat" video from youtube (480p) and resize each frame upto 1080p, and GUI looks like this (fullscreen 1920x1080):

enter image description here

Resize Methods / timeit elapsed time of showing frames:

As you see - no big difference between theese two so here's a code (only Application class and video_loop changed):

#importstry:    import tkinter as tkexcept:    import Tkinter as tkfrom PIL import Image, ImageTkimport argparseimport datetimeimport cv2import osclass Application:    def __init__(self, output_path = "./"):        """ Initialize application which uses OpenCV + Tkinter. It displays            a video stream in a Tkinter window and stores current snapshot on disk """        self.vs = cv2.VideoCapture('KeyCat.mp4') # capture video frames, 0 is your default video camera        self.output_path = output_path  # store output path        self.current_image = None  # current image from the camera        self.root = tk.Tk()  # initialize root window        self.root.title("PyImageSearch PhotoBooth")  # set window title        # self.destructor function gets fired when the window is closed        self.root.protocol('WM_DELETE_WINDOW', self.destructor)        self.root.attributes("-fullscreen", True)        # getting size to resize! 30 - space for button        self.size = (self.root.winfo_screenwidth(), self.root.winfo_screenheight() - 30)        self.panel = tk.Label(self.root)  # initialize image panel        self.panel.pack(fill='both', expand=True)        # create a button, that when pressed, will take the current frame and save it to file        self.btn = tk.Button(self.root, text="Snapshot!", command=self.take_snapshot)        self.btn.pack(fill='x', expand=True)        # start a self.video_loop that constantly pools the video sensor        # for the most recently read frame        self.video_loop()    def video_loop(self):        """ Get frame from the video stream and show it in Tkinter """        ok, frame = self.vs.read()  # read frame from video stream        if ok:  # frame captured without any errors            cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)  # convert colors from BGR to RGBA            cv2image = cv2.resize(cv2image, self.size, interpolation=cv2.INTER_NEAREST)            self.current_image = Image.fromarray(cv2image) #.resize(self.size, resample=Image.NEAREST)  # convert image for PIL            self.panel.imgtk = ImageTk.PhotoImage(image=self.current_image)            self.panel.config(image=self.panel.imgtk)  # show the image            self.root.after(1, self.video_loop)  # call the same function after 30 milliseconds

But you knew - do such a things "on fly" isn't a good idea, so lets try to resize all frames first and then do all stuff(only Application class and video_loop method changed, resize_video method added):

class Application:    def __init__(self, output_path = "./"):        """ Initialize application which uses OpenCV + Tkinter. It displays            a video stream in a Tkinter window and stores current snapshot on disk """        self.vs = cv2.VideoCapture('KeyCat.mp4') # capture video frames, 0 is your default video camera        ...        # init frames        self.frames = self.resize_video()        self.video_loop()def resize_video(self):    temp = list()    try:        temp_count_const = cv2.CAP_PROP_FRAME_COUNT    except AttributeError:        temp_count_const = cv2.cv.CV_CAP_PROP_FRAME_COUNT    frames_count = self.vs.get(temp_count_const)    while self.vs.isOpened():        ok, frame = self.vs.read()  # read frame from video stream        if ok:  # frame captured without any errors            cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)  # convert colors from BGR to RGBA            cv2image = cv2.resize(cv2image, self.size, interpolation=cv2.INTER_NEAREST)            cv2image = Image.fromarray(cv2image)  # convert image for PIL            temp.append(cv2image)            # simple progress print w/o sys import            print('%d/%d\t%d%%' % (len(temp), frames_count, ((len(temp)/frames_count)*100)))        else:            return tempdef video_loop(self):    """ Get frame from the video stream and show it in Tkinter """    if len(self.frames) != 0:        self.current_image = self.frames.pop(0)        self.panel.imgtk = ImageTk.PhotoImage(self.current_image)        self.panel.config(image=self.panel.imgtk)        self.root.after(1, self.video_loop)  # call the same function after 30 milliseconds

timeit elapsed time of showing pre-resized frames: ~78.78 s.

As you see - resizing isn't a main problem of your script, but a good option!