Saumith's picture
Update app.py
17b2b27 verified
#!/usr/bin/env python3
"""
app.py — Optimised Mosaic Generator (Lab 5)
This powers the Gradio Space using:
- 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 (Load CIFAR tiles ONCE per Space launch)
# -------------------------------------------------------------
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
):
"""Full mosaic generation pipeline with error handling."""
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 image
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}"
# LAB conversion + mean colors
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 conversion failed: {e}"
w, h, cell_w, cell_h = dims
# Prepare cached scaled tiles
TM.prepare_scaled_tiles(cell_w, cell_h)
# Find best matching tiles (FAISS)
try:
idxs = TM.lookup_tiles(cell_means)
except Exception as e:
return None, None, None, f"Tile lookup failed: {e}"
# Build mosaic
builder = MosaicBuilder(TM)
try:
mosaic_np = builder.build(idxs, dims, grid_n)
t2 = time.perf_counter()
except Exception as e:
return None, None, None, f"Mosaic build failed: {e}"
# Metrics
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
# Build 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 + OpenCV + LAB mosaic generator.\n")
with gr.Row():
# ----------------------------------------------------
# LEFT COLUMN (INPUTS)
# ----------------------------------------------------
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 (cells per side)"
)
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 Overlay")
run_btn = gr.Button("Generate Mosaic", variant="primary")
# ----------------------------------------------------
# EXAMPLE IMAGES (LOADED FROM REPO ROOT)
# ----------------------------------------------------
gr.Markdown("### Example Images")
example_files = [
"725px-Mona_Lisa_by_Leonardo_da_Vinci_from_C2RMF_retouched-e1660680153902.webp",
"WhatsApp Image 2025-11-08 at 01.39.58_cddcf540.jpg",
]
example_list = [[f] for f in example_files]
gr.Examples(
examples=example_list,
inputs=[img_in],
label="",
cache_examples=False, # required for HF Spaces
)
# ----------------------------------------------------
# RIGHT COLUMN (OUTPUTS)
# ----------------------------------------------------
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 Output"):
img_mosaic = gr.Image()
report = gr.Textbox(label="Timing & Metrics", lines=12)
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 APP
# -------------------------------------------------------------
if __name__ == "__main__":
demo = build_demo()
demo.launch()