File size: 6,798 Bytes
4b27b63 3fffbdc 17b2b27 3fffbdc 17b2b27 3b619b1 3fffbdc 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 17b2b27 4b27b63 3fffbdc 4b27b63 17b2b27 4b27b63 17b2b27 4b27b63 3fffbdc 4b27b63 17b2b27 5a504a5 4b27b63 17b2b27 4b27b63 17b2b27 4b27b63 3fffbdc 17b2b27 3fffbdc 17b2b27 3fffbdc 17b2b27 3fffbdc 17b2b27 3fffbdc 17b2b27 4b27b63 3fffbdc 17b2b27 3fffbdc 4b27b63 17b2b27 3fffbdc 3b619b1 3fffbdc 17b2b27 4b27b63 3fffbdc 4b27b63 17b2b27 4b27b63 17b2b27 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 17b2b27 5a504a5 17b2b27 4b27b63 3fffbdc 4b27b63 17b2b27 4b27b63 3fffbdc 17b2b27 4b27b63 3fffbdc 4b27b63 f77f9ee 17b2b27 f77f9ee 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 17b2b27 4b27b63 17b2b27 3fffbdc 17b2b27 4b27b63 3fffbdc 4b27b63 3fffbdc 4b27b63 17b2b27 4b27b63 17b2b27 4b27b63 3fffbdc 4b27b63 17b2b27 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 | #!/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()
|