Python + OpenCV + Tkinter playing video help
Hey, all. So here's my problem: I need a GUI to get a live webcam stream from openCV (or just open a video file), pass it to the Tkinter GUI window, and add some buttons and stuff to it. when I run the code and play the video, the video plays with proper FPS (same speed as just opening it with winows media player), however, the video window is small. It's very important that i get the video to full screen dimentions, perhaps a tad less so I can still see the GUI button.
If i try to resize the video for full screen, by adding self.current_image= self.current_image.resize([2560,1440],PIL.Image.ANTIALIAS), my FPS drop and video is playing very slowly.
going with self.root.attributes("-fullscreen",True) , the window just goes full screen but the video size itself is same. so that's no good either.
How can I fill the screen with the video while keeping proper FPS? is it a code error or just slow processing?
here is the code: thanks evryone
import PIL
from PIL import Image, ImageTk
import Tkinter as tk
import argparse
import datetime
import cv2
import os
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('Kaabil Hoon (Kaabil) Hrithik Roshan (2K Ultra HD 1440p)-(HDLoft.Com).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.panel = tk.Label(self.root) # initialize image panel
self.panel.pack(padx=10, pady=10)
self.root.config(cursor="arrow")
# create a button, that when pressed, will take the current frame and save it to file
btn = tk.Button(self.root, text="Snapshot!", command=self.take_snapshot)
btn.pack(fill="both", expand=True, padx=10, pady=10)
# 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
# frame = cv2.resize(frame, (1500,1000))
if ok: # frame captured without any errors
key = cv2.waitKey(1000)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA) # convert colors from BGR to RGBA
self.current_image = Image.fromarray(cv2image) # convert image for PIL
#self.current_image= self.current_image.resize([1280,1024],PIL.Image.ANTIALIAS)
imgtk = ImageTk.PhotoImage(image=self.current_image) # convert image for tkinter
self.panel.imgtk = imgtk # anchor imgtk so it does not be deleted by garbage-collector
self.panel.config(image=imgtk) # show the image
#self.root.attributes("-fullscreen",True)
self.root.after(1, self.video_loop) # call the same function after 30 milliseconds
def take_snapshot(self):
""" Take snapshot and ...
I suppose
PIL.Image.ANTIALIAS
is a very time consuming method. The methodPIL.Image.NEAREST
should be enough for downscaling in my opinion. You can also try with OpenCV to resize instead of PIL.Hi Eduardo, using
self.current_image= self.current_image.resize([1280,1024],PIL.Image.NEAREST)
inside the video_loop function still slows down FPS greatly. I've tried to make openCV do the resize withframe = cv2.resize(frame, (1280,1024))
just belowok, frame = self.vs.read()
in the loop, still FPS slowed down. I would greatly appreciate if anyone can run this code on some test avi/mp4 file and see if there is any way to go full screen with proper FPS. I could in theory just run the openCV window without any Tkinter GUI and get good speed, but i must have the mouse cursor options Tkinter gives me, the stock openCV window crosshair cursor is too small and there is no way to modify it without using GUI.Try to decrease the time to wait an input keyboard:
key = cv2.waitKey(5)
for instance.