meryadri commited on
Commit
8edf546
·
1 Parent(s): c422481

intermediary changes

Browse files
__pycache__/mosaic.cpython-313.pyc ADDED
Binary file (4.97 kB). View file
 
app.py CHANGED
@@ -3,35 +3,65 @@ import cv2
3
  import numpy as np
4
  from PIL import Image
5
  import os
6
- from logic.imgPreprocess import resize_img
 
 
 
7
 
8
- def preprocess_image(image: Image.Image, size: int):
9
- # Resize using the resize_img function directly on the PIL Image
 
 
 
10
  resized_np = resize_img(image, size=(size, size))
11
- # Convert back to RGB for display (cv2 uses BGR)
12
- resized_rgb = cv2.cvtColor(resized_np, cv2.COLOR_BGR2RGB)
13
- return Image.fromarray(resized_rgb)
14
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  # Only show example images for upload, no grid or extra info
17
  example_dir = "data/images"
18
  example_files = [os.path.join(example_dir, f) for f in [
19
  "bird.JPG", "cheetah.JPG", "lion.JPG", "oryx.JPG", "ostrich.JPG", "rhino.JPG", "zebra.JPG"
20
  ]]
 
21
 
22
- inputs = [
23
- gr.Image(type="pil", label="Upload or Select Example Image"),
24
- ]
25
-
26
- outputs = gr.Image(type="pil", label="Resized Image")
27
-
28
- examples = [[f, 400] for f in example_files]
 
 
 
 
 
 
 
 
 
29
 
30
- demo = gr.Interface(
31
- fn=preprocess_image,
32
- inputs=inputs,
33
- outputs=outputs,
34
- examples=examples,
35
- title="Image Resizer"
36
- )
37
  demo.launch()
 
3
  import numpy as np
4
  from PIL import Image
5
  import os
6
+ from logic.imgPreprocess import resize_img, color_quantize
7
+ from logic.imgGrid import segment_image_grid
8
+ from logic.tileMapping import load_tile_images, map_tiles_to_grid
9
+ from logic.perfMetric import mse, ssim_metric, timed
10
 
11
+ def preprocess_and_mosaic(image: Image.Image, size: int, grid_size: int, n_colors: int):
12
+ # Apply color quantization
13
+ quantized_img, color_centers = color_quantize(image, n_colors)
14
+ image = Image.fromarray(cv2.cvtColor(quantized_img, cv2.COLOR_BGR2RGB))
15
+ # Resize image
16
  resized_np = resize_img(image, size=(size, size))
17
+ cell_size = size // grid_size
18
+ crop_size = cell_size * grid_size
19
+ # Crop resized image to match mosaic size
20
+ resized_np_cropped = resized_np[:crop_size, :crop_size]
21
+ # Segment grid and classify colors
22
+ grid_labels, seg_time = timed(segment_image_grid)(resized_np_cropped, grid_size, color_centers)
23
+ # Load/generate tiles
24
+ tiles = load_tile_images('data/tiles', n_colors, cell_size)
25
+ # Map tiles to grid
26
+ mosaic_img, mosaic_time = timed(map_tiles_to_grid)(grid_labels, tiles, cell_size)
27
+ # Metrics
28
+ mse_val = mse(resized_np_cropped, mosaic_img)
29
+ ssim_val = ssim_metric(resized_np_cropped, mosaic_img)
30
+ # Convert for display
31
+ orig_disp = Image.fromarray(cv2.cvtColor(resized_np_cropped, cv2.COLOR_BGR2RGB))
32
+ mosaic_disp = Image.fromarray(cv2.cvtColor(mosaic_img, cv2.COLOR_BGR2RGB))
33
+ # Segmented image: show each cell as its cluster color
34
+ seg_img = np.zeros_like(resized_np_cropped)
35
+ for i in range(grid_size):
36
+ for j in range(grid_size):
37
+ seg_img[i*cell_size:(i+1)*cell_size, j*cell_size:(j+1)*cell_size] = color_centers[grid_labels[i,j]]
38
+ seg_disp = Image.fromarray(cv2.cvtColor(seg_img, cv2.COLOR_BGR2RGB))
39
+ # Info
40
+ info = f"MSE: {mse_val:.2f}\nSSIM: {ssim_val:.3f}\nSegmentation: {seg_time:.3f}s\nMosaic: {mosaic_time:.3f}s"
41
+ return orig_disp, seg_disp, mosaic_disp, info
42
 
43
  # Only show example images for upload, no grid or extra info
44
  example_dir = "data/images"
45
  example_files = [os.path.join(example_dir, f) for f in [
46
  "bird.JPG", "cheetah.JPG", "lion.JPG", "oryx.JPG", "ostrich.JPG", "rhino.JPG", "zebra.JPG"
47
  ]]
48
+ examples = [[f, 400, 32, 8] for f in example_files]
49
 
50
+ with gr.Blocks() as demo:
51
+ gr.Markdown("# Image Mosaic Generator")
52
+ with gr.Row():
53
+ image_input = gr.Image(type="pil", label="Upload or Select Example Image")
54
+ size_slider = gr.Slider(100, 800, value=400, step=10, label="Resize (pixels)")
55
+ grid_slider = gr.Slider(8, 64, value=32, step=1, label="Grid Size (NxN)")
56
+ color_slider = gr.Slider(2, 16, value=8, step=1, label="Number of Colors (Quantization)")
57
+ mosaic_btn = gr.Button("Generate Mosaic")
58
+ with gr.Row():
59
+ orig_out = gr.Image(label="Original (Resized)")
60
+ seg_out = gr.Image(label="Segmented Grid")
61
+ mosaic_out = gr.Image(label="Mosaic Image")
62
+ info_out = gr.Textbox(label="Metrics & Timing", interactive=False)
63
+ gr.Examples(examples=examples, inputs=[image_input, size_slider, grid_slider, color_slider], label="Example Images")
64
+
65
+ mosaic_btn.click(preprocess_and_mosaic, inputs=[image_input, size_slider, grid_slider, color_slider], outputs=[orig_out, seg_out, mosaic_out, info_out])
66
 
 
 
 
 
 
 
 
67
  demo.launch()
logic/__pycache__/imgGrid.cpython-313.pyc ADDED
Binary file (1.36 kB). View file
 
logic/__pycache__/imgPreprocess.cpython-313.pyc CHANGED
Binary files a/logic/__pycache__/imgPreprocess.cpython-313.pyc and b/logic/__pycache__/imgPreprocess.cpython-313.pyc differ
 
logic/__pycache__/mosaic_logic.cpython-313.pyc ADDED
Binary file (4.63 kB). View file
 
logic/__pycache__/perfMetric.cpython-313.pyc ADDED
Binary file (1.5 kB). View file
 
logic/__pycache__/tileMapping.cpython-313.pyc ADDED
Binary file (2.22 kB). View file
 
logic/imgGrid.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from PIL import Image
3
+ import cv2
4
+ from sklearn.cluster import KMeans
5
+
6
+ def segment_image_grid(image: np.ndarray, grid_size: int, color_centers: np.ndarray):
7
+ h, w, c = image.shape
8
+ cell_h, cell_w = h // grid_size, w // grid_size
9
+ image_cropped = image[:cell_h*grid_size, :cell_w*grid_size]
10
+ cells = image_cropped.reshape(grid_size, cell_h, grid_size, cell_w, c)
11
+ cells = cells.transpose(0,2,1,3,4).reshape(grid_size*grid_size, cell_h*cell_w, c)
12
+ cell_means = cells.mean(axis=1)
13
+ # Assign each cell to nearest color center
14
+ dists = np.linalg.norm(cell_means[:, None, :] - color_centers[None, :, :], axis=2)
15
+ labels = np.argmin(dists, axis=1)
16
+ grid_labels = labels.reshape(grid_size, grid_size)
17
+ return grid_labels
logic/imgPreprocess.py CHANGED
@@ -21,25 +21,25 @@ def resize_img(image: Image.Image, size=(400, 400)) -> np.ndarray:
21
  resized_np = cv2.resize(image_np, size, interpolation=cv2.INTER_LANCZOS4)
22
  return resized_np
23
 
24
-
25
- # def color_quantize(image: Image.Image, n_colors: int = 8) -> Image.Image:
26
- # """
27
- # Apply color quantization to an image using KMeans clustering.
28
- # Args:
29
- # image (PIL.Image.Image): Input image.
30
- # n_colors (int): Number of colors for quantization.
31
- # Returns:
32
- # PIL.Image.Image: Quantized image.
33
- # """
34
- # # Convert image to numpy array
35
- # img_np = np.array(image)
36
- # shape = img_np.shape
37
- # # Flatten the image to (num_pixels, 3)
38
- # img_flat = img_np.reshape(-1, 3)
39
- # # Fit KMeans
40
- # kmeans = KMeans(n_clusters=n_colors, random_state=42)
41
- # labels = kmeans.fit_predict(img_flat)
42
- # quantized_flat = kmeans.cluster_centers_[labels].astype(np.uint8)
43
- # # Reshape back to original image shape
44
- # quantized_img = quantized_flat.reshape(shape)
45
- # return Image.fromarray(quantized_img)
 
21
  resized_np = cv2.resize(image_np, size, interpolation=cv2.INTER_LANCZOS4)
22
  return resized_np
23
 
24
+ def color_quantize(image: Image.Image, n_colors: int = 8):
25
+ """
26
+ Apply color quantization to an image using KMeans clustering.
27
+ Args:
28
+ image (PIL.Image.Image): Input image.
29
+ n_colors (int): Number of colors for quantization.
30
+ Returns:
31
+ quantized_img (np.ndarray): Quantized image as np array (BGR format)
32
+ color_centers (np.ndarray): Array of color centers
33
+ """
34
+ img_np = np.array(image)
35
+ shape = img_np.shape
36
+ img_flat = img_np.reshape(-1, 3)
37
+ kmeans = KMeans(n_clusters=n_colors, random_state=42)
38
+ labels = kmeans.fit_predict(img_flat)
39
+ quantized_flat = kmeans.cluster_centers_[labels].astype(np.uint8)
40
+ quantized_img = quantized_flat.reshape(shape)
41
+ # Convert to BGR for consistency
42
+ if quantized_img.shape[-1] == 3:
43
+ quantized_img = cv2.cvtColor(quantized_img, cv2.COLOR_RGB2BGR)
44
+ color_centers = kmeans.cluster_centers_.astype(np.uint8)
45
+ return quantized_img, color_centers
logic/mosaic_logic.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from PIL import Image
3
+ import cv2
4
+ import time
5
+ import os
6
+ from skimage.metrics import structural_similarity as ssim
7
+
8
+ def segment_image_grid(image: np.ndarray, grid_size: int, n_colors: int = 8):
9
+ h, w, c = image.shape
10
+ cell_h, cell_w = h // grid_size, w // grid_size
11
+ image_cropped = image[:cell_h*grid_size, :cell_w*grid_size]
12
+ cells = image_cropped.reshape(grid_size, cell_h, grid_size, cell_w, c)
13
+ cells = cells.transpose(0,2,1,3,4).reshape(grid_size*grid_size, cell_h*cell_w, c)
14
+ cell_means = cells.mean(axis=1)
15
+ from sklearn.cluster import KMeans
16
+ kmeans = KMeans(n_clusters=n_colors, random_state=42)
17
+ labels = kmeans.fit_predict(cell_means)
18
+ grid_labels = labels.reshape(grid_size, grid_size)
19
+ return grid_labels, kmeans.cluster_centers_.astype(np.uint8)
20
+
21
+ def load_tile_images(tile_dir, n_colors, cell_size):
22
+ tiles = []
23
+ if os.path.isdir(tile_dir):
24
+ files = sorted([os.path.join(tile_dir, f) for f in os.listdir(tile_dir) if f.lower().endswith(('.png','.jpg','.jpeg'))])
25
+ for f in files[:n_colors]:
26
+ tile = np.array(Image.open(f).resize((cell_size, cell_size)))
27
+ tiles.append(tile)
28
+ while len(tiles) < n_colors:
29
+ color = np.random.randint(0,255,3)
30
+ tile = np.ones((cell_size, cell_size, 3), dtype=np.uint8) * color
31
+ tiles.append(tile)
32
+ return tiles
33
+
34
+ def map_tiles_to_grid(grid_labels, tiles, cell_size):
35
+ grid_size = grid_labels.shape[0]
36
+ mosaic = np.zeros((grid_size*cell_size, grid_size*cell_size, 3), dtype=np.uint8)
37
+ for i in range(grid_size):
38
+ for j in range(grid_size):
39
+ mosaic[i*cell_size:(i+1)*cell_size, j*cell_size:(j+1)*cell_size] = tiles[grid_labels[i,j]]
40
+ return mosaic
41
+
42
+ def mse(img1, img2):
43
+ return np.mean((img1.astype(np.float32) - img2.astype(np.float32))**2)
44
+
45
+ def ssim_metric(img1, img2):
46
+ img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
47
+ img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
48
+ return ssim(img1_gray, img2_gray)
49
+
50
+ def timed(func):
51
+ def wrapper(*args, **kwargs):
52
+ start = time.time()
53
+ result = func(*args, **kwargs)
54
+ elapsed = time.time() - start
55
+ return result, elapsed
56
+ return wrapper
logic/perfMetric.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import cv2
3
+ from skimage.metrics import structural_similarity as ssim
4
+ import time
5
+
6
+ def mse(img1, img2):
7
+ return np.mean((img1.astype(np.float32) - img2.astype(np.float32))**2)
8
+
9
+ def ssim_metric(img1, img2):
10
+ img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
11
+ img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
12
+ return ssim(img1_gray, img2_gray)
13
+
14
+ def timed(func):
15
+ def wrapper(*args, **kwargs):
16
+ start = time.time()
17
+ result = func(*args, **kwargs)
18
+ elapsed = time.time() - start
19
+ return result, elapsed
20
+ return wrapper
logic/tileMapping.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import os
3
+ from PIL import Image
4
+
5
+ def load_tile_images(tile_dir, n_colors, cell_size):
6
+ tiles = []
7
+ if os.path.isdir(tile_dir):
8
+ files = sorted([os.path.join(tile_dir, f) for f in os.listdir(tile_dir) if f.lower().endswith(('.png','.jpg','.jpeg'))])
9
+ for f in files[:n_colors]:
10
+ tile = np.array(Image.open(f).resize((cell_size, cell_size)))
11
+ tiles.append(tile)
12
+ while len(tiles) < n_colors:
13
+ color = np.random.randint(0,255,3)
14
+ tile = np.ones((cell_size, cell_size, 3), dtype=np.uint8) * color
15
+ tiles.append(tile)
16
+ return tiles
17
+
18
+ def map_tiles_to_grid(grid_labels, tiles, cell_size):
19
+ grid_size = grid_labels.shape[0]
20
+ mosaic = np.zeros((grid_size*cell_size, grid_size*cell_size, 3), dtype=np.uint8)
21
+ for i in range(grid_size):
22
+ for j in range(grid_size):
23
+ mosaic[i*cell_size:(i+1)*cell_size, j*cell_size:(j+1)*cell_size] = tiles[grid_labels[i,j]]
24
+ return mosaic
resize_image.py CHANGED
@@ -1,12 +0,0 @@
1
- from PIL import Image
2
-
3
- def resize_image(image: Image.Image, size: tuple = (800, 800)) -> Image.Image:
4
- """
5
- Resize the input image to a fixed size (default 800x800 pixels).
6
- Args:
7
- image (PIL.Image.Image): Input image.
8
- size (tuple): Target size as (width, height).
9
- Returns:
10
- PIL.Image.Image: Resized image.
11
- """
12
- return image.resize(size, Image.LANCZOS)