diff --git a/main.py b/main.py index 57a6547..b2943ad 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,3 @@ -import tkinter as tk -from tkinter import ttk -from process import process_frame -from PIL import Image, ImageTk # Required for displaying images -import cv2 # OpenCV for numpy array to image conversion """ Here’s a detailed prompt you can use to generate the same GUI code anew using a language model: @@ -56,6 +51,12 @@ Please provide a fully functional `gui.py` implementation meeting these requirem This prompt is designed to give the LLM everything it needs to generate the desired `gui.py` code. Let me know if you'd like to adjust it further! """ +import tkinter as tk +from tkinter import ttk +from process import process_frame +from PIL import Image, ImageTk # Required for displaying images +import cv2 # OpenCV for numpy array to image conversion + class OpenCVInterface: def __init__(self, root): self.root = root @@ -68,12 +69,12 @@ class OpenCVInterface: "param2": (0, 400, 25), "minRadius": (0, 100, 5), "maxRadius": (0, 1000, 1000), - "color1_R_min": (0, 255, 0), - "color1_R_max": (0, 255, 0), - "color1_V_min": (0, 255, 0), - "color1_V_max": (0, 255, 0), - "color1_B_min": (0, 255, 0), - "color1_B_max": (0, 255, 0), + "color1_R_min": (0, 64, 5), + "color1_R_max": (0, 64, 5), + "color1_V_min": (0, 64, 5), + "color1_V_max": (0, 64, 5), + "color1_B_min": (0, 64, 5), + "color1_B_max": (0, 64, 5), } self.variables = { @@ -89,24 +90,44 @@ class OpenCVInterface: self.root.columnconfigure(0, weight=1) self.root.columnconfigure(1, weight=1) + # Dropdown for camera selection + camera_frame = ttk.Frame(self.root) + camera_frame.grid(row=0, column=0, sticky="nsew") + self.camera_selection = tk.StringVar() + self.camera_dropdown = ttk.Combobox(camera_frame, textvariable=self.camera_selection) + self.camera_dropdown.grid(row=0, column=0, padx=5, pady=5) + self.populate_camera_dropdown() + # Left Column: Sliders left_frame = ttk.Frame(self.root) - left_frame.grid(row=0, column=0, sticky="nswe") + left_frame.grid(row=1, column=0, sticky="nswe") for var_name, var in self.variables.items(): min_val, max_val, _ = self.variables_config[var_name] self.create_slider(left_frame, var_name, var, min_val, max_val) # Right Column: Image Placeholder - self.image_canvas = tk.Canvas(self.root, bg="gray", width=800, height=600) - self.image_canvas.grid(row=0, column=1, sticky="nswe") + self.image_canvas = tk.Canvas(self.root, bg="gray", width=1024, height=768) + self.image_canvas.grid(row=0, column=1, rowspan=2, sticky="nswe") # Bottom Row: Run Button and Result run_button = ttk.Button(self.root, text="Run", command=self.run_process) - run_button.grid(row=1, column=0, sticky="we") + run_button.grid(row=2, column=0, sticky="we") - self.result_text = tk.Text(self.root, height=10, width=40) - self.result_text.grid(row=1, column=1, sticky="nswe") + self.result_text = tk.Text(self.root, height=5, width=40) + self.result_text.grid(row=2, column=1, sticky="nswe") + + def populate_camera_dropdown(self): + # Detect connected cameras using OpenCV + cameras = [] + for i in range(5): # Check first 5 indexes for cameras + cap = cv2.VideoCapture(i) + if cap.read()[0]: + cameras.append(f"Camera {i}") + cap.release() + self.camera_dropdown["values"] = cameras + if cameras: + self.camera_dropdown.current(0) def create_slider(self, parent, name, variable, min_val, max_val): frame = ttk.Frame(parent) @@ -118,7 +139,7 @@ class OpenCVInterface: def on_slide(value): # Round value to nearest multiple of 5 - rounded_value = round(float(value) / 2) * 2 + rounded_value = round(float(value) / 5) * 5 variable.set(int(rounded_value)) # Update the variable with the rounded value # Slider @@ -137,8 +158,11 @@ class OpenCVInterface: parameters = {key: var.get() for key, var in self.variables.items()} try: + # Get selected camera ID + cam_id = int(self.camera_selection.get().split()[-1]) + # Call process function - image, result_text = process_frame(parameters) + image, result_text = process_frame(parameters, cam_id=cam_id) # Convert OpenCV image (numpy array) to PIL Image for Tkinter display if image is not None: @@ -146,12 +170,13 @@ class OpenCVInterface: pil_image = Image.fromarray(image) # Convert numpy array to PIL Image # Rescale image to fit within 1024x768 while preserving aspect ratio - max_width, max_height = 800, 600 + max_width, max_height = 1024, 768 original_width, original_height = pil_image.size aspect_ratio = min(max_width / original_width, max_height / original_height) new_width = int(original_width * aspect_ratio) new_height = int(original_height * aspect_ratio) pil_image = pil_image.resize((new_width, new_height), Image.Resampling.LANCZOS) + tk_image = ImageTk.PhotoImage(pil_image) # Convert PIL Image to Tkinter Image # Clear canvas and display the image diff --git a/process.py b/process.py index 05445f2..f26cbcb 100644 --- a/process.py +++ b/process.py @@ -16,7 +16,7 @@ TYPE_2 = "___ ___" import cv2 -def capture_frame_from_webcam(): +def capture_frame_from_webcam(cam_id): """ Captures a single frame from the webcam. @@ -24,7 +24,7 @@ def capture_frame_from_webcam(): frame (numpy.ndarray): The captured frame as a NumPy array. """ # Open a connection to the second webcam (index 0) - cap = cv2.VideoCapture(1) + cap = cv2.VideoCapture(cam_id) if not cap.isOpened(): raise Exception("Could not open webcam. Please check your webcam connection.") @@ -50,7 +50,7 @@ class Object: rayon: int -def process_frame(params): +def process_frame(params, cam_id): """ Simulates OpenCV processing using parameters from the GUI. @@ -80,7 +80,7 @@ def process_frame(params): # src = dir_path.joinpath('tests/images/balls-full-small.jpg') # raw_image = cv2.imread(str(src)) - raw_image = capture_frame_from_webcam() + raw_image = capture_frame_from_webcam(cam_id) # 2. Boxing des objets via opencv gray = cv2.cvtColor(raw_image, cv2.COLOR_BGR2GRAY)