diff --git a/dashboard.py b/dashboard.py index dfb1a77..63c5c2b 100644 --- a/dashboard.py +++ b/dashboard.py @@ -3,6 +3,7 @@ import numpy as np import tkinter as tk import matplotlib.pyplot as plt +import helper_functions as hf from area_mapping import mask_deployment, get_tree_mask, get_water_mask from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure @@ -11,33 +12,26 @@ # Function to update the plot based on the image def update_plot(loading=False): overlay = img.copy() - alpha: float = 0.35 + alpha: float = alpha_var.get() + + active_masks = [] - # Apply masks if coast_var.get(): - coast_color_overlay = np.zeros_like(img) - coast_color_overlay[coast_mask > 0] = (174, 235, 52)[::-1] - overlay = cv2.addWeighted(overlay, 1, coast_color_overlay, alpha, 0) + active_masks.append((coast_mask, (174, 235, 52), alpha)) if inland_var.get(): - inland_color_overlay = np.zeros_like(img) - inland_color_overlay[inland_mask > 0] = (245, 130, 37)[::-1] - overlay = cv2.addWeighted(overlay, 1, inland_color_overlay, alpha, 0) + active_masks.append((inland_mask, (245, 130, 37), alpha)) if forest_edge_var.get(): - forest_edge_color_overlay = np.zeros_like(img) - forest_edge_color_overlay[forest_edge_mask > 0] = (81, 153, 14)[::-1] - overlay = cv2.addWeighted(overlay, 1, forest_edge_color_overlay, alpha, 0) + active_masks.append((forest_edge_mask, (81, 153, 14), alpha)) if tree_var.get(): - tree_color_overlay = np.zeros_like(img) - tree_color_overlay[tree_mask > 0] = (66, 191, 50)[::-1] - overlay = cv2.addWeighted(overlay, 1, tree_color_overlay, alpha, 0) + active_masks.append((tree_mask, (66, 191, 50), alpha)) if water_var.get(): - water_color_overlay = np.zeros_like(img) - water_color_overlay[water_mask > 0] = (58, 77, 222)[::-1] - overlay = cv2.addWeighted(overlay, 1, water_color_overlay, alpha, 0) + active_masks.append((water_mask, (58, 77, 222), alpha)) + + overlay = hf.overlay_from_masks(overlay, *active_masks) # Update matplotlib plot ax.clear() @@ -45,7 +39,7 @@ def update_plot(loading=False): # Show "Loading..." text when loading flag is set ax.text(0.5, 0.5, 'Loading...' if loading else "", color='black', fontsize=18, ha='center', va='center', transform=ax.transAxes) - ax.imshow(cv2.cvtColor(overlay, cv2.COLOR_BGR2RGB)) + ax.imshow(overlay) # Display paths if path layer is enabled if path_var.get(): @@ -157,9 +151,13 @@ def update_masks(): # Dropdown menu for selecting an image image_files = [f for f in os.listdir("./mocking_examples") if f.endswith(".png")] image_selection = ttk.Combobox(sidebar, values=image_files, style="TCombobox") -image_selection.pack(padx=10, pady=10) +image_selection.pack(padx=10, pady=(10, 5)) image_selection.bind("<>", load_image) +# Splitter +canvas = tk.Canvas(sidebar, width=150, height=1, bg="gray", bd=0, highlightthickness=0) +canvas.pack(padx=10, pady=10) + # Labels and checkbuttons for masks ttk.Label(sidebar, text="Toggle Layers", style="Dark.TLabel").pack(anchor="w", padx=10, pady=5) ttk.Checkbutton(sidebar, text="Coast Mask", variable=coast_var, style="Dark.TCheckbutton", command=update_plot).pack(anchor="w", padx=10, pady=5) @@ -170,6 +168,21 @@ def update_masks(): ttk.Checkbutton(sidebar, text="Buildings", variable=building_var, style="Dark.TCheckbutton", command=update_plot).pack(anchor="w", padx=10, pady=5) ttk.Checkbutton(sidebar, text="Paths", variable=path_var, style="Dark.TCheckbutton", command=update_plot).pack(anchor="w", padx=10, pady=5) +# Splitter +canvas = tk.Canvas(sidebar, width=150, height=1, bg="gray", bd=0, highlightthickness=0) +canvas.pack(padx=10, pady=10) + +# Title Label +ttk.Label(sidebar, text="Adjust Alpha", style="Dark.TLabel").pack(anchor="w", padx=10, pady=5) + +# Transparency Adjustment Slider +alpha_var = tk.DoubleVar(value=0.35) # Default alpha value +alpha_slider = ttk.Scale( + sidebar, from_=0.0, to=1.0, orient="horizontal", variable=alpha_var, + style="Horizontal.TScale", command=lambda val: update_plot() +) +alpha_slider.pack(anchor="w", padx=10, pady=5) + # Load and display the default image img_path = os.path.join("./mocking_examples", image_files[0]) # Select first image img = cv2.imread(img_path) diff --git a/helper_functions.py b/helper_functions.py index 7e317d8..b6fa94b 100644 --- a/helper_functions.py +++ b/helper_functions.py @@ -111,19 +111,19 @@ def place_buildings(blueprints: list, masks: dict[str, np.ndarray]) -> tuple[lis return placed_buildings, building_mask -def overlay_from_masks(img, *masks: np.ndarray) -> None: - img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) +def overlay_from_masks(img, *masks: np.ndarray) -> np.ndarray: - # Add each mask with its color to the Overlay + img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32) overlay = img_rgb.copy() + for mask, color, alpha in masks: - mask_overlay = img_rgb.copy() - mask_overlay[mask > 0] = color - overlay = cv2.addWeighted(overlay, 1 - alpha, mask_overlay, alpha, 0) - # Blend the overlay with the original image - overlay = cv2.addWeighted(img_rgb, 0, overlay, 1, 0) + mask_color = np.zeros_like(img_rgb, dtype=np.float32) + mask_color[mask > 0] = color + + alpha_mask = (mask > 0).astype(np.float32) * alpha + overlay = overlay * (1 - alpha_mask[..., None]) + mask_color * alpha_mask[..., None] - return overlay + return np.clip(overlay, 0, 255).astype(np.uint8) def filter_artifacts(mask: np.ndarray, min_area_threshold: int = 2500) -> np.ndarray: contours = get_contours(mask)