File size: 6,546 Bytes
4b27b63 3fffbdc 3b619b1 3fffbdc 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 3b619b1 4b27b63 3fffbdc 4b27b63 3b619b1 4b27b63 3b619b1 4b27b63 3fffbdc 4b27b63 3b619b1 5a504a5 4b27b63 3b619b1 4b27b63 f77f9ee 4b27b63 3fffbdc f77f9ee 3fffbdc 3b619b1 3fffbdc 3b619b1 3fffbdc 3b619b1 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 3b619b1 3fffbdc 3b619b1 3fffbdc f77f9ee 4b27b63 3fffbdc 4b27b63 3b619b1 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 3b619b1 5a504a5 3b619b1 4b27b63 3fffbdc 4b27b63 f77f9ee 4b27b63 3fffbdc 3b619b1 4b27b63 3fffbdc 4b27b63 f77f9ee 3b619b1 f77f9ee 4b27b63 3fffbdc 4b27b63 3fffbdc 3b619b1 3fffbdc 4b27b63 3fffbdc 4b27b63 3b619b1 3fffbdc 3b619b1 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 3b619b1 4b27b63 3fffbdc 4b27b63 3b619b1 3fffbdc 3b619b1 4b27b63 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | #!/usr/bin/env python3
"""
app.py
Gradio interface for the Optimised Mosaic Generator (Lab 5).
Loads CIFAR tiles once, then performs fast LAB-based matching using FAISS.
Connects UI to:
- crop_to_multiple()
- compute_cell_means_lab()
- TileManager
- MosaicBuilder
- MSE / SSIM metrics
"""
import gradio as gr
import numpy as np
import time
import os
from PIL import Image, ImageDraw
from mosaic_generator.image_processor import crop_to_multiple, compute_cell_means_lab
from mosaic_generator.tile_manager import TileManager
from mosaic_generator.mosaic_builder import MosaicBuilder
from mosaic_generator.metrics import mse, ssim_rgb
# ---------------------------------------------------------------
# GLOBAL TILE MANAGER — Loaded ONCE for entire HuggingFace Space
# ---------------------------------------------------------------
TM = TileManager()
TM.load(sample_size=20000)
# ---------------------------------------------------------------
# MAIN PIPELINE
# ---------------------------------------------------------------
def run_pipeline(
img, grid_size, tile_px, tile_sample,
quantize_on, quantize_colors, show_grid
):
"""
Runs full mosaic generation pipeline.
Returns:
original image (PIL)
segmented grid image (PIL)
mosaic image (PIL)
report string
"""
if img is None:
return None, None, None, "Upload an image first."
img_np = np.array(img.convert("RGB"))
grid_n = int(grid_size)
# --- Crop to perfect grid ---
base = crop_to_multiple(img_np, grid_n)
# --- Optional quantization ---
if quantize_on:
try:
q = Image.fromarray(base).quantize(
colors=int(quantize_colors),
method=Image.MEDIANCUT,
dither=Image.Dither.NONE
).convert("RGB")
base = np.array(q)
except Exception as e:
return None, None, None, f"Quantization failed: {e}"
# --- Compute LAB means ---
try:
t0 = time.perf_counter()
cell_means, dims = compute_cell_means_lab(base, grid_n)
t1 = time.perf_counter()
except Exception as e:
return None, None, None, f"LAB computation failed: {e}"
w, h, cell_w, cell_h = dims
# --- Prepare FAISS tiles ---
TM.prepare_scaled_tiles(cell_w, cell_h)
# --- Lookup nearest tiles ---
try:
idxs = TM.lookup_tiles(cell_means)
except Exception as e:
return None, None, None, f"Tile lookup failed: {e}"
# --- Build final mosaic ---
builder = MosaicBuilder(TM)
try:
mosaic_np = builder.build(idxs, dims, grid_n)
except Exception as e:
return None, None, None, f"Mosaic build failed: {e}"
t2 = time.perf_counter()
# --- Compute metrics (safe fallback) ---
try:
mse_val = mse(base, mosaic_np)
ssim_val = ssim_rgb(base, mosaic_np)
except:
mse_val, ssim_val = -1, -1
# --- Optional grid overlay ---
segmented = Image.fromarray(base)
if show_grid:
seg = segmented.copy()
draw = ImageDraw.Draw(seg)
for x in range(0, w, cell_w):
draw.line([(x, 0), (x, h)], fill="red", width=1)
for y in range(0, h, cell_h):
draw.line([(0, y), (w, y)], fill="red", width=1)
segmented = seg
# --- Text report ---
report = (
f"MSE: {mse_val:.2f}\n"
f"SSIM: {ssim_val:.4f}\n\n"
f"Preprocessing Time: {t1 - t0:.3f}s\n"
f"Mosaic Build Time: {t2 - t1:.3f}s\n"
f"Total Time: {t2 - t0:.3f}s\n"
)
return (
Image.fromarray(base),
segmented,
Image.fromarray(mosaic_np),
report
)
# ---------------------------------------------------------------
# GRADIO UI
# ---------------------------------------------------------------
def build_demo():
with gr.Blocks(title="High-Performance Mosaic Generator") as demo:
gr.Markdown("# ⚡ High-Performance Mosaic Generator (Lab 5)")
gr.Markdown("Ultra-fast FAISS-powered image mosaic generator.\n")
with gr.Row():
# ---------------- LEFT PANEL ----------------
with gr.Column(scale=1):
img_in = gr.Image(type="pil", label="Upload Image")
grid_size = gr.Radio(
["16", "32", "64", "128"],
value="32",
label="Grid Size"
)
tile_px = gr.Radio(
["8", "16", "24", "32"],
value="16",
label="Tile Resolution (px)"
)
tile_sample = gr.Slider(
512, 20000, step=256, value=2048,
label="Tile Sample Size"
)
quantize_on = gr.Checkbox(True, label="Enable Color Quantization")
quantize_colors = gr.Slider(
8, 128, value=32, step=8,
label="Quantization Palette Size"
)
show_grid = gr.Checkbox(True, label="Show Grid")
run_btn = gr.Button("Generate Mosaic", variant="primary")
# ---------------------------------------------------
# EXAMPLES REMOVED (HF blocks external URLs)
# ---------------------------------------------------
gr.Markdown(
"### Example Images\n"
"⚠️ Disabled on Hugging Face due to security restrictions.\n"
"Please upload your own image."
)
# ---------------- RIGHT PANEL ----------------
with gr.Column(scale=2):
with gr.Tab("Original"):
img_orig = gr.Image()
with gr.Tab("Grid View"):
img_seg = gr.Image()
with gr.Tab("Mosaic"):
img_mosaic = gr.Image()
report = gr.Textbox(label="Timing & Metrics", lines=10)
# Connect button
run_btn.click(
fn=run_pipeline,
inputs=[img_in, grid_size, tile_px, tile_sample,
quantize_on, quantize_colors, show_grid],
outputs=[img_orig, img_seg, img_mosaic, report]
)
return demo
# ---------------------------------------------------------------
# LAUNCH
# ---------------------------------------------------------------
if __name__ == "__main__":
demo = build_demo()
demo.launch()
|