I have Tkinter GUI with a canvas that currently shows the image by default and there is a switch that will print Cam On and Cam off when switched back and forth. What I'm trying to do is to get my webcam to stream instead of that image when I flit the switch on.
Here is the code I have for my GUI:
import tkinter
import tkinter.messagebox
import customtkinter
from PIL import Image,ImageTk
# Setting up theme of GUI
customtkinter.set_appearance_mode("Dark") # Modes: "System" (standard), "Dark", "Light"
customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
# configure window
self.is_on = True
self.image = ImageTk.PhotoImage(Image.open("../data/Mars.PNG"))
self.title("Cool Blue")
self.geometry(f"{1200}x{635}")
# configure grid layout (4x4)
self.grid_columnconfigure(1, weight=1)
self.grid_columnconfigure((2, 3), weight=0)
self.grid_rowconfigure((0, 1, 2, 3), weight=0)
###################################################################
# Create Sidebar for LED, LIghts and Camera controls
###################################################################
self.lights_control = customtkinter.CTkFrame(self)
self.lights_control.grid(row=3, column=0, rowspan = 1, padx=(5, 5), pady=(10, 10), sticky="nsew")
self.lights_control.grid_rowconfigure(1, weight=1)
# Camera
self.camera_switch = customtkinter.CTkSwitch(master=self.lights_control, text="Camera", command=self.camera_switch)
self.camera_switch.grid(row=2, column=1, pady=10, padx=20, )
###################################################################
# Create canvas for RPCam live stream
###################################################################
self.picam_frame = customtkinter.CTkFrame(self)
self.picam_frame.grid(row=0, column=1, rowspan=4, padx=(5, 5), pady=(10, 10), sticky="nsew")
self.picam_frame.grid_rowconfigure(4, weight=1)
self.picam_canvas = customtkinter.CTkCanvas(self.picam_frame, width=1730, height=944, background="gray")
self.picam_canvas.create_image(0, 0, image=self.image, anchor="nw")
self.picam_canvas.pack()
#########################################################################
# Camera Switch
#########################################################################
def camera_switch(self, event=None):
if self.is_on:
print("Cam on")
self.is_on = False
else:
print("Cam off")
self.is_on = True
if __name__ == "__main__":
app = App()
app.mainloop()
Now I did some research and found this code below that will do the trick in its own canvas but I am have not had luck to use the logic from the code below in my own code above.
# Import required Libraries
from tkinter import *
from PIL import Image, ImageTk
import cv2
# Create an instance of TKinter Window or frame
win = Tk()
# Set the size of the window
win.geometry("700x350")
# Create a Label to capture the Video frames
label =Label(win)
label.grid(row=0, column=0)
cap= cv2.VideoCapture(0)
# Define function to show frame
def show_frames():
# Get the latest frame and convert into Image
cv2image= cv2.cvtColor(cap.read()[1],cv2.COLOR_BGR2RGB)
img = Image.fromarray(cv2image)
# Convert image to PhotoImage
imgtk = ImageTk.PhotoImage(image = img)
label.imgtk = imgtk
label.configure(image=imgtk)
# Repeat after an interval to capture continiously
label.after(20, show_frames)
show_frames()
win.mainloop()
So what I really need is help with using the logic from the code below and incorporating it into my own code above. Can you please help me?
Here is my latest attempt to get this solved. So I was able to merge these two code based on the logic I provided above. And when I start the GUI and switch the camera button on, I can see that camera is starting since the LED light on the camera turns on and I get a windows notification that my program is starting the camera. however, it is not showing on the canvas yet. So I think I am close but I am not sure what I'm missing.
import tkinter
import tkinter.messagebox
import customtkinter
from PIL import Image,ImageTk
import cv2
# Setting up theme of GUI
customtkinter.set_appearance_mode("Dark") # Modes: "System" (standard), "Dark", "Light"
customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
# configure window
self.is_on = True
self.image = ImageTk.PhotoImage(Image.open("../data/Mars.PNG"))
self.capture = cv2.VideoCapture(0)
self.title("Cool Blue")
self.geometry(f"{1200}x{635}")
# configure grid layout (4x4)
self.grid_columnconfigure(1, weight=1)
self.grid_columnconfigure((2, 3), weight=0)
self.grid_rowconfigure((0, 1, 2, 3), weight=0)
###################################################################
# Create Sidebar for LED, LIghts and Camera controls
###################################################################
self.lights_control = customtkinter.CTkFrame(self)
self.lights_control.grid(row=3, column=0, rowspan = 1, padx=(5, 5), pady=(10, 10), sticky="nsew")
self.lights_control.grid_rowconfigure(1, weight=1)
# Camera
self.camera_switch = customtkinter.CTkSwitch(master=self.lights_control, text="Camera", command=self.camera_switch)
self.camera_switch.grid(row=2, column=1, pady=10, padx=20, )
###################################################################
# Create canvas for RPCam live stream
###################################################################
self.picam_frame = customtkinter.CTkFrame(self)
self.picam_frame.grid(row=0, column=1, rowspan=4, padx=(5, 5), pady=(10, 10), sticky="nsew")
self.picam_frame.grid_rowconfigure(4, weight=1)
# self.picam_canvas = customtkinter.CTkCanvas(self.picam_frame, width=1730, height=944, background="gray")
# self.picam_canvas.create_image(0, 0, image=self.image, anchor="nw")
self.picam_canvas = tkinter.Canvas(self.picam_frame, width=1730, height=944)
#self.picam_canvas.pack
#########################################################################
# Camera Switch
#########################################################################
def camera_switch(self, event=None):
if self.is_on:
self.update_frames()
print("Cam on")
self.is_on = False
else:
#self.close_camera()
self.image
print("Cam off")
self.is_on = True
def update_frames(self):
# Get the current frame from the webcam
_, frame = self.capture.read()
# Convert the frame to a PhotoImage object
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = Image.fromarray(frame)
frame = ImageTk.PhotoImage(frame)
# Update the canvas with the new frame
self.picam_canvas.create_image(0, 0, image=frame, anchor="nw")
self.picam_canvas.image = frame
# Schedule the next update
self.after(1000, self.update_frames)
def close_camera(self):
self.capture.release()
if __name__ == "__main__":
app = App()
app.mainloop()
Again, if anyone has any insight I would really appreciate it.
CodePudding user response:
In the code you can take advantage of the variable self.is_on
in the update_frame
function to finish the loop. Something like this.
def update_frames(self):
# Change the frame by the initial image and breaks the loop
if self.is_on:
self.picam_canvas.create_image(0, 0, image=self.image, anchor="nw")
return
else:
_, frame = self.capture.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = Image.fromarray(frame)
frame = ImageTk.PhotoImage(frame)
self.picam_canvas.create_image(0, 0, image=frame, anchor="nw")
self.picam_canvas.image = frame
self.picam_canvas.after(1, self.update_frames)
But this gave an error because when you turn it back on, the video capture didn't start. So I modified some lines in the camera_switch
function.
def camera_switch(self, event=None):
if self.is_on:
self.capture = cv2.VideoCapture(0)
print("Cam on")
self.is_on = False
self.update_frames()
else:
self.close_camera()
self.image
print("Cam off")
self.is_on = True
The line self.capture = cv2.VideoCapture(0)
was at the beginning but I removed it and put it here so that it initializes the video capture when the button is pressed