I am having problem that how to display a video preview window inside the tkinter window. Below code will play video but i want to show that video in the tkinter window..
Python Code:
from moviepy.editor import *
from moviepy.video.fx.resize import resize
import pygame
pygame.display.set_caption('Kumawat!')
clip=VideoFileClip('mk.mp4')
w=1300
h=700
display=(w,h)
clip.resize(display).preview()
pygame.quit()
After some researching it does not seem you can embed the clip easily into a tkinter frame. The solution I came up with is:
use imageio to download the video
extract each video frame using an iterator into an image
convert the image to a ImageTk
add this image to a tkinter label
In below example I have added two control buttons to start and stop the video as well as an waiting loop to run the video at real time assuming 24 frames per second. I have not investigated how to include sound.
import time
import tkinter as tk
import imageio
from PIL import Image, ImageTk
global pause_video
# download video at: http://www.html5videoplayer.net/videos/toystory.mp4
video_name = "toystory.mp4"
video = imageio.get_reader(video_name)
def video_frame_generator():
def current_time():
return time.time()
start_time = current_time()
_time = 0
for frame, image in enumerate(video.iter_data()):
# turn video array into an image and reduce the size
image = Image.fromarray(image)
image.thumbnail((750, 750), Image.ANTIALIAS)
# make image in a tk Image and put in the label
image = ImageTk.PhotoImage(image)
# introduce a wait loop so movie is real time -- asuming frame rate is 24 fps
# if there is no wait check if time needs to be reset in the event the video was paused
_time += 1 / 24
run_time = current_time() - start_time
while run_time < _time:
run_time = current_time() - start_time
else:
if run_time - _time > 0.1:
start_time = current_time()
_time = 0
yield frame, image
def _stop():
global pause_video
pause_video = True
def _start():
global pause_video
pause_video = False
if __name__ == "__main__":
root = tk.Tk()
root.title('Video in tkinter')
my_label = tk.Label(root)
my_label.pack()
tk.Button(root, text='start', command=_start).pack(side=tk.LEFT)
tk.Button(root, text='stop', command=_stop).pack(side=tk.LEFT)
pause_video = False
movie_frame = video_frame_generator()
while True:
if not pause_video:
frame_number, frame = next(movie_frame)
my_label.config(image=frame)
root.update()
root.mainloop()
Related
I am working on an app that basically turns the raspberry pi 4 into a camera, since I've been learning opencv i thought it would be a cool way to show off everything that I've done so far,
I do manage to retrieve the feed of the raspicam, but it's on the top layer so it covers up everything, including my cursor and i can't even stop the app.
I retrieve the image with this code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# camera_pi.py
#
#
#
import time
import io
import threading
import picamera
class Camera(object):
thread = None # background thread that reads frames from camera
frame = None # current frame is stored here by background thread
last_access = 0 # time of last client access to the camera
def initialize(self):
if Camera.thread is None:
# start background frame thread
Camera.thread = threading.Thread(target=self._thread)
Camera.thread.start()
# wait until frames start to be available
while self.frame is None:
time.sleep(0)
def get_frame(self):
Camera.last_access = time.time()
self.initialize()
return self.frame
#classmethod
def _thread(cls):
with picamera.PiCamera() as camera:
# camera setup
camera.resolution = (1920, 1080)
camera.hflip = True
camera.vflip = True
#camera.zoom = (0.22,0,0.7,0.7) # (x, y, w, h)
# let camera warm up
camera.start_preview()
time.sleep(2)
stream = io.BytesIO()
for foo in camera.capture_continuous(stream, 'jpeg',
use_video_port=True):
# store frame
stream.seek(0)
cls.frame = stream.read()
# reset stream for next frame
stream.seek(0)
stream.truncate()
# if there hasn't been any clients asking for frames in
# the last 10 seconds stop the thread
#if time.time() - cls.last_access > 10:
#break
cls.thread = None
And then make it into a full screen Tkinter widget with this code:
import cv2
from camera_pi import *
import sys, os
if sys.version_info[0] == 2: # the tkinter library changed it's name from Python 2 to 3.
import Tkinter
tkinter = Tkinter #I decided to use a library reference to avoid potential naming conflicts with people's programs.
else:
import tkinter
from PIL import Image, ImageTk
import time
camera = Camera()
feed = camera.get_frame()
frame = cv2.imread(feed)
#cv2.imshow(frame)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
root = tkinter.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
SetButton = Button(root,text="Settings", command=root.destroy)
SetButton.place(x=0,y=0)
def showPIL(pilImage):
imgWidth, imgHeight = pilImage.size
# resize photo to full screen
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(w/2,h/2,image=image)
imagesprite.lower()
root.update_idletasks()
root.update()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
try:
showPIL(frame)
except KeyboardInterrupt:
root.destroy
I'd like to add a button on the corner to open up a settings window where i could modify the camera parameters, or start one of the opencv modes ive been working on but being that i can't see the cursor that doesn't work, i also tried to use the canvas function to lower, and tried moving it around in the code but i think its because the image keeps refreshing, or i simply did it wrong.
i am using Python and I inserted a gif in my project. The issue is when i start the application the gif in the application runs in different way than orginal gif. I think that the frames in the gif are run in different speed. How to set the original gif?
I imported PIL and tkinter. This is the code:
import threading
from tkinter import *
from PIL import Image, ImageTk, ImageSequence
def play_gif():
global img
img = Image.open("Gifs/beaming_face_with_smiling_eyes.gif")
lbl = Label(root)
lbl.place(x = 0, y = 0)
for img in ImageSequence.Iterator(img):
img = ImageTk.PhotoImage(img)
lbl.config(image = img)
root.update()
def exit():
root.destroy()
threading.Timer(3.0, play_gif).start()
Button(root,text = "exit", command=exit).place(x = 450, y = 300)
root.mainloop()
How to add a cv2 trackbar to a Tkinter window?
I have 2 snippets of code that my teammates have made, but it is difficult to integrate them in the same window.
I am able to use them in separate windows but I want to use them in the same window.
CODE FOR THE VIDEO PLAYING IN TKINTER:
import cv2
import tkinter as tk
from tkinter import *
# from tkinter import ttk
# from ttk import Frame
# import ImageTk
white = "#ffffff"
lightBlue2 = "#adc5ed"
font = "Constantia"
fontButtons = (font, 12)
maxWidth = 800
maxHeight = 480
#Graphics window
mainWindow = tk.Tk()
mainWindow.configure(bg=lightBlue2)
mainWindow.geometry('%dx%d+%d+%d' % (maxWidth,maxHeight,0,0))
mainWindow.resizable(0,0)
# mainWindow.overrideredirect(1)
mainFrame = Frame(mainWindow)
mainFrame.place(x=20, y=20)
#Capture video frames
lmain = tk.Label(mainFrame)
lmain.grid(row=0, column=0)
cap = cv2.VideoCapture('test.mp4')
def show_frame():
ret, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image).resize((760, 400))
imgtk = ImageTk.PhotoImage(image = img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, show_frame)
closeButton = Button(mainWindow, text = "CLOSE", font = fontButtons, bg = white, width = 20, height= 1)
closeButton.configure(command= lambda: mainWindow.destroy())
closeButton.place(x=270,y=430)
show_frame() #Display
mainWindow.mainloop() #Starts GUI
And I have a second snippet of code that uses cv2 to display the track bar and changes the position of the video.
import cv2
CURRENT_FRAME_FLAG = cv2.CAP_PROP_POS_FRAMES
TOTAL_FRAMES_FLAG = cv2.CAP_PROP_FRAME_COUNT
WIN_NAME = "Frame Grabber"
POS_TRACKBAR = "pos_trackbar"
cap = cv2.VideoCapture('C:/Users/ayush/Desktop/test.mp4')
ret, frame = cap.read()
def dummy():
pass
def save_image():
filename = "image_%0.5f.png" % t.time()
cv2.imwrite(filename, frame)
def seek_callback(x):
global frame
i = cv2.getTrackbarPos(POS_TRACKBAR, WIN_NAME)
cap.set(CURRENT_FRAME_FLAG, i-1)
_, frame = cap.read()
cv2.imshow(WIN_NAME, frame)
def mouse_callback(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
save_image()
def skip_frame_generator(df):
def skip_frame():
global frame
cf = cap.get(CURRENT_FRAME_FLAG) - 1
cap.set(CURRENT_FRAME_FLAG, cf+df)
cv2.setTrackbarPos(POS_TRACKBAR, WIN_NAME, int(cap.get(CURRENT_FRAME_FLAG)))
_, frame = cap.read()
return skip_frame
cv2.namedWindow(WIN_NAME)
cv2.createTrackbar(POS_TRACKBAR, WIN_NAME, 0, int(cap.get(TOTAL_FRAMES_FLAG)), seek_callback)
cv2.setMouseCallback(WIN_NAME, mouse_callback)
actions = dict()
actions[ord("D")] = skip_frame_generator(10)
actions[ord("d")] = skip_frame_generator(1)
actions[ord("a")] = skip_frame_generator(-1)
actions[ord("A")] = skip_frame_generator(-10)
actions[ord("q")] = lambda: exit(0)
actions[ord("s")] = save_image
while True:
cv2.imshow(WIN_NAME, frame)
key = cv2.waitKey(0) & 0xFF
actions.get(key, dummy)()
I have to integrate the cv2 trackbar into the Tkinter window.
I am able to integrate but as I don't know how to use implement CV2 trackbar in tkinter, I am not able to do anything.
Please Help.
Try using tkinter Scale widgets instead of cv2 trackbars. They are slightly different but they should be fairly easy to swap out and work about the same. Then you can easily add them in your tkinter window/frame.
So I'm trying to make a little battle scene using Tkinter, the code is supposed to change the image, wait a couple of seconds, then exit the Tkinter window. The code I have just makes a little pause when the button to change images is pressed. I'm still a beginner and some concepts are hard for me to grasp.
Here is the code:
from tkinter import *
import time
class MainWindow():
def __init__(self, main):
# canvas for image
self.canvas = Canvas(main, width=660, height=440)
self.canvas.grid(row=0, column=0)
# images
self.my_images = []
self.my_images.append(PhotoImage(file = "att1.gif"))
self.my_images.append(PhotoImage(file = "att2.gif"))
self.my_image_number = 0
# set first image on canvas
self.image_on_canvas = self.canvas.create_image(0, 0, anchor = NW, image = self.my_images[self.my_image_number])
# button to change image
self.button = Button(main, text="FIGHT", command=self.onButton)
self.button.grid(row=1, column=0)
#----------------
def onButton(self):
# next image
self.my_image_number = 1
if self.my_image_number == 1:
time.sleep(2)
root.quit()
# change image
self.canvas.itemconfig(self.image_on_canvas, image = self.my_images[self.my_image_number])
root = Tk()
MainWindow(root)
root.mainloop()
some of this code is borrowed, I tried to alter it to fit my purpose
The image is not changed because time.sleep(2) blocks tkinter update. After the sleep, tkinter quit and so the image is not updated.
Since you have only 2 images and you want to exit the tkinter window 2 seconds after the change of image, try:
def onButton(self):
self.canvas.itemconfig(self.image_on_canvas, image=self.my_images[1])
root.after(2000, root.destroy) # close root window after 2 seconds
This question already has answers here:
Play an Animated GIF in python with tkinter
(3 answers)
Closed 5 years ago.
I've been trying to play an animated gif using Tkinter.PhotoImage, but haven't been seeing any success. It displays the image, but not the animation. The following is my code:
root = Tkinter.Tk()
photo = Tkinter.PhotoImage(file = "path/to/image.gif")
label = Tkinter.Label(image = photo)
label.pack()
root.mainloop()
It displays the image in a window, and that's it. I'm thinking that the issue has something to do with Tkinter.Label but I'm not sure. I've looked for solutions but they all tell me to use PIL (Python Imaging Library), and it's something that I don't want to use.
With the answer, I created some more code (which still doesn't work...), here it is:
from Tkinter import *
def run_animation():
while True:
try:
global photo
global frame
global label
photo = PhotoImage(
file = photo_path,
format = "gif - {}".format(frame)
)
label.configure(image = nextframe)
frame = frame + 1
except Exception:
frame = 1
break
root = Tk()
photo_path = "/users/zinedine/downloads/091.gif"
photo = PhotoImage(
file = photo_path,
)
label = Label(
image = photo
)
animate = Button(
root,
text = "animate",
command = run_animation
)
label.pack()
animate.pack()
root.mainloop()
Thanks for everything! :)
You have to drive the animation yourself in Tk. An animated gif consists of a number of frames in a single file. Tk loads the first frame but you can specify different frames by passing an index parameter when creating the image. For example:
frame2 = PhotoImage(file=imagefilename, format="gif -index 2")
If you load up all the frames into separate PhotoImages and then use timer events to switch the frame being shown (label.configure(image=nextframe)). The delay on the timer lets you control the animation speed. There is nothing provided to give you the number of frames in the image other than it failing to create a frame once you exceed the frame count.
See the photo Tk manual page for the official word.
Here's a simpler example without creating an object:
from tkinter import *
import time
import os
root = Tk()
frameCnt = 12
frames = [PhotoImage(file='mygif.gif',format = 'gif -index %i' %(i)) for i in range(frameCnt)]
def update(ind):
frame = frames[ind]
ind += 1
if ind == frameCnt:
ind = 0
label.configure(image=frame)
root.after(100, update, ind)
label = Label(root)
label.pack()
root.after(0, update, 0)
root.mainloop()