Python Tkinter OpenCV PIL image resize to fit label - python

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.

Related

Tk Window closing not going to classes

I've been running my code on python idle while working on this and didn't receive any problems until I tried running it on visual studio. When running it the tk window just closes and it doesn't go to the classes it tells it too. I am still learning so I probably have some mistakes I would love to get any feedback.
import tkinter as tk
#Takes photos with certain char and if clicked another char program stops
from cv2 import *
import numpy as np
import cv2
import os
from datetime import datetime
now = datetime.now()
time = now.strftime("%H:%M:%S")
#sets the directory and text info
os.chdir(r"C:\Users\asdasd\Desktop\camera")
file_name = 'pic'
cam = cv2.VideoCapture(0)
font = cv2.FONT_HERSHEY_TRIPLEX
org = (00,300)
fontScale = 1
color = (255,0,0)
thickness = 1
root= tk.Tk()
photo = tk.PhotoImage(file=r"C:\Users\asdas\Desktop\camera\pic.png")
root.iconphoto(False, photo)
root.geometry("+0+50")
print("created window")
#Creates window
canvas1 = tk.Canvas(root, width = 600, height = 600)
canvas1.pack()
canvas1.configure(bg='lightgray')
root.title("ShippingData")
root.lift()
#text label for batch #
label1 = tk.Label(root, text='Enter Batch# :')
label1.config(font=('helvetica', 15))
canvas1.create_window(65, 50, window=label1)
print("created window")
#creates input window for batch #
entry1 = tk.Entry (root)
canvas1.create_window(200, 50, window=entry1)
#text label for initials
label1 = tk.Label(root, text='Enter initials :')
label1.config(font=('helvetica', 15))
canvas1.create_window(65, 100, window=label1)
#creates input window for intials
entry2 = tk.Entry (root)
canvas1.create_window(200, 100, window=entry2)
#gets the info after start button is pressed
def getInfo ():
print("getinfo")
x1 = entry1.get()
x2 = entry2.get()
name = str(x1 + x2)
global dirname
dirname = name
os.mkdir(dirname)
label1 = tk.Label(root, text= "Program Starting")
canvas1.create_window(200, 230, window=label1)
canvas1.destroy()
programStarted()
print("button")
button1 = tk.Button(root, text='Start', command=getInfo)
print("button created")
canvas1.create_window(200, 180, window=button1)
print("canvas created for window")
def programStarted():
print("programstart")
root.update()
#creates new window
global canvas2
canvas2 = tk.Canvas(root, width = 400, height = 300)
canvas2.pack()
# Camera instructions
label2 = tk.Label(root, text= "Press z to take Photos.")
canvas2.create_window(200, 100, window=label2)
label3 = tk.Label(root, text= "Press c multiple times when finished to stop taking photos. ")
canvas2.create_window(200, 150, window=label3)
root.update()
camera()
#camera program
def camera():
print("camera")
global n
global time
global path
n= 1
while(True):
numphoto = "#" + str(n)
ret, frame = cam.read()
cv2.namedWindow("Shipping camera", cv2.WINDOW_NORMAL)
scale_percent = 100 # percent of original size
width = int(frame.shape[1] * scale_percent / 100)
height = int(frame.shape[0] * scale_percent / 100)
dim = (width, height)
frame = cv2.resize(frame, dim, interpolation = cv2.INTER_AREA)
scale_percent = 100 # percent of original size
width = int(frame.shape[1] * scale_percent / 100)
height = int(frame.shape[0] * scale_percent / 100)
dim = (width, height)
frame = cv2.resize(frame, dim, interpolation = cv2.INTER_AREA)
cv2.putText(frame, numphoto, org, font, fontScale,color,thickness, cv2.LINE_AA, False)
cv2.imshow('Shipping camera', frame)
cv2.setWindowProperty("Shipping camera", cv2.WND_PROP_TOPMOST, 1)
if cv2.waitKey(1) & 0xFF == ord('z'):
n+=1
cv2.imwrite(os.path.join(dirname,(file_name + (str(n-1)) + ".jpg")), frame)
path = (os.path.join(str(r"C:\Users\sadsads\Desktop\camera"), str(dirname)))
elif (cv2.waitKey(1) & 0xFF == ord('c')):
# stops everything
cam.release()
cv2.destroyAllWindows()
with open((path+r'\timelog.txt'), 'w') as f:
f.write(time+ '\n')
now = datetime.now()
time2 = now.strftime("%H:%M:%S")
f.write(time2+ '\n')
y = 0
if(y == 0):
# destory the other windows
root.quit()
root.destroy()
break
else:
root.mainloop()

How can I find the reason my tkinter is dead?

I'm trying to make a screen recording program with some interface.
the recording works nice when it's played independently,
but as soon as I put into a function and use as a button command,
tkinter gets dead.
there is no error message, nothing but a dead window.
how can I figure this out?
the code is:
import pyautogui
import cv2
import numpy as np
import keyboard
import time
from tkinter import*
from tkinter import messagebox
def record_stop():
keyboard.press_and_release('q')
def screenrec(): #recording program
resolution = (1920,1080)
codec = cv2.VideoWriter_fourcc(*'XVID')
filename = '{}.avi'.format(time.strftime('_%Y%m%d_%H%M%S'))
fps = 60.0
out = cv2.VideoWriter(filename, codec, fps, resolution)
messagebox.showinfo('info', 'Recording start.')
while True:
img = pyautogui.screenshot()
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.write(frame)
if cv2.waitKey(1) == ord('q'):
messagebox.showinfo('info', 'Recording stopped.')
break
out.release()
cv2.destroyAllWindows()
root = Tk()
root.resizable(False, False)
root.title('Record program')
btnframe = LabelFrame(root, text='Record')
btnframe.pack(fill='x', padx=5, pady=5)
btn_start = Button(btnframe, text='Start recording', width=10, command=screenrec)
btn_start.pack(side='left', padx=5, pady=5)
btn_stop = Button(btnframe, text='Stop recording', width=10, command=record_stop)
btn_stop.pack(side='right', pady=5, padx=5)
root.mainloop()
Your while loop is blocking tkinter's loop. So make use of threads using the threading module
Here is an example:
import pyautogui
import cv2
import numpy as np
import keyboard
import time
from tkinter import *
from tkinter import messagebox
from threading import Thread
def record_stop():
keyboard.press_and_release('q')
def screenrec(): #recording program
resolution = (1920,1080)
codec = cv2.VideoWriter_fourcc(*'XVID')
filename = '{}.avi'.format(time.strftime('_%Y%m%d_%H%M%S'))
fps = 60.0
out = cv2.VideoWriter(filename, codec, fps, resolution)
messagebox.showinfo('info', 'Recording start.')
while record:
img = pyautogui.screenshot()
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.write(frame)
if cv2.waitKey(1) == ord('q'):
messagebox.showinfo('info', 'Recording stopped.')
break
out.release()
cv2.destroyAllWindows()
def switchRec():
global record
record = not record
if record:
btn_start.config(text="Stop recording")
thread = Thread(target=screenrec)
thread.setDaemon(True)
thread.start()
else:
btn_start.config(text="Start recording")
root = Tk()
root.resizable(False, False)
root.title('Record program')
record = False
btnframe = LabelFrame(root, text='Record')
btnframe.pack(fill='x', padx=5, pady=5)
btn_start = Button(btnframe, text='Start recording', width=10, command=switchRec)
btn_start.pack(side='left', padx=5, pady=5)
root.mainloop()
While loops mess with mainloop. Try this:
import multiprocessing
.....
def screenrec(): #recording program
resolution = (1920,1080)
codec = cv2.VideoWriter_fourcc(*'XVID')
filename = '{}.avi'.format(time.strftime('_%Y%m%d_%H%M%S'))
fps = 60.0
out = cv2.VideoWriter(filename, codec, fps, resolution)
messagebox.showinfo('info', 'Recording start.')
while True:
img = pyautogui.screenshot()
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.write(frame)
if cv2.waitKey(1) == ord('q'):
messagebox.showinfo('info', 'Recording stopped.')
proc.terminate()
break
out.release()
cv2.destroyAllWindows()
def new_process():
proc = multiprocessing.Process(target=screenrec)
proc.start()
btn_start = Button(btnframe, text='Start recording', width=10, command=new_process)
btn_start.pack(side='left', padx=5, pady=5)

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()

OpenCV w/ Tkinter : Lag & window problems

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()

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