I have only 2 USB cameras that are connected to my PC (Note: highly confident that I won’t use more than 2 cameras now and in future) . My aim of this program is to capture front and rear view concurrently. And I have successfully have the working prototype of the program which allowed to view 2 live feed video at the same time .
I attached the sample program here which allowed live video feeds from 2 cameras concurrently at the same time.
import cv2
import tkinter as tk
from datetime import datetime
from PIL import Image, ImageTk, ImageDraw
global photo1, photo2
photo1 = None
photo2 = None
def print_camera_info(width, height, camera_number):
print(f"Camera {camera_number}")
print(f"Width: {width}")
print(f"Height: {height}")
print("---")
def swap_camera():
print("In swap_camera!") #debugging purpose
global photo1, photo2
print("After define global in swap_camera") #debugging purpose
print("Before swap")#debugging purpose
# Swap the frames algorithm
tmp = photo1
photo1 = photo2
photo2 = tmp
print("After Swap") #debugging purpose
def main():
# Open two camera devices
front_cap = cv2.VideoCapture(0) # Use 0 for the first camera (Front Camera)
rear_cap = cv2.VideoCapture(1) # Use 1 for the second camera (Rear Camera)
# Check if the cameras opened successfully
if not (front_cap.isOpened() and rear_cap.isOpened()):
print("Error: Could not open cameras.")
print("front_cap opened:", front_cap.isOpened())
print("rear_cap opened:", rear_cap.isOpened())
return
# Set the desired width and height for live feed
target_width, target_height = 320, 240
# Set the CAP_PROP_FRAME_WIDTH and CAP_PROP_FRAME_HEIGHT properties for both cameras
front_cap.set(cv2.CAP_PROP_FRAME_WIDTH, target_width)
front_cap.set(cv2.CAP_PROP_FRAME_HEIGHT, target_height)
rear_cap.set(cv2.CAP_PROP_FRAME_WIDTH, target_width)
rear_cap.set(cv2.CAP_PROP_FRAME_HEIGHT, target_height)
# Get the actual dimensions after setting the properties
actual_width1 = int(front_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_height1 = int(front_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
actual_width2 = int(rear_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_height2 = int(rear_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Print camera information with the actual resized dimensions
print_camera_info(actual_width1, actual_height1, "Front")
print_camera_info(actual_width2, actual_height2, "Rear")
# Create Tkinter window
root = tk.Tk()
root.title("Combined Cameras")
# Create a Checkbutton for camera toggle
camera_toggle_button = tk.Checkbutton(root, text="Toggle Camera", command=swap_camera)
camera_toggle_button.grid(row=1, column=1, padx=10, pady=10)
# Create label widget for date and time
datetime_label = tk.Label(root, text="", font=("Helvetica", 14))
datetime_label.grid(row=1, column=2, columnspan=2, pady=10)
# Create label widgets for camera views
label1 = tk.Label(root, text="FRONT VIEW")
label2 = tk.Label(root, text="REAR VIEW")
label1.grid(row=2, column=2)
label2.grid(row=2, column=3)
# Create image labels for camera feeds
video_livefeedfront = tk.Label(root)
video_livefeedrear = tk.Label(root)
video_livefeedfront.grid(row=3, column=2, padx=10)
video_livefeedrear.grid(row=3, column=3, padx=10)
while True:
# Read frames from both cameras
ret1, frame1 = front_cap.read()
ret2, frame2 = rear_cap.read()
# Check if the frames were read successfully
if not (ret1 and ret2):
print("Error: Could not read frames from cameras.")
break
# Resize frames to the target dimensions
frame_resized1 = cv2.resize(frame1, (target_width, target_height))
frame_resized2 = cv2.resize(frame2, (target_width, target_height))
# Convert frames to RGB format for PIL
frame_rgb1 = cv2.cvtColor(frame_resized1, cv2.COLOR_BGR2RGB)
frame_rgb2 = cv2.cvtColor(frame_resized2, cv2.COLOR_BGR2RGB)
# Convert frames to PhotoImage format for Tkinter
photo1 = ImageTk.PhotoImage(Image.fromarray(frame_rgb1))
photo2 = ImageTk.PhotoImage(Image.fromarray(frame_rgb2))
# Update image live videofeed
video_livefeedfront.configure(image=photo1)
video_livefeedfront.photo = photo1
video_livefeedrear.configure(image=photo2)
video_livefeedrear.photo = photo2
# Update the Tkinter window
root.update()
# Release the camera devices and destroy the Tkinter window
front_cap.release()
rear_cap.release()
cv2.destroyAllWindows()
root.destroy()
if __name__ == "__main__":
main()
There are at times where the front and rear views might be at its designated location when connected (i.e; Front camera show rear live video feed). Therefore, I add a camera_toggle_button
to swap the view . However, there are weird bugs right now, when I click on the checkbox camera_toggle_button
, I expect the FRONT VIEW should be swapped with REAR VIEW , but as shown below, it does not happened at all. As you can see, I successfully print out the debugging notes (meaning it enter all the algorithm sequences correctly) , but somehow the live video feed does not swapped at all. It is weird at least.
You need to swap the target labels instead of photo1
and photo2
. Also avoid using while
loop in the main thread of a tkinter application, use after loop instead.
...
def swap_camera():
global video_livefeedfront, video_livefeedrear
# swap the target labels
video_livefeedfront, video_livefeedrear = video_livefeedrear, video_livefeedfront
def main():
global video_livefeedfront, video_livefeedrear
...
# Create image labels for camera feeds
video_livefeedfront = tk.Label(root)
video_livefeedrear = tk.Label(root)
video_livefeedfront.grid(row=3, column=2, padx=10)
video_livefeedrear.grid(row=3, column=3, padx=10)
# use after loop instead of while loop
def update_cameras():
# Read frames from both cameras
ret1, frame1 = front_cap.read()
ret2, frame2 = rear_cap.read()
# Check if the frames were read successfully
if not (ret1 and ret2):
print("Error: Could not read frames from cameras.")
root.destroy()
# Resize frames to the target dimensions
frame_resized1 = cv2.resize(frame1, (target_width, target_height))
frame_resized2 = cv2.resize(frame2, (target_width, target_height))
# Convert frames to RGB format for PIL
frame_rgb1 = cv2.cvtColor(frame_resized1, cv2.COLOR_BGR2RGB)
frame_rgb2 = cv2.cvtColor(frame_resized2, cv2.COLOR_BGR2RGB)
# Convert frames to PhotoImage format for Tkinter
photo1 = ImageTk.PhotoImage(Image.fromarray(frame_rgb1))
photo2 = ImageTk.PhotoImage(Image.fromarray(frame_rgb2))
# Update image live videofeed
video_livefeedfront.configure(image=photo1)
video_livefeedfront.photo = photo1
video_livefeedrear.configure(image=photo2)
video_livefeedrear.photo = photo2
root.after(25, update_cameras) # change 25ms to whatever that suits your requirement
update_cameras() # start the after loop to update the camera feeds
root.mainloop()
# Release the camera devices and destroy the Tkinter window
front_cap.release()
rear_cap.release()
cv2.destroyAllWindows()
...
Here is the complete code. Many thanks for @acw1668
import cv2
import tkinter as tk
from datetime import datetime
from PIL import Image, ImageTk, ImageDraw
global photo1, photo2
##photo1 = None
##photo2 = None
def print_camera_info(width, height, camera_number):
print(f"Camera {camera_number}")
print(f"Width: {width}")
print(f"Height: {height}")
print("---")
def swap_camera():
print("In swap_camera functions!") #debugging purpose
global video_livefeedfront, video_livefeedrear
print("After define global in swap_camera") #debugging purpose
print("Before swap")#debugging purpose
# Swap the frames algorithm
video_livefeedfront, video_livefeedrear = video_livefeedrear, video_livefeedfront
print("After Swap") #debugging purpose
def main():
global video_livefeedfront, video_livefeedrear
# Open two camera devices
front_cap = cv2.VideoCapture(0) # Use 0 for the first camera (Front Camera)
rear_cap = cv2.VideoCapture(1) # Use 1 for the second camera (Rear Camera)
# Check if the cameras opened successfully
if not (front_cap.isOpened() and rear_cap.isOpened()):
print("Error: Could not open cameras.")
print("front_cap opened:", front_cap.isOpened())
print("rear_cap opened:", rear_cap.isOpened())
return
# Set the desired width and height for live feed
target_width, target_height = 320, 240
# Set the CAP_PROP_FRAME_WIDTH and CAP_PROP_FRAME_HEIGHT properties for both cameras
front_cap.set(cv2.CAP_PROP_FRAME_WIDTH, target_width)
front_cap.set(cv2.CAP_PROP_FRAME_HEIGHT, target_height)
rear_cap.set(cv2.CAP_PROP_FRAME_WIDTH, target_width)
rear_cap.set(cv2.CAP_PROP_FRAME_HEIGHT, target_height)
# Get the actual dimensions after setting the properties
actual_width1 = int(front_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_height1 = int(front_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
actual_width2 = int(rear_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_height2 = int(rear_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Print camera information with the actual resized dimensions
print_camera_info(actual_width1, actual_height1, "Front")
print_camera_info(actual_width2, actual_height2, "Rear")
# Create Tkinter window
root = tk.Tk()
root.title("Combined Cameras")
# Create a Checkbutton for camera toggle
camera_toggle_button = tk.Checkbutton(root, text="Toggle Camera", command=swap_camera)
camera_toggle_button.grid(row=1, column=1, padx=10, pady=10)
# Create label widget for date and time
datetime_label = tk.Label(root, text="", font=("Helvetica", 14))
datetime_label.grid(row=1, column=2, columnspan=2, pady=10)
# Create label widgets for camera views
label1 = tk.Label(root, text="FRONT VIEW")
label2 = tk.Label(root, text="REAR VIEW")
label1.grid(row=2, column=2)
label2.grid(row=2, column=3)
# Create image labels for camera feeds
video_livefeedfront = tk.Label(root)
video_livefeedrear = tk.Label(root)
video_livefeedfront.grid(row=3, column=2, padx=10)
video_livefeedrear.grid(row=3, column=3, padx=10)
def update_cameras():
# Read frames from both cameras
ret1, frame1 = front_cap.read()
ret2, frame2 = rear_cap.read()
# Check if the frames were read successfully
if not (ret1 and ret2):
print("Error: Could not read frames from cameras.")
# Resize frames to the target dimensions
frame_resized1 = cv2.resize(frame1, (target_width, target_height))
frame_resized2 = cv2.resize(frame2, (target_width, target_height))
# Convert frames to RGB format for PIL
frame_rgb1 = cv2.cvtColor(frame_resized1, cv2.COLOR_BGR2RGB)
frame_rgb2 = cv2.cvtColor(frame_resized2, cv2.COLOR_BGR2RGB)
# Convert frames to PhotoImage format for Tkinter
photo1 = ImageTk.PhotoImage(Image.fromarray(frame_rgb1))
photo2 = ImageTk.PhotoImage(Image.fromarray(frame_rgb2))
# Update image live videofeed
video_livefeedfront.configure(image=photo1)
video_livefeedfront.photo = photo1
video_livefeedrear.configure(image=photo2)
video_livefeedrear.photo = photo2
root.after(25, update_cameras)
# Update the Tkinter window
#root.update()
update_cameras()
root.mainloop()
# Release the camera devices and destroy the Tkinter window
front_cap.release()
rear_cap.release()
cv2.destroyAllWindows()
root.destroy()
if __name__ == "__main__":
main()
purely a programming problem, i.e. your understanding of your own code. this may be using opencv but it’s not an opencv problem.