Saumith commited on
Commit
0f5bc52
·
1 Parent(s): ff3f176

Replace Space with latest LAB1 code

Browse files
Files changed (1) hide show
  1. app.py +27 -28
app.py CHANGED
@@ -1,4 +1,4 @@
1
- import io, time, zipfile, math
2
  from pathlib import Path
3
  from typing import List, Tuple, Optional, Dict
4
 
@@ -9,17 +9,17 @@ from skimage.metrics import structural_similarity as ssim
9
  from skimage.color import rgb2lab
10
  from sklearn.cluster import KMeans
11
 
12
- # ---- Hugging Face dataset: hard-wired ----
13
  from datasets import load_dataset
14
 
15
- HF_DATASET = "benjamin-paine/imagenet-1k-32x32" # always use this
16
  HF_SPLIT = "train"
17
- TILE_LIMIT = 1500 # cap tiles to keep mapping fast; raise if you want
18
- BASE_TILE_SIZE = 32 # dataset images are 32x32
19
 
20
  # Global caches
21
- _TILES_RAW_32: Optional[List[np.ndarray]] = None # list of 32x32 RGB uint8 arrays
22
- _TILE_CACHE_BY_SIZE: Dict[int, Tuple[List[np.ndarray], np.ndarray]] = {} # cell_size -> (tiles_resized, tiles_lab_means)
23
 
24
  # =======================
25
  # Image utils
@@ -53,10 +53,10 @@ def mse(a: np.ndarray, b: np.ndarray) -> float:
53
  return float(np.mean((a.astype(np.float32) - b.astype(np.float32))**2))
54
 
55
  # =======================
56
- # Load & cache tiles from HF dataset (once)
57
  # =======================
58
  def _load_tiles_raw_32(limit: int = TILE_LIMIT) -> List[np.ndarray]:
59
- """Load 32x32 tiles (RGB uint8) from benjamin-paine/imagenet-1k-32x32."""
60
  global _TILES_RAW_32
61
  if _TILES_RAW_32 is not None:
62
  return _TILES_RAW_32
@@ -64,15 +64,16 @@ def _load_tiles_raw_32(limit: int = TILE_LIMIT) -> List[np.ndarray]:
64
  ds = load_dataset(HF_DATASET, split=HF_SPLIT)
65
  tiles = []
66
  for i, ex in enumerate(ds):
67
- if "image" not in ex:
 
68
  continue
69
- img: Image.Image = ex["image"].convert("RGB")
70
- # dataset already 32x32; enforce in case
71
  if img.size != (BASE_TILE_SIZE, BASE_TILE_SIZE):
72
  img = img.resize((BASE_TILE_SIZE, BASE_TILE_SIZE), Image.BILINEAR)
73
  tiles.append(np.asarray(img))
74
- if limit and len(tiles) >= limit:
75
  break
 
76
  if len(tiles) == 0:
77
  raise gr.Error(f"No tiles loaded from {HF_DATASET}.")
78
  _TILES_RAW_32 = tiles
@@ -85,22 +86,20 @@ def _average_color_lab(tile: np.ndarray) -> np.ndarray:
85
  def _tiles_for_cell_size(cell_size: int) -> Tuple[List[np.ndarray], np.ndarray]:
86
  """
87
  Return (tiles_resized, tiles_lab_means) for the requested cell size.
88
- Caches results to avoid recompute on every click.
89
  """
90
  if cell_size in _TILE_CACHE_BY_SIZE:
91
  return _TILE_CACHE_BY_SIZE[cell_size]
92
 
93
  raw_tiles = _load_tiles_raw_32()
94
- # Resize to cell_size if needed
95
  if cell_size == BASE_TILE_SIZE:
96
  tiles_resized = raw_tiles
97
  else:
98
- tiles_resized = [np.asarray(Image.fromarray(t).resize((cell_size, cell_size), Image.BILINEAR))
99
- for t in raw_tiles]
100
-
101
- # LAB means (size does not matter much for mean, but compute on resized set)
102
  tiles_lab = np.array([_average_color_lab(t) for t in tiles_resized], dtype=np.float32)
103
-
104
  _TILE_CACHE_BY_SIZE[cell_size] = (tiles_resized, tiles_lab)
105
  return tiles_resized, tiles_lab
106
 
@@ -167,11 +166,11 @@ def segment_preview(src: np.ndarray, cell: int) -> np.ndarray:
167
  return out.astype(np.uint8)
168
 
169
  # =======================
170
- # Full pipeline (tiles always from HF dataset)
171
  # =======================
172
  def build_mosaic(
173
  input_image: Image.Image,
174
- cell_size: int = 32, # default 32 to match dataset; you can change
175
  use_vectorized: bool = True,
176
  quant_k: int = 0,
177
  similarity_metric: str = "SSIM",
@@ -196,7 +195,7 @@ def build_mosaic(
196
  mean_rgb, R, C = grid_mean_colors_loop(src, cell_size)
197
  t_grid = time.perf_counter() - t0
198
 
199
- # 4) Tiles from HF dataset (cached & resized to cell_size)
200
  tiles, tiles_lab = _tiles_for_cell_size(cell_size)
201
 
202
  # 5) Map & build mosaic
@@ -259,12 +258,12 @@ if not (EXAMPLES_DIR / "gradient1.png").exists():
259
  grad1 = np.dstack([g1, np.flipud(g1).copy(), np.roll(g1, 160, axis=1)])
260
  Image.fromarray(grad1).save(EXAMPLES_DIR/"gradient1.png")
261
 
262
- with gr.Blocks(title="Image Mosaic (ImageNet32 tiles)", css="footer {visibility: hidden}") as demo:
263
  gr.Markdown(
264
  f"""
265
  # 🧩 Image Mosaic Generator (tiles from `{HF_DATASET}`)
266
- - Tiles are auto-loaded from **Hugging Face** dataset: `{HF_DATASET}` (split `{HF_SPLIT}`, limit {TILE_LIMIT}).
267
- - Upload an image and generate a mosaic **immediately** — no extra tile setup.
268
  """
269
  )
270
  with gr.Row():
@@ -275,7 +274,8 @@ with gr.Blocks(title="Image Mosaic (ImageNet32 tiles)", css="footer {visibility:
275
  inputs=[inp],
276
  label="Example"
277
  )
278
- cell = gr.Slider(16, 64, value=32, step=2, label="Grid cell size (px)")
 
279
  quant_k = gr.Slider(0, 24, value=0, step=1, label="Optional color quantization (k-means K)")
280
  similarity = gr.Radio(choices=["SSIM", "MSE"], value="SSIM", label="Similarity metric")
281
  vec = gr.Checkbox(value=True, label="Use vectorized NumPy (uncheck for loop baseline)")
@@ -307,6 +307,5 @@ if __name__ == "__main__":
307
  try:
308
  _load_tiles_raw_32(TILE_LIMIT)
309
  except Exception as e:
310
- # Gradio will still start; you'll see an error if tiles can't be loaded
311
  print("Warning: failed to preload tiles:", e)
312
  demo.launch()
 
1
+ import time
2
  from pathlib import Path
3
  from typing import List, Tuple, Optional, Dict
4
 
 
9
  from skimage.color import rgb2lab
10
  from sklearn.cluster import KMeans
11
 
12
+ # ---- Hugging Face dataset: hard-wired to CIFAR-100 ----
13
  from datasets import load_dataset
14
 
15
+ HF_DATASET = "uoft-cs/cifar100" # tiles come from here
16
  HF_SPLIT = "train"
17
+ TILE_LIMIT = 0 # cap to keep mapping fast (adjust as needed)
18
+ BASE_TILE_SIZE = 32 # CIFAR-100 images are 32x32
19
 
20
  # Global caches
21
+ _TILES_RAW_32: Optional[List[np.ndarray]] = None # list of 32x32 RGB uint8 arrays
22
+ _TILE_CACHE_BY_SIZE: Dict[int, Tuple[List[np.ndarray], np.ndarray]] = {} # size -> (tiles_resized, lab_means)
23
 
24
  # =======================
25
  # Image utils
 
53
  return float(np.mean((a.astype(np.float32) - b.astype(np.float32))**2))
54
 
55
  # =======================
56
+ # CIFAR-100: load & cache base tiles (32x32)
57
  # =======================
58
  def _load_tiles_raw_32(limit: int = TILE_LIMIT) -> List[np.ndarray]:
59
+ """Load 32x32 tiles (RGB uint8) from CIFAR-100 (uoft-cs/cifar100)."""
60
  global _TILES_RAW_32
61
  if _TILES_RAW_32 is not None:
62
  return _TILES_RAW_32
 
64
  ds = load_dataset(HF_DATASET, split=HF_SPLIT)
65
  tiles = []
66
  for i, ex in enumerate(ds):
67
+ # CIFAR-100 column name is "img"
68
+ if "img" not in ex:
69
  continue
70
+ img: Image.Image = ex["img"].convert("RGB")
 
71
  if img.size != (BASE_TILE_SIZE, BASE_TILE_SIZE):
72
  img = img.resize((BASE_TILE_SIZE, BASE_TILE_SIZE), Image.BILINEAR)
73
  tiles.append(np.asarray(img))
74
+ if limit > 0 and len(tiles) >= limit:
75
  break
76
+
77
  if len(tiles) == 0:
78
  raise gr.Error(f"No tiles loaded from {HF_DATASET}.")
79
  _TILES_RAW_32 = tiles
 
86
  def _tiles_for_cell_size(cell_size: int) -> Tuple[List[np.ndarray], np.ndarray]:
87
  """
88
  Return (tiles_resized, tiles_lab_means) for the requested cell size.
89
+ Caches results to avoid recomputation on each run.
90
  """
91
  if cell_size in _TILE_CACHE_BY_SIZE:
92
  return _TILE_CACHE_BY_SIZE[cell_size]
93
 
94
  raw_tiles = _load_tiles_raw_32()
 
95
  if cell_size == BASE_TILE_SIZE:
96
  tiles_resized = raw_tiles
97
  else:
98
+ tiles_resized = [
99
+ np.asarray(Image.fromarray(t).resize((cell_size, cell_size), Image.BILINEAR))
100
+ for t in raw_tiles
101
+ ]
102
  tiles_lab = np.array([_average_color_lab(t) for t in tiles_resized], dtype=np.float32)
 
103
  _TILE_CACHE_BY_SIZE[cell_size] = (tiles_resized, tiles_lab)
104
  return tiles_resized, tiles_lab
105
 
 
166
  return out.astype(np.uint8)
167
 
168
  # =======================
169
+ # Full pipeline (tiles always from CIFAR-100)
170
  # =======================
171
  def build_mosaic(
172
  input_image: Image.Image,
173
+ cell_size: int = 32,
174
  use_vectorized: bool = True,
175
  quant_k: int = 0,
176
  similarity_metric: str = "SSIM",
 
195
  mean_rgb, R, C = grid_mean_colors_loop(src, cell_size)
196
  t_grid = time.perf_counter() - t0
197
 
198
+ # 4) Tiles from CIFAR-100 (cached & resized to cell_size)
199
  tiles, tiles_lab = _tiles_for_cell_size(cell_size)
200
 
201
  # 5) Map & build mosaic
 
258
  grad1 = np.dstack([g1, np.flipud(g1).copy(), np.roll(g1, 160, axis=1)])
259
  Image.fromarray(grad1).save(EXAMPLES_DIR/"gradient1.png")
260
 
261
+ with gr.Blocks(title="Image Mosaic (CIFAR-100 tiles)", css="footer {visibility: hidden}") as demo:
262
  gr.Markdown(
263
  f"""
264
  # 🧩 Image Mosaic Generator (tiles from `{HF_DATASET}`)
265
+ - Tiles auto-loaded from **Hugging Face** dataset: `{HF_DATASET}` (split `{HF_SPLIT}`, limit {TILE_LIMIT}).
266
+ - Upload an image and generate a mosaic immediately.
267
  """
268
  )
269
  with gr.Row():
 
274
  inputs=[inp],
275
  label="Example"
276
  )
277
+ cell = gr.Slider(16, 128, value=32, step=2, label="Grid cell size (px)")
278
+
279
  quant_k = gr.Slider(0, 24, value=0, step=1, label="Optional color quantization (k-means K)")
280
  similarity = gr.Radio(choices=["SSIM", "MSE"], value="SSIM", label="Similarity metric")
281
  vec = gr.Checkbox(value=True, label="Use vectorized NumPy (uncheck for loop baseline)")
 
307
  try:
308
  _load_tiles_raw_32(TILE_LIMIT)
309
  except Exception as e:
 
310
  print("Warning: failed to preload tiles:", e)
311
  demo.launch()