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: --- **Prompt:** "I need a Python program to create a Tkinter-based GUI named 'Yiking'. The GUI will control parameters for an OpenCV image processing program. The program must be split into two files: 1. **`process.py`**: Contains a `process_frame` function that takes parameters as input, performs OpenCV operations (not implemented in this request), and returns an image as a NumPy array and a result string. 2. **`gui.py`**: Implements the GUI and integrates with `process.py`. Here are the detailed requirements: ### GUI Details: - **Window Title**: 'Yiking' - **Layout**: - **Row 1**: Two columns - Left column: Group of sliders for controlling parameters. - Right column: A canvas for displaying a processed image (1024x768 pixels). - **Row 2**: Two columns - Left column: A "Run" button. - Right column: A text box for displaying results or error messages. - **Widgets**: - Sliders with corresponding min, max, and default values: - `minDist` = (0, 500, 100) - `param1` = (0, 500, 30) - `param2` = (0, 400, 25) - `minRadius` = (0, 100, 5) - `maxRadius` = (0, 1000, 1000) - `color1_R_min` = (0, 64, 5) - `color1_V_min` = (0, 64, 5) - `color1_B_min` = (0, 64, 5) - `color1_R_min` = (0, 64, 5) - `color1_V_min` = (0, 64, 5) - `color1_B_min` = (0, 64, 5) - Sliders must snap to increments of 5 and synchronize with a text entry box. - The image canvas must resize input images to fit within 1024x768 while maintaining aspect ratio. - A "Run" button executes the `process_frame` function with the current slider values. - If an exception occurs in `process_frame`, it should display the error in the result text box and clear the canvas. ### Key Features: - Use the `Pillow` library (`PIL`) to handle image conversion and resizing. - Catch exceptions in `run_process` to display error messages. - Keep the GUI responsive and visually clean. ### Output: Please provide a fully functional `gui.py` implementation meeting these requirements. Include imports, class structure, and the `__main__` block. Do not implement the OpenCV functionality within `process.py`—assume it exists for integration purposes." --- 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! """ class OpenCVInterface: def __init__(self, root): self.root = root self.root.title("Yiking") # Variables for sliders with min, max, and default values self.variables_config = { "minDist": (0, 500, 100), "param1": (0, 500, 30), "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), } self.variables = { name: tk.IntVar(value=config[2]) for name, config in self.variables_config.items() } # GUI Layout self.setup_gui() def setup_gui(self): # Root grid layout self.root.rowconfigure(1, weight=1) self.root.columnconfigure(0, weight=1) self.root.columnconfigure(1, weight=1) # Left Column: Sliders left_frame = ttk.Frame(self.root) left_frame.grid(row=0, 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=1024, height=768) self.image_canvas.grid(row=0, column=1, 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") self.result_text = tk.Text(self.root, height=10, width=40) self.result_text.grid(row=1, column=1, sticky="nswe") def create_slider(self, parent, name, variable, min_val, max_val): frame = ttk.Frame(parent) frame.pack(fill="x", padx=5, pady=2) # Label label = ttk.Label(frame, text=name) label.pack(side="left") def on_slide(value): # Round value to nearest multiple of 5 rounded_value = round(float(value) / 2) * 2 variable.set(int(rounded_value)) # Update the variable with the rounded value # Slider slider = ttk.Scale( frame, from_=min_val, to=max_val, variable=variable, orient="horizontal", command=on_slide ) slider.pack(side="left", fill="x", expand=True, padx=5) # Entry box entry = ttk.Entry(frame, textvariable=variable, width=5) entry.pack(side="left") def run_process(self): # Collect slider values parameters = {key: var.get() for key, var in self.variables.items()} try: # Call process function image, result_text = process_frame(parameters) # Convert OpenCV image (numpy array) to PIL Image for Tkinter display if image is not None: image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Convert BGR to RGB 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 = 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 self.image_canvas.delete("all") self.image_canvas.create_image(512, 384, image=tk_image, anchor="center") self.image_canvas.image = tk_image # Keep a reference to prevent garbage collection # Update result text self.result_text.delete(1.0, tk.END) self.result_text.insert(tk.END, result_text) except Exception as exc: # Handle and display exceptions self.result_text.delete(1.0, tk.END) self.result_text.insert(tk.END, str(exc)) self.image_canvas.delete("all") if __name__ == "__main__": root = tk.Tk() app = OpenCVInterface(root) root.mainloop()