OpenCV w/ Tkinter : Lag & window problems - python

I recently started using opencv with tkinter, and I started to have some problems that I can't seem to fix by myself...
The following code is supposed to play a video file while being able to choose which sub-directory you want to sort the file in. The problems I started to have is that the number of frames per seconds seems to act weird, since some clip I play seems "lagging", or don't have the right fps.
Secondly, the code seems really messy, and thus buttons "disappear" after clicking on one for a moment.
And finally, I tried to do something so the buttons get as big as possible to fill the x axis on the bottom of the window, while the main frame, with the video playing, stays the same same size (so the video is supposed to stay in the middle, adapting his height and width to the frame size without changing the ratio) but that doesn't seems to work too.
Any help will be appreciated
PS: I am using Python 3.8 with openCV 4.1.2
Here is the code :
from tkinter import Tk, Button, Label, Frame
import os
import shutil
import cv2
from PIL import Image, ImageTk
x = 0
path = "path/to/folder"
def nbr():
global x
x += 1
text.config(text=files[x])
class ButtonX (Button):
def __init__ (self, *args, folder="", **kwargs):
super().__init__(*args, **kwargs)
self.folder = folder
self.config(command=self.moveTo)
def moveTo(self):
global x
global cap
global width
if cap.isOpened():
cap.release()
shutil.move(path + files[x], path + self.folder + "/" +files[x])
print(files[x] + " moved to " + self.folder)
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
folders = [dI for dI in os.listdir(path) if os.path.isdir(os.path.join(path,dI))]
allfiles = os.listdir(path)
files = [ fname for fname in allfiles if fname.endswith('.webm')]
files.sort(key=len)
print(folders)
window = Tk()
window.resizable(0, 0)
window.geometry("1600x908")
back = Frame(window)
back.grid(row=1, column=1)
window.grid_rowconfigure(0, weight=1)
window.grid_rowconfigure(2, weight=1)
window.grid_columnconfigure(0, weight=1)
window.grid_columnconfigure(2, weight=1)
player = Frame(back)
player.grid(row = 0, column=0)
buttouns = Frame(back)
buttouns.grid(row = 1, column=0)
text = Label(player)
text.grid(row=0, columnspan=4, sticky='w,e,n,s', padx=5, pady=50)
cap = cv2.VideoCapture(path+files[x])
fps = cap.get(cv2.CAP_PROP_FPS)
cap.set(cv2.CAP_PROP_FPS, fps)
print(fps)
height = 600
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
def show_frame():
global cap
global width
cap.set(cv2.CAP_PROP_FPS, fps)
ret, frame = cap.read()
if frame is None:
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image).resize((width, height))
imgtk = ImageTk.PhotoImage(image = img)
text.imgtk = imgtk
text.configure(image=imgtk)
text.after(3, show_frame)
buttons = []
z = 1
y = 0
for i in range(len(folders)):
new_button = ButtonX(buttouns,text=folders[i], width=20, height=2, folder=folders[i])
buttons.append(new_button)
buttons[i].grid(row=z, column=y, sticky='w,e,n,s', padx=5, pady=5)
y += 1
if y == 4:
y = 0
z += 1
def deleted():
global cap
global width
print("deleted " + files[x])
if cap.isOpened():
cap.release()
shutil.move(path + files[x], "path/to/deleted" + files[x])
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
def skipped():
global cap
global width
print(files[x] + " skipped")
if cap.isOpened():
cap.release()
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
delete= Button(buttouns,text="Delete", width=20, height=2, command=deleted, foreground="red")
delete.grid(row=z+1,column=2, columnspan=2, sticky='w,e,n,s', padx=5, pady=5)
skip= Button(buttouns,text="Skip", width=20, height=2, command=skipped)
skip.grid(row=z+1, columnspan=2, sticky='w,e,n,s', padx=5, pady=5)
show_frame()
window.mainloop()

Related

Frozen cameras in OpenCV

I have tried to place two cameras to be able to take snapshots in both, I have even put a button to activate one and then the other but one way or another whenever I activate both together or deactivate one and activate the next one the window freezes. I attach the code that I was building if you have any suggestions on the matter I would greatly appreciate it. I have little knowledge of Python in general so keep it a little friendly.
from tkinter import *
from tkinter import Tk, Label, Frame, Entry, Button
from tkinter import ttk
from PIL import Image
from PIL import ImageTk
import cv2
import threading
import imutils
window0= Tk() #Pantalla inicial
window0.title('Detección del punto optimo de vacunación') #Titulo de la ventana
window0.geometry('1280x720') #Dimesiones de la ventana
window0.configure(bg='#35455d') #Color de fondo
tabControl = ttk.Notebook(window0)
tab1 = ttk.Frame(tabControl)
tab2 = ttk.Frame(tabControl)
tabControl.add(tab1, text ='Formulario')
tabControl.add(tab2, text ='Captura de webcam')
tabControl.pack(expand = 1, fill ="both")
#Pestaña 1
label_0 = Label(tab1, text="Formulario de Registro",width=20,font=("bold", 20))
label_0.place(x=90,y=53)
label_1 = Label(tab1, text="Edad",width=20,font=("bold", 10))
label_1.place(x=70,y=130)
entry_1 = Entry(tab1)
entry_1.place(x=240,y=130)
label_2 = Label(tab1, text="Genero",width=20,font=("bold", 10))
label_2.place(x=70,y=180)
var = IntVar()
Radiobutton(tab1, text="M",padx = 5, variable=var, value=1).place(x=235,y=180)
Radiobutton(tab1, text="F",padx = 20, variable=var, value=2).place(x=290,y=180)
def IMC():
try:
peso = int(entrada_texto.get())
estatura = int(entrada2_texto.get())
imc = peso/estatura**2
etiqueta5.config(text=imc)
except ValueError:
etiqueta5.config(text="Introduce un numero")
label_3 = Label(tab1, text="Estatura",width=20,font=("bold", 10))
label_3.place(x=70,y=230)
estatura= ""
entry_3 = Entry(tab1, textvariable=estatura)
entry_3.place(x=240,y=230)
label_4 = Label(tab1,text="Peso",width=20,font=("bold", 10))
label_4.place(x=70,y=280)
peso= ""
entry_4 =Entry(tab1, textvariable=peso)
entry_4.place(x=240,y=280)
# print('Su IMC es:¨{}'.format(indice))
label_5 = Label(tab1,text="IMC:",width=20,font=("bold", 10))
label_5.place(x=70,y=330)
entry_5 =Entry(tab1)
entry_5.place(x=240,y=330)
Button(tab1, text='Capturar Imagen',width=20,bg='brown',fg='white').place(x=580,y=560)
# it is use for display the registration form on the window
def iniciarcam1():
global cap
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
visualizar()
def iniciarcam2():
global cap1
cap1 = cv2.VideoCapture(0,cv2.CAP_DSHOW)
visualizar1()
def visualizar():
global cap
if cap is not None:
ret, frame = cap.read()
if ret == True:
frame = imutils.resize(frame, width=360)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
im = Image.fromarray(frame)
img = ImageTk.PhotoImage(image=im)
lblVideo.configure(image=img)
lblVideo.image = img
lblVideo.after(20, visualizar)
else:
lblVideo.image = ""
cap.release()
def visualizar1():
global cap1
if cap1 is not None:
ret, frame = cap1.read()
if ret == True:
frame = imutils.resize(frame, width=360)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
im = Image.fromarray(frame)
img = ImageTk.PhotoImage(image=im)
lblVideo1.configure(image=img)
lblVideo1.image = img
lblVideo1.after(20, visualizar)
else:
lblVideo1.image = ""
cap1.release()
def finalizarcam1():
global cap
if cap.isOpened():cap.release()
print("Camara 1 release")
def finalizarcam2():
global cap1
if cap1.isOpened():cap1.release()
print("Camara 2 release")
cap = None
cap1 = None
btnIniciar = Button(tab1, text="Iniciar CAM1", width=20, command=iniciarcam1)
# btnIniciar.grid(column=0, row=0, padx=5, pady=5)
btnIniciar.place(x=800,y=53)
btnFinalizar = Button(tab1, text="Finalizar CAM1", width=20, command=finalizarcam1)
# btnFinalizar.grid(column=1, row=0, padx=5, pady=5)
btnFinalizar.place(x=800,y=103)
btnIniciar = Button(tab1, text="Iniciar CAM2", width=20, command=iniciarcam2)
# btnIniciar.grid(column=0, row=0, padx=5, pady=5)
btnIniciar.place(x=1000,y=53)
btnFinalizar = Button(tab1, text="Finalizar CAM2", width=20, command=finalizarcam2)
# btnFinalizar.grid(column=1, row=0, padx=5, pady=5)
btnFinalizar.place(x=1000,y=103)
lblVideo = Label(window0)
lblVideo1 = Label(window0)
# lblVideo.grid(column=0, row=1, columnspan=2)
lblVideo.place(x=500,y=200)
lblVideo1.place(x=900,y=200)
#Pestaña 2
label2_0 = Label(tab2, text="Procesado",width=20,font=("bold", 20))
label2_0.place(x=90,y=20)
window0.mainloop()
I run code and it never freeze window.
The only mistake which I found is: you fogot 1 in word visualizar1 in line lblVideo1.after(20, visualizar) in function visualizar1 - so when you start second camera then after tries to run code for first camera and it can't update image for second camera and it may look like it freeze.

how to upload video to AWS while capturing videos using openCV python

I have a Tkinter multiFrame/pages application In one of the frames i have camera related work i.e when I go on the page the camera automatically start and start capturing 20 sec video recording with openCV that means when video gets 20 second long it saves video locally and then starts recording new video of 20 second now i want those videos to upload on aws when a video gets recorded and got saved locally how can i achieve that whenever a video gets record i want that video should upload to aws automatically and get deleted from local computer and than this process should again start when new 20 second video is recorded.
my code
class FrontCameraPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.cameraFrame = tk.Frame(self, bg=gray)
self.cameraFrame.grid(row=1, column=0, sticky="nsew")
self.buttonFrame = tk.Frame(self, bg="white")
self.buttonFrame.grid(row=1, column=1, sticky="nsew", padx=(10, 0))
self.stop= tk.Button(self.buttonFrame, text="END TRIP", font=small_Font, bg=dark_blue, fg="White")
self.stop.grid(row=2, column=0, ipadx=10, pady=(0, 5))
self.stop['command'] = self.stop_capture
self.cancelButton = tk.Button(self.buttonFrame, text="Cancel", font=small_Font, bg=dark_blue, fg="white")
self.cancelButton.grid(row=3, column=0, ipadx=10)
self.cancelButton['command'] = lambda: controller.show_frame(go_to_some_page)
# setup callbacks for switching in and out events
self.bind('<<SwitchIn>>', self.start_capture)
self.bind('<<SwitchOut>>', self.stop_capture)
self.lmain = tk.Label(self.cameraFrame)
self.lmain.pack()
self.capture = None
def start_capture(self, event=None):
if self.capture is None:
#-----------------------------------
width, height = 200, 200
self.cap = cv2.VideoCapture(0)
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
# used instance variables for width and height
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# initialize file rotation and frame counters
self.timer = 1 # file rotation counter
self.frames = 0 # frame counter
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out = cv2.VideoWriter(
f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
#-----------------------------------
self.show_frame()
print('capture started')
def stop_capture(self, event=None):
if self.capture:
self.after_cancel(self.capture)
#-----------------------------------
self.cap.release()
self.out.release()
#------------------------------
self.capture = None
print('capture stopped')
def show_frame(self):
ret, frame = self.cap.read()
if ret:
self.out.write(frame)
self.frames += 1
if self.frames >= 500:
self.out.release()
self.timer += 1
self.out.open(f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
self.frames = 0
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
self.imgtk = ImageTk.PhotoImage(image=img)
self.lmain.configure(image=self.imgtk)
self.capture = self.after(10, self.show_frame)

Trouble calling a camera capture function tkinter

I am trying to create different radio buttons for different methods of uploading an image. I created a function for running a camera and showcasing it with a button to take a picture. Whenever I call this function it works. But when I try to call it inside tk.radiobutton I get the following error.
_tkinter.TclError: image "pyimage77" doesn't exist
Here is my code. I try to create a function called camerachoice which creates a window for the camera. #
import tkinter as tk
from tkinter import filedialog
import cv2
import PIL.Image, PIL.ImageTk
import time
def camerachoice():
class App:
def __init__(self, window, window_title, video_source=0):
self.window = window
self.window.title(window_title)
self.video_source = video_source
self.vid = MyVideoCapture(self.video_source)
self.canvas = tk.Canvas(window, width = self.vid.width, height = self.vid.height)
self.canvas.pack()
self.btn_snapshot=tk.Button(window, text="Snapshot", width=50, command=self.snapshot)
self.btn_snapshot.pack(anchor=tk.CENTER, expand=True)
self.delay = 15
self.update()
self.window.mainloop()
def snapshot(self):
ret, frame = self.vid.get_frame()
if ret:
#cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M- br%S") + ".jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
cv2.imwrite("cancercheck.jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
def update(self):
ret, frame = self.vid.get_frame()
if ret:
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tk.NW)
self.window.after(self.delay, self.update)
class MyVideoCapture:
def __init__(self, video_source=0):
self.vid = cv2.VideoCapture(video_source)
if not self.vid.isOpened():
raise ValueError("Unable to open video source", video_source)
self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
def get_frame(self):
if self.vid.isOpened():
ret, frame = self.vid.read()
if ret:
return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
else:
return (ret, None)
else:
return (ret, None)
def __del__(self):
if self.vid.isOpened():
self.vid.release()
#App()
App(tk.Tk(), "Tkinter and OpenCV")
root = tk.Tk()
v = tk.IntVar()
tk.Label(root,
text="""Choose method:""",
justify = tk.LEFT,
padx = 20).pack()
tk.Radiobutton(root,
text="Camera",
padx = 20,
variable=v,
command=camerachoice(),
value=2,
).pack(anchor=tk.W)
root.mainloop()

Python Tkinter OpenCV PIL image resize to fit label

I am trying to resize my webcam output to fit into the label but I couldn't really make it work. If you decided to try and test the code I have put a blue background in the label as a guide on how large you will need to resize the webcam output.
The code is:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
isrunning = 0
def start():
global isrunning
if isrunning == 0:
global cap
cap = cv2.VideoCapture(0)
isrunning = 1
lmain.grid(row = 1,column = 1)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
if isrunning == 1:
lmain.after(10, show_frame)
show_frame()
def Stop():
global isrunning
isrunning = 0
lmain.grid_forget()
def main():
Stop()
Reset.invoke()
stopFunc.invoke()
root = Tk()
lmain = Label(root, width = 800, height = 600, bg = "blue")
stopFunc = Button(root, text = "stop", command = Stop)
Reset = Button(root, text = "Reset", command = start)
Main = Button(root, text = "Stop", command = main)
Start = Button(root, text = "Start", command = start)
Start.grid(row = 0, column = 0)
Main.grid(row = 0, column = 1)
root.mainloop()
I have tried your code, and I change some code here:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
isrunning = 0
def start():
global isrunning
if isrunning == 0:
global cap
cap = cv2.VideoCapture(0)
isrunning = 1
lmain.grid(row = 1,column = 1)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
frame = cv2.resize(frame, (800,600))
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
if isrunning == 1:
lmain.after(10, show_frame)
else:
cap.release()
show_frame()
def Stop():
global isrunning
isrunning = 0
lmain.grid_forget()
def main():
Stop()
#Reset.invoke()
#stopFunc.invoke()
root = Tk()
lmain = Label(root, width = 800, height = 600, bg = "blue")
stopFunc = Button(root, text = "stop", command = Stop)
Reset = Button(root, text = "Reset", command = start)
Main = Button(root, text = "Stop", command = main)
Start = Button(root, text = "Start", command = start)
Start.grid(row = 0, column = 0)
Main.grid(row = 0, column = 1)
root.mainloop()
As you can see, I add one line: frame = cv2.resize(frame, (800,600)) to re-size the image.
And I found that after I add this line, here was an error occurred when I pressed the "Stop" button. So I try to use the cap.release() to release the camera every time when you pressed the "Stop" button. But I don't have webcam to test this code now, I can not ensure it will work when you re-start the stream. Hope it helps.

Python OpenCV output on Tkinter label deletion

I am trying to delete a Tkinter label that is currently displaying a webcam stream made by OpenCV. I eventually made it to happen but not with the way I wanted because it just stops the stream but the last image outputted by the stream is still present. The code is this:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
def Start():
width, height = 800, 600
cap = cv2.VideoCapture(0)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, height)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, show_frame)
show_frame()
root = Tk()
lmain = Label(root)
lmain.pack(side = RIGHT)
Button1 = Button(root, text = "Start", command = Start)
Button1.pack(side = LEFT)
Button2 = Button(root, text = "Stop", command = Start)
Button2.pack(side = LEFT)
root.mainloop()
You may notice that the function I used to stop it is the same function I used to start it, that is because I am very clueless as on how to stop it.
The code is:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
isrunning = 0
def Start():
global isrunning
if isrunning == 0:
global cap
cap = cv2.VideoCapture(0)
isrunning = 1
lmain.pack(side = RIGHT)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
if isrunning == 1:
lmain.after(10, show_frame)
show_frame()
def Stop():
global isrunning
isrunning = 0
lmain.pack_forget()
def main():
Stop()
Button1.invoke()
Stop()
root = Tk()
lmain = Label(root)
Button1 = Button(root, text = "Start", command = Start)
Button1.pack(side = LEFT)
Button2 = Button(root, text = "Stop", command = main)
Button2.pack(side = LEFT)
root.mainloop()
I have tried your code, and I add some code here:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
isrunning = 0
def Start():
global isrunning
if isrunning == 0:
width, height = 800, 600
cap = cv2.VideoCapture(0)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, height)
isrunning = 1
lmain.pack(side = RIGHT)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
if isrunning == 1:
lmain.after(10, show_frame)
show_frame()
def Stop():
global isrunning
isrunning = 0
lmain.pack_forget()
root = Tk()
lmain = Label(root)
Button1 = Button(root, text = "Start", command = Start)
Button1.pack(side = LEFT)
Button2 = Button(root, text = "Stop", command = Stop)
Button2.pack(side = LEFT)
root.mainloop()
You can find that I add a global variable isrunning to let the function show_frame check every time. If the variable isrunning is equal to 0, the function will stop. And I also add the function Stop as the callback function of the "Stop" button which contains the code lmain.pack_forget() to remove the label.
Since the label will be removed every time when you click the "Stop" button, I move the code for adding the label to the Start function. Hope it helps.

Categories