gexu13 commited on
Commit
d2aa004
·
1 Parent(s): c91ddaf

add app files

Browse files
Files changed (3) hide show
  1. .DS_Store +0 -0
  2. app.py +126 -0
  3. requirements.txt +108 -0
.DS_Store ADDED
Binary file (6.15 kB). View file
 
app.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ from skimage.metrics import structural_similarity as ssim
5
+ from PIL import Image
6
+
7
+ def preprocess_image(image, grid_size):
8
+ """Resize image to ensure consistent processing."""
9
+ if isinstance(image, str): # If image is a file path
10
+ image = cv2.imread(image)
11
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
12
+
13
+ height, width = image.shape[:2]
14
+ max_dim = 512
15
+ scale = max_dim / max(height, width)
16
+ new_width = int(width * scale)
17
+ new_height = int(height * scale)
18
+ return cv2.resize(image, (new_width, new_height))
19
+
20
+ def quantize_colors(image, n_colors=8):
21
+ """Quantize colors using optimized K-means clustering."""
22
+ pixels = image.reshape(-1, 3).astype(np.float32) # Flatten image for K-means
23
+
24
+ # Define K-means criteria and apply clustering
25
+ criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
26
+ _, labels, centers = cv2.kmeans(pixels, n_colors, None, criteria, 10, cv2.KMEANS_PP_CENTERS)
27
+
28
+ # Convert back to uint8 and reshape
29
+ centers = np.uint8(centers)
30
+ quantized = centers[labels.flatten()]
31
+ return quantized.reshape(image.shape)
32
+
33
+ def create_grid(image, grid_size):
34
+ """Divide image into grid cells."""
35
+ height, width = image.shape[:2]
36
+ cell_height = height // grid_size
37
+ cell_width = width // grid_size
38
+
39
+ grid = []
40
+ for i in range(grid_size):
41
+ row = []
42
+ for j in range(grid_size):
43
+ y_start = i * cell_height
44
+ x_start = j * cell_width
45
+ y_end = height if i == grid_size - 1 else (i + 1) * cell_height
46
+ x_end = width if j == grid_size - 1 else (j + 1) * cell_width
47
+ cell = image[y_start:y_end, x_start:x_end]
48
+ row.append(cell)
49
+ grid.append(row)
50
+ return grid
51
+
52
+ def get_average_color(cell):
53
+ """Calculate average color of a grid cell."""
54
+ return np.mean(cell, axis=(0, 1)).astype(np.uint8)
55
+
56
+ def create_mosaic(image, grid_size, use_color_quantization, n_colors=8):
57
+ """Create mosaic from input image using optional color quantization."""
58
+ processed_image = preprocess_image(image, grid_size)
59
+
60
+ if use_color_quantization:
61
+ processed_image = quantize_colors(processed_image, n_colors)
62
+
63
+ grid = create_grid(processed_image, grid_size)
64
+
65
+ height, width = processed_image.shape[:2]
66
+ cell_height = height // grid_size
67
+ cell_width = width // grid_size
68
+
69
+ mosaic = np.zeros_like(processed_image)
70
+
71
+ for i in range(grid_size):
72
+ for j in range(grid_size):
73
+ y_start = i * cell_height
74
+ x_start = j * cell_width
75
+ y_end = height if i == grid_size - 1 else (i + 1) * cell_height
76
+ x_end = width if j == grid_size - 1 else (j + 1) * cell_width
77
+
78
+ avg_color = get_average_color(grid[i][j])
79
+ mosaic[y_start:y_end, x_start:x_end] = avg_color
80
+
81
+
82
+ return processed_image, mosaic
83
+
84
+ def calculate_similarity(original, mosaic):
85
+ """Calculate similarity between original and mosaic images."""
86
+ original_gray = cv2.cvtColor(original, cv2.COLOR_RGB2GRAY)
87
+ mosaic_gray = cv2.cvtColor(mosaic, cv2.COLOR_RGB2GRAY)
88
+
89
+ similarity = ssim(original_gray, mosaic_gray)
90
+ mse = np.mean((original - mosaic) ** 2)
91
+
92
+ return similarity, mse
93
+
94
+ def process_image(input_image, grid_size, use_quantization, n_colors):
95
+ """Process image with K-means color quantization instead of a fixed palette."""
96
+ original, mosaic = create_mosaic(input_image, grid_size, use_quantization, n_colors)
97
+ similarity, mse = calculate_similarity(original, mosaic)
98
+
99
+ return (mosaic,
100
+ f"Structural Similarity: {similarity:.4f}",
101
+ f"Mean Squared Error: {mse:.4f}")
102
+
103
+ iface = gr.Interface(
104
+ fn=process_image,
105
+ inputs=[
106
+ gr.Image(type="numpy", label="Upload Image"),
107
+ gr.Slider(minimum=8, maximum=64, step=8, value=16, label="Grid Size"),
108
+ gr.Checkbox(label="Use Color Quantization"),
109
+ gr.Slider(minimum=2, maximum=16, step=1, value=8, label="Number of Colors (K-Means)")
110
+ ],
111
+ outputs=[
112
+ gr.Image(type="numpy", label="Mosaic Result"),
113
+ gr.Textbox(label="Structural Similarity (SSIM)"),
114
+ gr.Textbox(label="Mean Squared Error (MSE)")
115
+ ],
116
+ title="Interactive Image Mosaic Generator (Optimized K-Means)",
117
+ description="Upload an image to create a mosaic-style reconstruction. Adjust the grid size and color quantization settings.",
118
+ examples=[["https://res.cloudinary.com/daigovpbf/image/upload/c_crop,g_auto,h_800,w_800/samples/cup-on-a-table", 8, False, 0],
119
+ ["https://res.cloudinary.com/daigovpbf/image/upload/c_crop,g_auto,h_800,w_800/samples/dessert-on-a-plate", 16, True, 8],
120
+ ["https://res.cloudinary.com/daigovpbf/image/upload/c_crop,g_auto,h_800,w_800/samples/breakfast", 32, True, 4],
121
+ ["https://res.cloudinary.com/daigovpbf/image/upload/c_crop,g_auto,h_800,w_800/samples/balloons", 64, True, 8]],
122
+ theme="default"
123
+ )
124
+
125
+ if __name__ == "__main__":
126
+ iface.launch(share=True)
requirements.txt ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.2.1
2
+ annotated-types==0.7.0
3
+ anyio==4.8.0
4
+ appnope==0.1.4
5
+ asttokens==3.0.0
6
+ attrs==25.1.0
7
+ backcall==0.2.0
8
+ beautifulsoup4==4.13.3
9
+ bleach==6.2.0
10
+ certifi==2022.9.24
11
+ charset-normalizer==2.1.1
12
+ click==8.1.8
13
+ contourpy==1.0.6
14
+ cycler==0.11.0
15
+ decorator==5.1.1
16
+ defusedxml==0.7.1
17
+ docopt==0.6.2
18
+ exceptiongroup==1.2.2
19
+ executing==2.2.0
20
+ fastapi==0.115.8
21
+ fastjsonschema==2.21.1
22
+ ffmpy==0.5.0
23
+ filelock==3.17.0
24
+ fonttools==4.38.0
25
+ fsspec==2025.2.0
26
+ gradio==5.15.0
27
+ gradio_client==1.7.0
28
+ h11==0.14.0
29
+ httpcore==1.0.7
30
+ httpx==0.28.1
31
+ huggingface-hub==0.28.1
32
+ idna==3.4
33
+ imageio==2.37.0
34
+ ipython==8.12.3
35
+ jedi==0.19.2
36
+ Jinja2==3.1.5
37
+ jsonschema==4.23.0
38
+ jsonschema-specifications==2024.10.1
39
+ jupyter_client==8.6.3
40
+ jupyter_core==5.7.2
41
+ jupyterlab_pygments==0.3.0
42
+ kiwisolver==1.4.4
43
+ lazy_loader==0.4
44
+ markdown-it-py==3.0.0
45
+ MarkupSafe==2.1.5
46
+ matplotlib==3.6.2
47
+ matplotlib-inline==0.1.7
48
+ mdurl==0.1.2
49
+ mistune==3.1.1
50
+ nbclient==0.10.2
51
+ nbconvert==7.16.6
52
+ nbformat==5.10.4
53
+ networkx==3.4.2
54
+ numpy==2.2.2
55
+ opencv-python==4.11.0.86
56
+ orjson==3.10.15
57
+ packaging==21.3
58
+ pandas==2.2.3
59
+ pandocfilters==1.5.1
60
+ parso==0.8.4
61
+ pexpect==4.9.0
62
+ pickleshare==0.7.5
63
+ pillow==11.1.0
64
+ pipreqs==0.5.0
65
+ platformdirs==4.3.6
66
+ prompt_toolkit==3.0.50
67
+ ptyprocess==0.7.0
68
+ pure_eval==0.2.3
69
+ pydantic==2.10.6
70
+ pydantic_core==2.27.2
71
+ pydub==0.25.1
72
+ Pygments==2.19.1
73
+ pyparsing==3.0.9
74
+ python-dateutil==2.8.2
75
+ python-multipart==0.0.20
76
+ pytz==2022.6
77
+ PyYAML==6.0.2
78
+ pyzmq==26.2.1
79
+ referencing==0.36.2
80
+ requests==2.28.1
81
+ rich==13.9.4
82
+ rpds-py==0.22.3
83
+ ruff==0.9.4
84
+ safehttpx==0.1.6
85
+ scikit-image==0.25.1
86
+ scipy==1.15.1
87
+ semantic-version==2.10.0
88
+ shellingham==1.5.4
89
+ six==1.16.0
90
+ sniffio==1.3.1
91
+ soupsieve==2.6
92
+ stack-data==0.6.3
93
+ starlette==0.45.3
94
+ tifffile==2025.1.10
95
+ tinycss2==1.4.0
96
+ tomlkit==0.13.2
97
+ tornado==6.4.2
98
+ tqdm==4.67.1
99
+ traitlets==5.14.3
100
+ typer==0.15.1
101
+ typing_extensions==4.12.2
102
+ tzdata==2025.1
103
+ urllib3==1.26.12
104
+ uvicorn==0.34.0
105
+ wcwidth==0.2.13
106
+ webencodings==0.5.1
107
+ websockets==14.2
108
+ yarg==0.1.9