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,