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.
This commit is contained in:
tanyar09 2025-10-06 11:53:35 -04:00
parent 38f931a7a7
commit b75e12816c
3 changed files with 86 additions and 29 deletions

View File

@ -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

View File

@ -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"""

View File

@ -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,