From b75e12816ccf0742c6dcc333f980404effe44f82 Mon Sep 17 00:00:00 2001 From: tanyar09 Date: Mon, 6 Oct 2025 11:53:35 -0400 Subject: [PATCH] Refactor AutoMatchGUI layout and enhance confidence display This commit refines the layout of the AutoMatchGUI by adjusting the positioning of elements for better usability. The photo icon placement is now calculated based on the actual image dimensions, ensuring accurate positioning. Additionally, a new confidence badge feature is introduced, providing a visual representation of confidence levels alongside filenames. The layout adjustments improve the overall user experience by ensuring that images and related information are displayed more intuitively. The IdentifyGUI is also updated to reflect similar layout enhancements for consistency across the application. --- auto_match_gui.py | 39 +++++++++++++++++++++++---------------- gui_core.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ identify_gui.py | 31 ++++++++++++++++++------------- 3 files changed, 86 insertions(+), 29 deletions(-) diff --git a/auto_match_gui.py b/auto_match_gui.py index 52817d0..fa937a3 100644 --- a/auto_match_gui.py +++ b/auto_match_gui.py @@ -677,10 +677,12 @@ class AutoMatchGUI: matched_canvas.image = photo # Add photo icon to the matched person face - exactly in corner - # Use actual image dimensions instead of assuming 300x300 + # Compute top-left of the centered image for accurate placement actual_width, actual_height = pil_image.size + top_left_x = 150 - (actual_width // 2) + top_left_y = 150 - (actual_height // 2) self.gui_core.create_photo_icon(matched_canvas, matched_photo_path, icon_size=20, - face_x=150, face_y=150, + face_x=top_left_x, face_y=top_left_y, face_width=actual_width, face_height=actual_height, canvas_width=300, canvas_height=300) except Exception as e: @@ -755,27 +757,21 @@ class AutoMatchGUI: # Configure match frame for grid layout match_frame.columnconfigure(0, weight=0) # Checkbox column - fixed width - match_frame.columnconfigure(1, weight=1) # Text column - expandable - match_frame.columnconfigure(2, weight=0) # Image column - fixed width + match_frame.columnconfigure(1, weight=0) # Image column - fixed width + match_frame.columnconfigure(2, weight=1) # Text column - expandable # Checkbox without text checkbox = ttk.Checkbutton(match_frame, variable=match_var) checkbox.grid(row=0, column=0, rowspan=2, sticky=(tk.W, tk.N), padx=(0, 5)) match_checkboxes.append(checkbox) - # Create labels for confidence and filename - confidence_label = ttk.Label(match_frame, text=f"{confidence_pct:.1f}% {confidence_desc}", font=("Arial", 9, "bold")) - confidence_label.grid(row=0, column=1, sticky=tk.W, padx=(0, 10)) - - filename_label = ttk.Label(match_frame, text=f"📁 {match['unidentified_filename']}", font=("Arial", 8), foreground="gray") - filename_label.grid(row=1, column=1, sticky=tk.W, padx=(0, 10)) - - # Unidentified face image + # Unidentified face image now immediately after checkbox (right panel face to the right of checkbox) + match_canvas = None if show_faces: style = ttk.Style() canvas_bg_color = style.lookup('TFrame', 'background') or '#d9d9d9' match_canvas = tk.Canvas(match_frame, width=100, height=100, bg=canvas_bg_color, highlightthickness=0) - match_canvas.grid(row=0, column=2, rowspan=2, sticky=(tk.W, tk.N), padx=(10, 0)) + match_canvas.grid(row=0, column=1, rowspan=2, sticky=(tk.W, tk.N), padx=(5, 10)) unidentified_crop_path = self.face_processor._extract_face_crop( unidentified_photo_path, @@ -791,15 +787,25 @@ class AutoMatchGUI: match_canvas.create_image(50, 50, image=photo) match_canvas.image = photo - # Add photo icon to the unidentified face + # Add photo icon exactly at top-right of the face area self.gui_core.create_photo_icon(match_canvas, unidentified_photo_path, icon_size=15, - face_x=50, face_y=50, + face_x=0, face_y=0, face_width=100, face_height=100, canvas_width=100, canvas_height=100) - except Exception as e: + except Exception: match_canvas.create_text(50, 50, text="❌", fill="red") else: match_canvas.create_text(50, 50, text="🖼️", fill="gray") + + # Confidence badge and filename to the right of image + info_container = ttk.Frame(match_frame) + info_container.grid(row=0, column=2, rowspan=2, sticky=(tk.W, tk.E)) + + badge = self.gui_core.create_confidence_badge(info_container, confidence_pct) + badge.pack(anchor=tk.W) + + filename_label = ttk.Label(info_container, text=f"📁 {match['unidentified_filename']}", font=("Arial", 8), foreground="gray") + filename_label.pack(anchor=tk.W, pady=(2, 0)) # Update Select All / Clear All button states after populating update_match_control_buttons_state() @@ -892,3 +898,4 @@ class AutoMatchGUI: data_cache['photo_paths'] = {row[0]: row[1] for row in cursor.fetchall()} return data_cache + diff --git a/gui_core.py b/gui_core.py index 5fa592f..dce7fc4 100644 --- a/gui_core.py +++ b/gui_core.py @@ -172,6 +172,51 @@ class GUICore: return tooltip # Return tooltip reference for cleanup if needed + def create_confidence_badge(self, parent, confidence_pct: float): + """Create a colorful confidence badge with percentage and label. + Returns a frame containing a small colored circle (with percent) and a text label. + """ + import tkinter as tk + from tkinter import ttk + + # Determine color and label + if confidence_pct >= 80: + color = "#27AE60" # green + label = "Very High" + text_color = "white" + elif confidence_pct >= 70: + color = "#F1C40F" # yellow + label = "High" + text_color = "black" + elif confidence_pct >= 60: + color = "#E67E22" # orange + label = "Medium" + text_color = "white" + elif confidence_pct >= 50: + color = "#E74C3C" # red + label = "Low" + text_color = "white" + else: + color = "#2C3E50" # dark blue/black + label = "Very Low" + text_color = "white" + + badge_frame = ttk.Frame(parent) + + # Draw circle sized to roughly match the label font height + size = 14 + style = ttk.Style() + bg_color = style.lookup('TFrame', 'background') or '#d9d9d9' + canvas = tk.Canvas(badge_frame, width=size, height=size, highlightthickness=0, bg=bg_color) + canvas.grid(row=0, column=0, padx=(0, 4)) + canvas.create_oval(1, 1, size-1, size-1, fill=color, outline=color) + + # Text label right to the circle + label_widget = ttk.Label(badge_frame, text=f"{int(round(confidence_pct))}% {label}", font=("Arial", 9, "bold")) + label_widget.grid(row=0, column=1, sticky="w") + + return badge_frame + def create_face_crop_image(self, photo_path: str, face_location: tuple, face_id: int, crop_size: int = 100) -> Optional[str]: """Create a face crop image for display""" diff --git a/identify_gui.py b/identify_gui.py index 3520d6b..6679cdf 100644 --- a/identify_gui.py +++ b/identify_gui.py @@ -1539,12 +1539,23 @@ class IdentifyGUI: # Add to similar face variables list similar_face_vars.append((similar_face_id, match_var)) - # Create labels for confidence and filename - confidence_label = ttk.Label(match_frame, text=f"{confidence_pct:.1f}% {confidence_desc}", font=("Arial", 9, "bold")) - confidence_label.grid(row=0, column=2, sticky=tk.W, padx=(0, 10)) + # Right panel requirement: image immediately to the right of checkbox + # Create canvas for face image next to checkbox + style = ttk.Style() + canvas_bg_color = style.lookup('TFrame', 'background') or '#d9d9d9' + match_canvas = tk.Canvas(match_frame, width=80, height=80, bg=canvas_bg_color, highlightthickness=0) + match_canvas.grid(row=0, column=1, rowspan=2, sticky=(tk.W, tk.N), padx=(5, 10)) - filename_label = ttk.Label(match_frame, text=f"📁 {filename}", font=("Arial", 8), foreground="gray") - filename_label.grid(row=1, column=2, sticky=tk.W, padx=(0, 10)) + # Create labels container to the right of image + info_container = ttk.Frame(match_frame) + info_container.grid(row=0, column=2, rowspan=2, sticky=(tk.W, tk.E)) + + # Confidence badge + badge = self.gui_core.create_confidence_badge(info_container, confidence_pct) + badge.pack(anchor=tk.W) + + filename_label = ttk.Label(info_container, text=f"📁 {filename}", font=("Arial", 8), foreground="gray") + filename_label.pack(anchor=tk.W, pady=(2, 0)) # Face image (reusing auto-match image display) try: @@ -1568,20 +1579,14 @@ class IdentifyGUI: # Extract face crop using existing method face_crop_path = self.face_processor._extract_face_crop(photo_path, face_data['location'], similar_face_id) if face_crop_path and os.path.exists(face_crop_path): - # Create canvas for face image (like in auto-match) - style = ttk.Style() - canvas_bg_color = style.lookup('TFrame', 'background') or '#d9d9d9' - match_canvas = tk.Canvas(match_frame, width=80, height=80, bg=canvas_bg_color, highlightthickness=0) - match_canvas.grid(row=0, column=1, rowspan=2, sticky=(tk.W, tk.N), padx=(5, 10)) - - # Load and display image (reusing auto-match image loading) + # Load and display image pil_image = Image.open(face_crop_path) pil_image.thumbnail((80, 80), Image.Resampling.LANCZOS) photo = ImageTk.PhotoImage(pil_image) match_canvas.create_image(40, 40, image=photo) match_canvas.image = photo # Keep reference - # Add photo icon to the similar face + # Add photo icon exactly at the image's top-right corner self.gui_core.create_photo_icon(match_canvas, photo_path, icon_size=15, face_x=0, face_y=0, face_width=80, face_height=80,