How to make this Tkinter and OpenCV program more scalable? - python

I have this part of my program to show webcam feed on a Tkinter window:
from tkinter import *
from PIL import Image, ImageTk
import cv2
root = Tk()
def show_frames():
cv2image = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2RGB)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
label.imgtk = imgtk
label.configure(image=imgtk)
label.after(20, show_frames)
label = Label(root)
label.grid()
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
show_frames()
root.mainloop()
Whole program is getting quite long and hard to naivgate and I am trying get split the source code in multiple files. However I have trouble even with this core part of my code. I tried giving show_frames() argument cap, and it runs the function once and breaks on the seccond frame.
Then I tried this:
from tkinter import *
from PIL import Image, ImageTk
import cv2
root = Tk()
def show_frames():
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
cv2image = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2RGB)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
label.imgtk = imgtk
label.configure(image=imgtk)
label.after(20, show_frames)
label = Label(root)
label.grid()
show_frames()
root.mainloop()
In this one I am unsure how to "load" the frame onto screen.

You need to move cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) outside of show_frames function.
from tkinter import *
from PIL import Image, ImageTk
import cv2
root = Tk()
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
def show_frames():
cv2image = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2RGB)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
label.imgtk = imgtk
label.configure(image=imgtk)
label.after(20, show_frames)
label = Label(root)
label.grid()
show_frames()
root.mainloop()
Also, don't use the wildcard * it may cause you problems in the future.

Related

How to display screen recorder inside a Tkinter frame or lable?

I am trying to display the screen recorder video in Tkinter. I was able to display webcam video but I am facing a problem while trying to displaying screen recorder video.
root = Tk()
# Create a frame
app = Frame(root, bg="white")
app.grid()
# Create a label in the frame
lmain = Label(app)
lmain.grid()
# Capture from camera
cap = cv2.VideoCapture(0)
def video_stream():
_, frame = cap.read()
print(frame)
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(1, video_stream)
root.after(1, video_stream)
root.mainloop()
Code used for displaying webcam video on Tkinter.

How to use Tkinter after method multiple times or is there alternative method for that?

I have program that can show webcam image/video on tkinter. I want my program to run method when I press certain key (from keyboard) or button (tkinter button) inside tkinter. Here is my code:
from tkinter import *
from PIL import Image, ImageTk
import cv2
root = Tk()
label =Label(root)
label.grid(row=0, column=0)
cap= cv2.VideoCapture(0, cv2.CAP_DSHOW)
def show_frames():
cv2image= cv2.cvtColor(cap.read()[1],cv2.COLOR_BGR2RGB)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image = img)
label.imgtk = imgtk
label.configure(image=imgtk)
label.after(20, show_frames)
def method():
print("test")
show_frames()
root.after(2000, method)
root.mainloop()
Problem with this code is was that first it ran only once. Then I tried to change the method it in this:
def method():
while True:
print("test")
Problem with this is that it freezes first the window and ultimately crashes the program. Even with only this one print statement.
how would you suggest I go about this? Or is there other method than after that I should use instead?
I added a key_pressed function and now it handles multiple key presses you can see it yourself on the console.
from tkinter import *
from PIL import Image, ImageTk
import cv2
root = Tk()
label =Label(root)
label.grid(row=0, column=0)
cap= cv2.VideoCapture(0, cv2.CAP_DSHOW)
def show_frames():
cv2image= cv2.cvtColor(cap.read()[1],cv2.COLOR_BGR2RGB)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image = img)
label.imgtk = imgtk
label.configure(image=imgtk)
label.after(20, show_frames)
def key_pressed(event):
method()
def method():
print("test")
show_frames()
root.bind("<Key>", key_pressed)
root.mainloop()

Tkinter and cv2 freezes when trying to resize window

Hey I have gotten a simple tkinter window to display my webcam using OpenCv from this question, see code
However, when I try to resize the window using my mouse curser, does the window go black and gets unresponsive.
How do I fix this, so I can resize the window after I have started the application?
Update
After a comment from #jizhihaoSAMA have I discovered that this bug is only affecting my mac running macOS 10.15.4 and python 3.7. However, it does not affect my windows 10 PC running python 3.7.
import tkinter as tk
import cv2
from PIL import Image, ImageTk
width, height = 800, 600
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
root = tk.Tk()
root.bind('<Escape>', lambda e: root.quit())
lmain = tk.Label(root)
lmain.pack()
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.mainloop()

Opencv does not recognize a usb camera

I have a problem with Opencv and Python. When I try to see frames from camera it does not to recognize a usb camera, I have used standar code from books with two usb cameras, the problem is that only one camera works and I do not know. I run opencv with python on windows, the camera's drivers are installed because Windows recognizes it.
Whats it´s wrong with second camera?
Thanks
of course! The code is following:
import cv2
import Tkinter as tk
from PIL import Image, ImageTk
#Set up GUI
window = tk.Tk() #Makes main window
window.wm_title("Digital Microscope")
window.config(background="#FFFFFF")
#Graphics window
imageFrame = tk.Frame(window, width=600, height=500)
imageFrame.grid(row=0, column=0, padx=10, pady=2)
#Capture video frames
lmain = tk.Label(imageFrame)
lmain.grid(row=0, column=0)
cap = cv2.VideoCapture(0)
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() #Display 2
window.mainloop() #Starts GUI
I don't exactly remember where I copy this code, I think from here, stackoverflow.
Thanks

Using OpenCV with Tkinter

I'm writing a program that needs to display a video stream in a Tkinter window. Since there will also be buttons for performing various functions, I'm using grid to organize where everything goes.
The following code, modified from Show webcam sequence TkInter, works fine on my Raspberry Pi:
import Tkinter as tk
import cv2
from PIL import Image, ImageTk
width, height = 800, 600
cap = cv2.VideoCapture(0)
root = tk.Tk()
lmain = tk.Label(root)
lmain.pack()
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.mainloop()
However, combining it with Tkinter doesn't work. (In what follows, I've tried commenting out Display 1, Display 2, and neither.)
import numpy as np
import cv2
import Tkinter as tk
import Image, ImageTk
#Set up GUI
window = tk.Tk() #Makes main window
window.wm_title("Digital Microscope")
window.config(background="#FFFFFF")
#Graphics window
imageFrame = tk.Frame(window, width=600, height=500)
imageFrame.grid(row=0, column=0, padx=10, pady=2)
#Capture video frames
lmain = tk.Label(imageFrame)
cap = cv2.VideoCapture(0)
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)
tk.Label(imageFrame, image=show_frame()).grid(row=0, column=0, padx=10, pady=2) #Display 1
#Slider window (slider controls stage position)
sliderFrame = tk.Frame(window, width=600, height=100)
sliderFrame.grid(row = 600, column=0, padx=10, pady=2)
show_frame() #Display 2
window.mainloop() #Starts GUI
How can I get the video to display in imageFrame?
This should work:
import numpy as np
import cv2
import Tkinter as tk
import Image, ImageTk
#Set up GUI
window = tk.Tk() #Makes main window
window.wm_title("Digital Microscope")
window.config(background="#FFFFFF")
#Graphics window
imageFrame = tk.Frame(window, width=600, height=500)
imageFrame.grid(row=0, column=0, padx=10, pady=2)
#Capture video frames
lmain = tk.Label(imageFrame)
lmain.grid(row=0, column=0)
cap = cv2.VideoCapture(0)
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)
#Slider window (slider controls stage position)
sliderFrame = tk.Frame(window, width=600, height=100)
sliderFrame.grid(row = 600, column=0, padx=10, pady=2)
show_frame() #Display 2
window.mainloop() #Starts GUI
First of all, you have the line tk.Label(imageFrame, image=show_frame()).grid(row=0, column=0, padx=10, pady=2), and since show_frame() doesn't return anything, you've set image to None. Second of all, you need to make sure you lmain.grid(), otherwise lmain won't show.
If you want to have two displays one on top of the other, you could do something like this:
import numpy as np
import cv2
import Tkinter as tk
import Image, ImageTk
#Set up GUI
window = tk.Tk() #Makes main window
window.wm_title("Digital Microscope")
window.config(background="#FFFFFF")
#Graphics window
imageFrame = tk.Frame(window, width=600, height=500)
imageFrame.grid(row=0, column=0, padx=10, pady=2)
#Capture video frames
cap = cv2.VideoCapture(0)
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)
display1.imgtk = imgtk #Shows frame for display 1
display1.configure(image=imgtk)
display2.imgtk = imgtk #Shows frame for display 2
display2.configure(image=imgtk)
window.after(10, show_frame)
display1 = tk.Label(imageFrame)
display1.grid(row=1, column=0, padx=10, pady=2) #Display 1
display2 = tk.Label(imageFrame)
display2.grid(row=0, column=0) #Display 2
#Slider window (slider controls stage position)
sliderFrame = tk.Frame(window, width=600, height=100)
sliderFrame.grid(row = 600, column=0, padx=10, pady=2)
show_frame() #Display
window.mainloop() #Starts GUI
Try this code:
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(0) # 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)
# 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
if ok: # frame captured without any errors
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA) # convert colors from BGR to RGBA
self.current_image = Image.fromarray(cv2image) # convert image for PIL
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.after(30, self.video_loop) # call the same function after 30 milliseconds
def take_snapshot(self):
""" Take snapshot and save it to the file """
ts = datetime.datetime.now() # grab the current timestamp
filename = "{}.jpg".format(ts.strftime("%Y-%m-%d_%H-%M-%S")) # construct filename
p = os.path.join(self.output_path, filename) # construct output path
self.current_image.save(p, "JPEG") # save image as jpeg file
print("[INFO] saved {}".format(filename))
def destructor(self):
""" Destroy the root object and release all resources """
print("[INFO] closing...")
self.root.destroy()
self.vs.release() # release web camera
cv2.destroyAllWindows() # it is not mandatory in this application
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", default="./",
help="path to output directory to store snapshots (default: current folder")
args = vars(ap.parse_args())
# start the app
print("[INFO] starting...")
pba = Application(args["output"])
pba.root.mainloop()

Categories

Resources