hi i am just trying to keep video frame using webcam in python GUI using tkinter module
how can i move video to down or to some other place in GUI and how to decrease the video show screen size
i am trying to change lmain = tk.Label(master=window) in main function to
lmain = tk.Label(master=window).place(x=500,y=500)
if i do that i am getting the following error
[ WARN:0] global C:\projects\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (674)
SourceReaderCB::~SourceReaderCB terminating async callback
#This Python program is developed in order to open an internal camera and display the image within Tkinter window.
#importing modules required
from ttk import *
import tkinter as tk
from tkinter import *
import cv2
from PIL import Image, ImageTk
import os
import numpy as np
global last_frame #creating global variable
last_frame = np.zeros((480, 640, 3), dtype=np.uint8)
global cap
cap = cv2.VideoCapture(0)
def show_vid(): #creating a function
if not cap.isOpened(): #checks for the opening of camera
print("cant open the camera")
flag, frame = cap.read()
frame = cv2.flip(frame, 1)
if flag is None:
print("Major error!")
elif flag:
global last_frame
last_frame = frame.copy()
pic = cv2.cvtColor(last_frame, cv2.COLOR_BGR2RGB) #we can change the display color of the frame gray,black&white here
img = Image.fromarray(pic)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, show_vid)
if __name__ == '__main__':
window=tk.Tk() #assigning window variable for Tkinter as tk
lmain = tk.Label(master=window)
lmain.grid(column=0, rowspan=4, padx=5, pady=5)
window.title("Sign Language Processor") #you can give any title
window.geometry("1366x768")
show_vid()
window.mainloop() #keeps the application in an infinite loop so it works continuosly
cap.release()
Related
I'm pretty new to python and espcially tkinter and opencv.
I've got someway (a little way) to creating a gui that will eventually control a microscope and ai. But I've hit a stumbling block, trying to record the video that is displayed within the gui, I think its to do with the video feed already been captured in the display, but I can't find a way around it. It all works fine until I hit record then it crashes and i get the error: open VIDEOIO(V4L2:/dev/video0): can't open camera by index.
Apologies for the long code but I've cut it down to as much as I think possible.
The problem is in the root.recbtn and def rec sections.
import cv2
import tkinter as tk
import multiprocessing
from tkinter import *
from PIL import Image,ImageTk
from datetime import datetime
from tkinter import messagebox, filedialog
e = multiprocessing.Event()
p = None
# Defining CreateWidgets() function to create necessary tkinter widgets
def createwidgets():
root.cameraLabel = Label(root, bg="gray25", borderwidth=3, relief="ridge")
root.cameraLabel.grid(row=2, column=1, padx=10, pady=10, columnspan=3)
root.browseButton = Button(root, bg="gray25", width=10, text="BROWSE", command=destBrowse)
root.browseButton.grid(row=1, column=1, padx=10, pady=10)
root.recbtn = Button(root, bg="gray25", width=10, text="Record", command=rec)
root.recbtn.grid(row=1, column=5, padx=10, pady=10)
root.saveLocationEntry = Entry(root, width=55, textvariable=destPath)
root.saveLocationEntry.grid(row=1, column=2, padx=10, pady=10)
# Calling ShowFeed() function
ShowFeed()
# Defining ShowFeed() function to display webcam feed in the cameraLabel;
def ShowFeed():
# t5 # Capturing frame by frame
ret, frame = root.cap.read()
if ret:
# Flipping the frame vertically
frame = cv2.flip(frame, 1)
# Changing the frame color from BGR to RGB
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
# Creating an image memory from the above frame exporting array interface
videoImg = Image.fromarray(cv2image)
# Creating object of PhotoImage() class to display the frame
imgtk = ImageTk.PhotoImage(image = videoImg)
# Configuring the label to display the frame
root.cameraLabel.configure(image=imgtk)
# Keeping a reference
root.cameraLabel.imgtk = imgtk
# Calling the function after 10 milliseconds
root.cameraLabel.after(10, ShowFeed)
else:
# Configuring the label to display the frame
root.cameraLabel.configure(image='')
def destBrowse():
# Presenting user with a pop-up for directory selection. initialdir argument is optional
# Retrieving the user-input destination directory and storing it in destinationDirectory
# Setting the initialdir argument is optional. SET IT TO YOUR DIRECTORY PATH
destDirectory = filedialog.askdirectory(initialdir="YOUR DIRECTORY PATH")
# Displaying the directory in the directory textbox
destPath.set(destDirectory)
def rec():
vid_name = datetime.now().strftime('%d-%m-%Y %H-%M-%S')
# If the user has selected the destination directory, then get the directory and save it in image_path
if destPath.get() != '':
vid_path = destPath.get()
# If the user has not selected any destination directory, then set the image_path to default directory
else:
messagebox.showerror("ERROR", "No Directory Selected!")
# Concatenating the image_path with image_name and with .jpg extension and saving it in imgName variable
vidName = vid_path + '/' + vid_name + ".avi"
capture = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
videoWriter = cv2.VideoWriter(vidName, fourcc, 30.0, (640, 480))
while (True):
ret, frame = capture.read()
if ret:
cv2.imshow('video', frame)
videoWriter.write(frame)
if cv2.waitKey(1) == 27:
break
capture.release()
videoWriter.release()
# Creating object of tk class
root = tk.Tk()
# Creating object of class VideoCapture with webcam index
root.cap = cv2.VideoCapture(0)
# Setting width and height
width, height = 1200, 1200
root.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
root.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
# Setting the title, window size, background color and disabling the resizing property
root.title("Test-AI-tes")
root.geometry("1600x1024")
root.resizable(True, True)
root.configure(background = "gray18")
# Creating tkinter variables
destPath = StringVar()
imagePath = StringVar()
createwidgets()
root.mainloop()
Thanks!
This answer is similar to #Art's answer but I removed the after_id and queue.
import cv2
import threading
import tkinter as tk
from PIL import Image, ImageTk
def stop_rec():
global running
running = False
start_button.config(state="normal")
stop_button.config(state="disabled")
def start_capture():
global capture, last_frame
capture = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc("X", "V", "I", "D")
video_writer = cv2.VideoWriter(r"sample.avi", fourcc, 30.0, (640, 480))
while running:
rect, frame = capture.read()
if rect:
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
last_frame = Image.fromarray(cv2image)
video_writer.write(frame)
capture.release()
video_writer.release()
def update_frame():
if last_frame is not None:
tk_img = ImageTk.PhotoImage(master=video_label, image=last_frame)
video_label.config(image=tk_img)
video_label.tk_img = tk_img
if running:
root.after(10, update_frame)
def start_rec():
global running
running = True
thread = threading.Thread(target=start_capture, daemon=True)
thread.start()
update_frame()
start_button.config(state="disabled")
stop_button.config(state="normal")
def closeWindow():
stop_rec()
root.destroy()
running = False
after_id = None
last_frame = None
root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", closeWindow)
video_label = tk.Label()
video_label.pack(expand=True, fill="both")
start_button = tk.Button(text="Start", command=start_rec)
start_button.pack()
stop_button = tk.Button(text="Stop", command=stop_rec, state="disabled")
stop_button.pack()
root.mainloop()
It uses the boolean flag running instead of using after_id. Also instead of storing the images in a queue then showing it, I only keep the last image. That way it can run in real time on my computer. Don't worry all of the frames are still being stored in the video file.
You cannot have infinite while loop along with the GUI's loop. You should instead make use of threading, whenever you have an IO operation to complete.
Example code:
import cv2
import threading
import tkinter as tk
from PIL import Image, ImageTk
from queue import Queue
def stop_rec():
global running, after_id
running = False
if after_id:
root.after_cancel(after_id)
after_id = None
with frame_queue.mutex:
frame_queue.queue.clear()
def start_capture():
global capture
capture = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
video_writer = cv2.VideoWriter(r"sample.avi", fourcc, 30.0, (640, 480))
while running:
rect, frame = capture.read()
if rect:
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
videoImg = Image.fromarray(cv2image)
# current_frame = ImageTk.PhotoImage(image = videoImg)
frame_queue.put(videoImg)
video_writer.write(frame)
capture.release()
video_writer.release()
def update_frame():
global after_id
if not frame_queue.empty():
video_label.image_frame = ImageTk.PhotoImage(frame_queue.get_nowait())
video_label.config(image=video_label.image_frame)
after_id = root.after(10, update_frame)
def start_rec():
global running
stop_rec()
running = True
thread = threading.Thread(target=start_capture, daemon=True)
thread.start()
update_frame()
def closeWindow():
stop_rec()
root.destroy()
running = False
after_id = None
frame_queue = Queue()
root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", closeWindow)
video_label = tk.Label()
video_label.pack(expand=True, fill="both")
tk.Button(text="Start", command=start_rec).pack()
tk.Button(text="stop", command=stop_rec).pack()
root.mainloop()
Quick explanation:
start the record function in a new thread.
Use Queue to store the frames.
Then make use of [widget].after to update the label at regular intervals.
To stop the recording make use of [widget].after_cancel(after_id)(after_id is returned when you use .after method) and set the running variable to False to stop the loop.
I designed a window with tkinter and wanted to show a video stream there, and I also wanted to be able to pause the video with the "p" key. I created a function which puts a picture captured with a webcam into a label on the window. Then I put the function into the while loop to call it repeatedly and make a continuous video in the window. And I used waitKey() functions in the loop to read the key presses. The waitKey() also sets the frame rate or speed of the video. I managed to get the video running but the program does not react to key presses. On the other hand, I can change the frame rate when I change the argument of the waitKey(), so the function seems to work but it doesn't read the key presses and nothing happens when a key is pressed. There are also no error messages. I would be thankful if somebody would show me how to use the waitKey() in this loop so that I could control the video stream with key presses, or suggest a different way to do it. This is my code, most of it is designing the window but the loop with waitKey() functions is at the end:
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *
from PIL import ImageTk, Image
from cv2 import cv2
mainwin = Tk() #create main window
appWinWidth = int(0.6 * mainwin.winfo_screenwidth()) #set main window size (depending on the screen)
appWinHeight = int(0.5 * mainwin.winfo_screenheight())
screen_width = mainwin.winfo_screenwidth() #get screen dimensions
screen_height = mainwin.winfo_screenheight()
appWinX = int((screen_width - appWinWidth)/2) #set coordinates of the main window so that it
appWinY = int((screen_height - appWinHeight)/2) #would be located in the middle of the screen
#create and place the frames
frame1 = tk.Frame(mainwin, background = "white", width = int(appWinWidth/2), height = appWinHeight)
frame2 = tk.Frame(mainwin, background = "black", width = int(appWinWidth/2), height = appWinHeight)
frame1.grid(row = 0, column = 0, sticky = "nsew")
frame2.grid(row = 0, column = 1, sticky = "nsew")
mainwin.grid_columnconfigure(0, weight = 1)
mainwin.grid_columnconfigure(1, weight = 1)
mainwin.grid_rowconfigure(0, weight = 1)
#set the geometry of the main window
mainwin.geometry("{}x{}+{}+{}".format(appWinWidth, appWinHeight, appWinX, appWinY))
mainwin.resizable(width = 0, height = 0)
#create labels in frames
frame2.grid_propagate(0) #labels and other widgets in frame don't change the size of the frame
frame2.grid()
labelF2 = Label(frame2)
labelF2.grid()
labelF2.place(relx=0.5, rely=0.5, anchor="center")
frame1.grid_propagate(0)
labelF1 = Label(frame1, background = "white")
labelF1.grid()
mainwin.update()
#get camera feed and frame size
cap = cv2.VideoCapture(0)
capFrameWidth = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
capFrameHeight = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
widthRelation = capFrameWidth/frame2.winfo_width()
heigthRelation = capFrameHeight/frame2.winfo_height()
#define the size of the video frame so that the video would fit into the frame of the main window
if widthRelation > 1 and widthRelation > heigthRelation:
fittedSize = (int(capFrameWidth/widthRelation), int(capFrameHeight/widthRelation))
elif heigthRelation > 1 and heigthRelation > widthRelation:
fittedSize = (int(capFrameWidth/heigthRelation), int(capFrameHeight/heigthRelation))
else:
fittedSize = (capFrameWidth, capFrameHeight)
#funtion for getting a video frame, resizing it for the main window and placing it into the frame 2
def video_to_mainwin():
chk, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
imgV = cv2.resize(cv2image, fittedSize)
img = Image.fromarray(imgV)
imgtk = ImageTk.PhotoImage(image=img)
labelF2.imgtk = imgtk
labelF2.configure(image=imgtk)
#run the video function continuously to create a stream, and be ready to react to key presses
while True:
key = cv2.waitKey(1)
if key == ord('p'): #if 'p' is pressed, pause the stream and write 'Paused' to frame 1 on the main window
video_to_mainwin()
labelF1.config(text = 'Paused')
mainwin.update()
key2 = cv2.waitKey(0) #remain paused until 'c' is pressed
if key2 == ord('c'):
labelF1.config(text = '')
else: #if no key is pressed, then just show the video stream
video_to_mainwin()
mainwin.update()
If you display cv2 image in tkinter then you don't need cv2.waitKey().
You can use tkinter for this
mainwin.bind("p", function_name)
to run function_name() when you press p.
And when you use bind() then you don't need while True to check pressed key because tkinter mainloop will do it for you.
You need only root.after(milliseconds, function_name) to run function which will update image in window every few milliseconds.
Working code
#from tkinter import * # PEP8: `import *` is not preferred
#from tkinter.ttk import * # PEP8: `import *` is not preferred
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk, Image
from cv2 import cv2
# --- constants --- (PEP8: UPPER_CASE_NAMES)
#FPS = 25
# --- classes --- (PEP8: CamelCaseNames)
# ... empty ...
# --- functions --- (PEP8: lower_case_names)
def video_to_mainwin():
"""Getting a video frame, resizing it for the main window and placing it into the frame 2."""
if not paused:
chk, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
imgV = cv2.resize(cv2image, fitted_size)
img = Image.fromarray(imgV)
imgtk = ImageTk.PhotoImage(image=img)
labelF2.imgtk = imgtk
labelF2.configure(image=imgtk)
# run it again after `1000/FPS` milliseconds
#mainwin.after(int(1000/FPS), video_to_mainwin)
mainwin.after(int(1000/cap_fps), video_to_mainwin)
def set_pause(event):
global paused
paused = True
labelF1.config(text = 'Paused')
def unset_pause(event):
global paused
paused = False
labelF1.config(text = '')
# --- main ---- (PEP8: lower_case_names)
paused = False # default value at start
# - cap -
cap = cv2.VideoCapture(0)
cap_frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
cap_frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
cap_fps = int(cap.get(cv2.CAP_PROP_FPS))
# - tk -
mainwin = tk.Tk() # create main window
app_win_width = int(0.6 * mainwin.winfo_screenwidth()) # set main window size (depending on the screen)
app_win_height = int(0.5 * mainwin.winfo_screenheight())
screen_width = mainwin.winfo_screenwidth() # get screen dimensions
screen_height = mainwin.winfo_screenheight()
app_win_x = int((screen_width - app_win_width)/2) # set coordinates of the main window so that it
app_win_y = int((screen_height - app_win_height)/2) # would be located in the middle of the screen
#create and place the frames
frame1 = tk.Frame(mainwin, background="white", width=int(app_win_width/2), height=app_win_height)
frame2 = tk.Frame(mainwin, background="black", width=int(app_win_width/2), height=app_win_height)
frame1.grid(row=0, column=0, sticky="nsew") # PEP8: without spaces around `=`
frame2.grid(row=0, column=1, sticky="nsew") # PEP8: without spaces around `=`
mainwin.grid_columnconfigure(0, weight=1) # PEP8: without spaces around `=`
mainwin.grid_columnconfigure(1, weight=1) # PEP8: without spaces around `=`
mainwin.grid_rowconfigure(0, weight=1)
#set the geometry of the main window
mainwin.geometry("{}x{}+{}+{}".format(app_win_width, app_win_height, app_win_x, app_win_y))
mainwin.resizable(width=0, height=0)
# create labels in frames
frame2.grid_propagate(0) # labels and other widgets in frame don't change the size of the frame
frame2.grid()
labelF2 = tk.Label(frame2)
labelF2.place(relx=0.5, rely=0.5, anchor="center")
frame1.grid_propagate(0)
labelF1 = tk.Label(frame1, background = "white")
labelF1.grid()
mainwin.update() # to create window and correctly calculate sizes
# get camera feed and frame size
width_relation = cap_frame_width/frame2.winfo_width()
heigth_relation = cap_frame_height/frame2.winfo_height()
# define the size of the video frame so that the video would fit into the frame of the main window
if width_relation > 1 and width_relation > heigth_relation:
fitted_size = (int(cap_frame_width/width_relation), int(cap_frame_height/width_relation))
elif heigth_relation > 1 and heigth_relation > width_relation:
fitted_size = (int(cap_frame_width/heigth_relation), int(cap_frame_height/heigth_relation))
else:
fitted_size = (cap_frame_width, cap_frame_height)
# assing functions to buttons
mainwin.bind("p", set_pause)
mainwin.bind("c", unset_pause)
# star video
video_to_mainwin()
# start tkinter mainloop (event loop)
mainwin.mainloop()
# - end -
cap.release()
PEP 8 -- Style Guide for Python Code
I have few examples with cv2 and tkinter on Github.
For example: python-cv2-streams-viewer uses cv2 in separted thread to read from webcam or file (even from file on internet). It also uses tk.Frame to create widget which display stream from cv2. It uses this widget many times to display many streams at the same time.
Other examples in python-examples - cv2 or tkinter
I am trying to build a GUI using tkinter in python 3.6.4 64-bit on Windows 8 by integrating opencv components into the program. I can get the video to play, but there is significant flicker going on. Namely, a screen the same color as the native tkinter background shows up briefly several times a second. I've tested several cameras with similar results, and double-checked that the cameras work properly via native video playback software. Here is my code:
from tkinter import *
from PIL import Image, ImageTk
import cv2
import threading
cap = cv2.VideoCapture(0)
root = Tk()
def videoLoop():
global root
global cap
vidLabel = None
while True:
ret, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = Image.fromarray(frame)
frame = ImageTk.PhotoImage(frame)
if vidLabel: vidLabel.configure(image=frame)
else:
vidLabel = Label(root, image=frame, anchor=NW)
vidLabel.pack(expand=YES, fill=BOTH)
videoThread = threading.Thread(target=videoLoop, args=())
videoThread.start()
root.mainloop()
Could anyone suggest what I might be doing wrong? I did hear that tkinter doesn't always play well with threads, but that's about all I can think of. In response to a comment suggesting the flicker is caused by label updating, I added some code that still reads from video and updates the label within the loop, but uses an image loaded outside of the loop to update the label. The flicker then goes away, although (to my understanding) the efficiency of the loop and updating of the label hasn't changed. Here is the changed videoLoop function (with flicker gone):
def videoLoop():
global root
vidLabel = None
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = Image.fromarray(frame)
frame = ImageTk.PhotoImage(frame)
while True:
ret, lame = cap.read()
lame = cv2.cvtColor(lame, cv2.COLOR_BGR2RGB)
lame = Image.fromarray(lame)
lame = ImageTk.PhotoImage(lame)
if vidLabel:
vidLabel.configure(image=None)
vidLabel.configure(image=frame)
else:
vidLabel = Label(root, image=frame, anchor=NW)
vidLabel.pack(expand=YES, fill=BOTH)
Solution: Make sure the image configure call precedes storing the image in the label image attribute.
I've managed to solve this issue, however I don't fully understand WHY it works as I am a python/tkinter novice. I will post the solution for now and will update the answer when I manage to find a proper explanation to this behavior. My best guess is that the storing of the image in the label attribute is what actually causes it to update on the screen, while the configure method just declares that there will be an image attached, which causes the loop to have to go through another iteration before getting to the update image update statement. The below code works fine without flicker:
from tkinter import *
from PIL import Image, ImageTk
import cv2
import threading
cap = cv2.VideoCapture(0)
root = Tk()
def videoLoop():
global root
global cap
vidLabel = Label(root, anchor=NW)
vidLabel.pack(expand=YES, fill=BOTH)
while True:
ret, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = Image.fromarray(frame)
frame = ImageTk.PhotoImage(frame)
vidLabel.configure(image=frame)
vidLabel.image = frame
videoThread = threading.Thread(target=videoLoop, args=())
videoThread.start()
root.mainloop()
In tkinter in order to display images, the image needs to have a global reference reference that doesn't go out of scope and then gets garbage-collected, perhaps flickering is caused by lack of such reference. See below code that has such reference to the image, and also ditched the if/else with better structuring:
from tkinter import *
from PIL import Image, ImageTk
import cv2
import threading
cap = cv2.VideoCapture(0)
root = Tk()
def videoLoop():
global root
global cap
vidLabel = Label(root, anchor=NW)
vidLabel.pack(expand=YES, fill=BOTH)
while True:
ret, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = Image.fromarray(frame)
vidLabel.image = ImageTk.PhotoImage(frame)
vidLabel.configure(image=vidLabel.image)
videoThread = threading.Thread(target=videoLoop, args=())
videoThread.start()
root.mainloop()
I am trying to show video frames (not from a stream) with tkinter. The next step are buttons which allow the user to get a frame backward or forward in the video. I have to say that I am quite new in programming with python.
So first I read the following articles:
Python snippets: Converting video to images http://srand.fr/blog/python%20import%20video.html
The Tkinter PhotoImage Class: http://effbot.org/tkinterbook/photoimage.htm
The problem is that I can’t use the image converted with imageio or VideoFileClip to show it with tkinter photoimage. I get the following error:
_tkinter.TclError: image "[[ …(some numbers)… ]]" doesn't exist
Here is my simple code. I hope you can help me :)
from moviepy.editor import VideoFileClip
from tkinter import *
import pylab
vid =VideoFileClip("example.mp4")
window = Tk()
window.title("Choose Frame")
window.geometry ("900x600")
count =20
photo = vid.get_frame(count)
label =Label(window, image = photo)
label.pack()
Other Code, same problem:
import imageio
from tkinter import *
import pylab
filename = './example.mp4'
vid = imageio.get_reader(filename, 'ffmpeg')
window = Tk()
window.title("Choose Frame")
window.geometry ("900x600")
count =20
photo = vid.get_data(count)
label =Label(window, image = photo)
label.pack()
This is a bit late but better late than never.
Here is a working example I found and modify a little, this works with '.mp4', videos but not with '.flv', don't know why.
Note:
python 2.7 import Tkinter
python 3 import tkinter
import Tkinter as tk
import threading
import imageio
from PIL import Image, ImageTk
video_name = "test_video.mp4" #This is your video file path
video = imageio.get_reader(video_name)
def stream(label):
frame = 0
for image in video.iter_data():
frame += 1 #counter to save new frame number
image_frame = Image.fromarray(image)
image_frame.save('FRAMES/frame_%d.png' % frame) #if you need the frame you can save each frame to hd
frame_image = ImageTk.PhotoImage(image_frame)
label.config(image=frame_image)
label.image = frame_image
if frame == 40: break #after 40 frames stop, or remove this line for the entire video
if __name__ == "__main__":
root = tk.Tk()
my_label = tk.Label(root)
my_label.pack()
thread = threading.Thread(target=stream, args=(my_label,))
thread.daemon = 1
thread.start()
root.mainloop()
And here is another nice working example of a player that I was trying to make with Tkinter and some sample code with Opencv module.
This is a just an example idea, not finish code by any means.
import cv2
from Tkinter import *
from PIL import Image, ImageTk
import io
import threading
import os, sys
def resize(image):
im = image
new_siz = siz
im.thumbnail(new_siz, Image.ANTIALIAS)
return im
def size(event):
global siz
if siz == screenWH:
siz = (200, 200)
else:
siz = screenWH
win.state('zoomed')
print 'size is: ', siz
def view_frame_video():
vc = cv2.VideoCapture('test_video.flv')
if vc.isOpened():
rval , frame = vc.read()
else:
rval = False
while rval:
rval, frame = vc.read()
img =Image.fromarray(frame)
img = resize(img)
imgtk = ImageTk.PhotoImage(img)
lbl.config(image=imgtk)
lbl.img = imgtk
if stop == True:
vc.release()
break #stop the loop thus stops updating the label and reading imagge frames
cv2.waitKey(1)
vc.release()
def stop_():
global stop
stop = True
def play():
stop = False
t = threading.Thread(target=view_frame_video)
t.start()
win = Tk()
stop = None
screenWH = (win.winfo_screenwidth(), win.winfo_screenheight())
siz = (200, 200)
Label(text='Press Play Button').pack()
frm_ = Frame(bg='black')
frm_.pack()
lbl = Label(frm_, bg='black')
lbl.pack(expand=True)
lbl.bind('<Double-Button-1>', size)
frm = Frame()
frm.pack()
Button(text='Play', command = play).pack(side=LEFT)
Button(text='Stop', command = stop_).pack(side=LEFT)
win.mainloop()
I'm trying to create a GUI that opens a video and an image below it:
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
import Image, ImageTk
import Tkinter, tkMessageBox
import ttk
import cv2
import sys
width, height = 800, 600
banner = cv2.imread('../data/banner.png')
b,g,r = cv2.split(banner)
banner = cv2.merge((r,g,b))
im = Image.fromarray(banner)
cap = cv2.VideoCapture('../data/sample.mov')
root = Tkinter.Tk()
root.bind('<Escape>', lambda e: root.quit())
root.title("Contador")
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
lmain = Tkinter.Label(root)
lmain.grid(row=0,column=0,sticky='nsew')
bmain = Tkinter.Label(root)
bmain.grid(row=1,column=0,sticky='nsew')
baner = ImageTk.PhotoImage(image=im)
bmain.configure(image=baner)
def show_frame():
_, frame = cap.read()
if frame is None:
return
# labelWidth = root.winfo_screenwidth()
# labelHeight = root.winfo_screenheight()
# maxsize = (labelWidth, labelHeight)
# frame = frame.resize(maxsize)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(frame)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, show_frame)
show_frame()
root.mainloop()
The problems I'm having are the following:
I need to resize the image to fit the label.
the commented part i got from here (how to fit image to label in Python) but it gives a channel number error(line 40) and further down the code gives a NoneType error(line 41) and a invalid type of image(numpy array) in line 42
the image and video don't change size when resizing the window
So I need solution for this tkinter code(or even a better framework for python)
I found out what the problem was.
Turns out the line I got from another question:
frame = frame.resize(maxsize)
should be:
frame = cv2.resize(frame, maxsize)
Also to get the label's size the command is:
labelWidth = lmain.winfo_width()
labelHeight = lmain.winfo_height()
since
labelWidth = root.winfo_width()
labelHeight = root.winfo_height()
gets the root's size not the label's.