""" Interactive Region Coordinate Helper Opens an image and helps you find pixel coordinates for colorable regions. Click on the image to see coordinates. Usage: python region_helper.py images/cobrai.jpg """ import sys from PIL import Image, ImageDraw, ImageFont import tkinter as tk from tkinter import Canvas from PIL import ImageTk class RegionHelper: def __init__(self, image_path): self.image_path = image_path self.image = Image.open(image_path) self.width, self.height = self.image.size # Setup UI self.root = tk.Tk() self.root.title(f"Region Helper - {image_path}") # Scale image if too large self.scale = 1.0 max_display_width = 1000 max_display_height = 800 if self.width > max_display_width or self.height > max_display_height: scale_w = max_display_width / self.width scale_h = max_display_height / self.height self.scale = min(scale_w, scale_h) new_width = int(self.width * self.scale) new_height = int(self.height * self.scale) self.display_image = self.image.resize((new_width, new_height), Image.LANCZOS) else: self.display_image = self.image.copy() # Setup canvas self.canvas = Canvas( self.root, width=self.display_image.width, height=self.display_image.height ) self.canvas.pack(side=tk.LEFT) # Display image self.photo = ImageTk.PhotoImage(self.display_image) self.canvas.create_image(0, 0, anchor=tk.NW, image=self.photo) # Info panel info_frame = tk.Frame(self.root, width=300) info_frame.pack(side=tk.RIGHT, fill=tk.BOTH, padx=10, pady=10) tk.Label(info_frame, text="Image Dimensions:", font=('Arial', 12, 'bold')).pack(anchor=tk.W, pady=5) tk.Label(info_frame, text=f"{self.width} x {self.height} pixels").pack(anchor=tk.W) if self.scale != 1.0: tk.Label(info_frame, text=f"Scaled: {self.scale:.2%}").pack(anchor=tk.W) tk.Label(info_frame, text="\nClick to get coordinates:", font=('Arial', 12, 'bold')).pack(anchor=tk.W, pady=(20, 5)) self.coord_label = tk.Label(info_frame, text="X: -, Y: -", font=('Arial', 14)) self.coord_label.pack(anchor=tk.W, pady=5) tk.Label(info_frame, text="\nFirst click = Top-Left", fg='blue').pack(anchor=tk.W) tk.Label(info_frame, text="Second click = Bottom-Right", fg='blue').pack(anchor=tk.W) tk.Label(info_frame, text="\nRegion JSON:", font=('Arial', 12, 'bold')).pack(anchor=tk.W, pady=(20, 5)) self.json_text = tk.Text(info_frame, height=15, width=35, font=('Courier', 9)) self.json_text.pack(fill=tk.BOTH, expand=True) tk.Button(info_frame, text="Clear Points", command=self.clear_points).pack(pady=10) tk.Button(info_frame, text="Copy JSON", command=self.copy_json).pack() # Bind events self.canvas.bind('', self.on_mouse_move) self.canvas.bind('', self.on_click) # Store points self.points = [] self.point_ids = [] self.update_json() def on_mouse_move(self, event): """Show current mouse coordinates.""" x = int(event.x / self.scale) y = int(event.y / self.scale) self.coord_label.config(text=f"X: {x}, Y: {y}") def on_click(self, event): """Record clicked point.""" x = int(event.x / self.scale) y = int(event.y / self.scale) # Limit to 2 points (top-left, bottom-right) if len(self.points) >= 2: self.clear_points() self.points.append((x, y)) # Draw point on canvas color = 'blue' if len(self.points) == 1 else 'red' point_id = self.canvas.create_oval( event.x - 5, event.y - 5, event.x + 5, event.y + 5, fill=color, outline='white', width=2 ) self.point_ids.append(point_id) # Draw rectangle if we have both points if len(self.points) == 2: x1, y1 = self.points[0] x2, y2 = self.points[1] # Draw on canvas (scaled) rect_id = self.canvas.create_rectangle( x1 * self.scale, y1 * self.scale, x2 * self.scale, y2 * self.scale, outline='green', width=2, dash=(5, 5) ) self.point_ids.append(rect_id) self.update_json() def clear_points(self): """Clear all points and rectangles.""" for point_id in self.point_ids: self.canvas.delete(point_id) self.points = [] self.point_ids = [] self.update_json() def update_json(self): """Update the JSON display.""" self.json_text.delete('1.0', tk.END) if len(self.points) == 0: self.json_text.insert('1.0', '{\n "name": "region_name",\n "topLeft": [?, ?],\n "bottomRight": [?, ?],\n "description": "..."\n}') elif len(self.points) == 1: x, y = self.points[0] self.json_text.insert('1.0', f'{{\n "name": "region_name",\n "topLeft": [{x}, {y}],\n "bottomRight": [?, ?],\n "description": "..."\n}}') else: x1, y1 = self.points[0] x2, y2 = self.points[1] # Calculate dimensions width = abs(x2 - x1) height = abs(y2 - y1) json_str = f'''{{\n "name": "region_name",\n "topLeft": [{x1}, {y1}],\n "bottomRight": [{x2}, {y2}],\n "description": "Width: {width}px, Height: {height}px"\n}}''' self.json_text.insert('1.0', json_str) def copy_json(self): """Copy JSON to clipboard.""" json_str = self.json_text.get('1.0', tk.END).strip() self.root.clipboard_clear() self.root.clipboard_append(json_str) self.root.update() def run(self): """Start the GUI.""" self.root.mainloop() if __name__ == '__main__': if len(sys.argv) < 2: print("Usage: python region_helper.py ") print("Example: python region_helper.py images/cobrai.jpg") sys.exit(1) image_path = sys.argv[1] try: helper = RegionHelper(image_path) helper.run() except FileNotFoundError: print(f"Error: Image file not found: {image_path}") sys.exit(1) except Exception as e: print(f"Error: {e}") sys.exit(1)