Spaces:
Sleeping
Sleeping
performance metrics
Browse files- app.py +100 -21
- logic/__pycache__/perfMetric.cpython-313.pyc +0 -0
- logic/perfMetric.py +190 -0
- performance_benchmark.png +3 -0
- requirements.txt +85 -7
app.py
CHANGED
|
@@ -3,13 +3,18 @@ import cv2
|
|
| 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, grid_size: int, n_colors: int):
|
| 12 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
width, height = image.size
|
| 14 |
if width != height:
|
| 15 |
min_size = min(width, height)
|
|
@@ -18,8 +23,9 @@ def preprocess_and_mosaic(image: Image.Image, grid_size: int, n_colors: int):
|
|
| 18 |
image = image.crop((left, top, left + min_size, top + min_size))
|
| 19 |
resized_img = resize_img(image, 400)
|
| 20 |
quantized_img, color_centers = color_quantize(resized_img, n_colors)
|
|
|
|
| 21 |
|
| 22 |
-
|
| 23 |
resized_np = np.array(quantized_img)
|
| 24 |
if resized_np.shape[-1] == 3:
|
| 25 |
resized_np = cv2.cvtColor(resized_np, cv2.COLOR_RGB2BGR)
|
|
@@ -28,27 +34,60 @@ def preprocess_and_mosaic(image: Image.Image, grid_size: int, n_colors: int):
|
|
| 28 |
actual_grid_size = 400 // cell_size
|
| 29 |
actual_image_size = actual_grid_size * cell_size
|
| 30 |
|
|
|
|
| 31 |
resized_np_cropped = resized_np[:actual_image_size, :actual_image_size]
|
|
|
|
|
|
|
| 32 |
grid_labels, seg_time = timed(segment_image_grid)(resized_np_cropped, actual_grid_size, color_centers)
|
| 33 |
|
| 34 |
-
|
|
|
|
|
|
|
| 35 |
tiles, tile_colors = load_tile_images('data/tiles', n_colors, cell_size)
|
|
|
|
|
|
|
|
|
|
| 36 |
mosaic_img, mosaic_time = timed(map_tiles_to_grid)(grid_labels, tiles, cell_size, color_centers, tile_colors)
|
| 37 |
|
| 38 |
-
|
|
|
|
|
|
|
|
|
|
| 39 |
mse_val = mse(resized_np_cropped, mosaic_img)
|
| 40 |
ssim_val = ssim_metric(resized_np_cropped, mosaic_img)
|
|
|
|
| 41 |
|
|
|
|
| 42 |
orig_disp = Image.fromarray(cv2.cvtColor(resized_np_cropped, cv2.COLOR_BGR2RGB))
|
| 43 |
mosaic_disp = Image.fromarray(cv2.cvtColor(mosaic_img, cv2.COLOR_BGR2RGB))
|
|
|
|
|
|
|
| 44 |
seg_img = np.zeros_like(resized_np_cropped)
|
| 45 |
for i in range(actual_grid_size):
|
| 46 |
for j in range(actual_grid_size):
|
| 47 |
seg_img[i*cell_size:(i+1)*cell_size, j*cell_size:(j+1)*cell_size] = color_centers[grid_labels[i,j]]
|
| 48 |
seg_disp = Image.fromarray(cv2.cvtColor(seg_img, cv2.COLOR_BGR2RGB))
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
example_urls = [
|
| 54 |
"https://images.unsplash.com/photo-1686854016047-bcd783404deb?q=80&w=880&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
|
@@ -59,21 +98,61 @@ example_urls = [
|
|
| 59 |
|
| 60 |
examples = [[url, 64, 16] for url in example_urls]
|
| 61 |
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
demo.launch()
|
|
|
|
| 3 |
import numpy as np
|
| 4 |
from PIL import Image
|
| 5 |
import os
|
| 6 |
+
import time
|
| 7 |
from logic.imgPreprocess import resize_img, color_quantize
|
| 8 |
from logic.imgGrid import segment_image_grid
|
| 9 |
from logic.tileMapping import load_tile_images, map_tiles_to_grid
|
| 10 |
+
from logic.perfMetric import mse, ssim_metric, timed, create_performance_report, run_performance_benchmark
|
| 11 |
|
| 12 |
def preprocess_and_mosaic(image: Image.Image, grid_size: int, n_colors: int):
|
| 13 |
+
"""Enhanced mosaic generation with detailed performance metrics"""
|
| 14 |
+
start_total = time.time()
|
| 15 |
+
|
| 16 |
+
# Step 1: Image preprocessing
|
| 17 |
+
start_preprocess = time.time()
|
| 18 |
width, height = image.size
|
| 19 |
if width != height:
|
| 20 |
min_size = min(width, height)
|
|
|
|
| 23 |
image = image.crop((left, top, left + min_size, top + min_size))
|
| 24 |
resized_img = resize_img(image, 400)
|
| 25 |
quantized_img, color_centers = color_quantize(resized_img, n_colors)
|
| 26 |
+
preprocess_time = time.time() - start_preprocess
|
| 27 |
|
| 28 |
+
# Step 2: Image grid processing
|
| 29 |
resized_np = np.array(quantized_img)
|
| 30 |
if resized_np.shape[-1] == 3:
|
| 31 |
resized_np = cv2.cvtColor(resized_np, cv2.COLOR_RGB2BGR)
|
|
|
|
| 34 |
actual_grid_size = 400 // cell_size
|
| 35 |
actual_image_size = actual_grid_size * cell_size
|
| 36 |
|
| 37 |
+
# Crop the image to match the actual grid dimensions
|
| 38 |
resized_np_cropped = resized_np[:actual_image_size, :actual_image_size]
|
| 39 |
+
|
| 40 |
+
# Step 2: Grid segmentation (timed)
|
| 41 |
grid_labels, seg_time = timed(segment_image_grid)(resized_np_cropped, actual_grid_size, color_centers)
|
| 42 |
|
| 43 |
+
# Step 3: Tile mapping
|
| 44 |
+
# Step 3a: Load tiles (timed)
|
| 45 |
+
start_tile_load = time.time()
|
| 46 |
tiles, tile_colors = load_tile_images('data/tiles', n_colors, cell_size)
|
| 47 |
+
tile_load_time = time.time() - start_tile_load
|
| 48 |
+
|
| 49 |
+
# Step 3b: Map tiles to grid (timed)
|
| 50 |
mosaic_img, mosaic_time = timed(map_tiles_to_grid)(grid_labels, tiles, cell_size, color_centers, tile_colors)
|
| 51 |
|
| 52 |
+
total_time = time.time() - start_total
|
| 53 |
+
|
| 54 |
+
# Step 4: Performance Metrics
|
| 55 |
+
start_metrics = time.time()
|
| 56 |
mse_val = mse(resized_np_cropped, mosaic_img)
|
| 57 |
ssim_val = ssim_metric(resized_np_cropped, mosaic_img)
|
| 58 |
+
metrics_time = time.time() - start_metrics
|
| 59 |
|
| 60 |
+
# Convert for display - all outputs as PIL Images
|
| 61 |
orig_disp = Image.fromarray(cv2.cvtColor(resized_np_cropped, cv2.COLOR_BGR2RGB))
|
| 62 |
mosaic_disp = Image.fromarray(cv2.cvtColor(mosaic_img, cv2.COLOR_BGR2RGB))
|
| 63 |
+
|
| 64 |
+
# Segmented image: show each cell as its cluster color
|
| 65 |
seg_img = np.zeros_like(resized_np_cropped)
|
| 66 |
for i in range(actual_grid_size):
|
| 67 |
for j in range(actual_grid_size):
|
| 68 |
seg_img[i*cell_size:(i+1)*cell_size, j*cell_size:(j+1)*cell_size] = color_centers[grid_labels[i,j]]
|
| 69 |
seg_disp = Image.fromarray(cv2.cvtColor(seg_img, cv2.COLOR_BGR2RGB))
|
| 70 |
|
| 71 |
+
# Enhanced performance info using perfMetric module
|
| 72 |
+
performance_info = create_performance_report(
|
| 73 |
+
actual_grid_size, cell_size, n_colors, actual_image_size,
|
| 74 |
+
preprocess_time, seg_time, tile_load_time, mosaic_time, metrics_time,
|
| 75 |
+
total_time, mse_val, ssim_val
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
return orig_disp, seg_disp, mosaic_disp, performance_info
|
| 79 |
+
|
| 80 |
+
def performance_benchmark(image: Image.Image, n_colors: int = 16):
|
| 81 |
+
"""Run performance benchmark using perfMetric module"""
|
| 82 |
+
preprocess_funcs = {
|
| 83 |
+
'resize': resize_img,
|
| 84 |
+
'quantize': color_quantize
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
return run_performance_benchmark(
|
| 88 |
+
preprocess_funcs, segment_image_grid, load_tile_images, map_tiles_to_grid,
|
| 89 |
+
image, n_colors
|
| 90 |
+
)
|
| 91 |
|
| 92 |
example_urls = [
|
| 93 |
"https://images.unsplash.com/photo-1686854016047-bcd783404deb?q=80&w=880&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
|
|
|
| 98 |
|
| 99 |
examples = [[url, 64, 16] for url in example_urls]
|
| 100 |
|
| 101 |
+
benchmark_examples = [[url, 16] for url in example_urls]
|
| 102 |
+
|
| 103 |
+
with gr.Blocks(title="Mosaic Generator - Performance Analysis") as demo:
|
| 104 |
+
gr.Markdown("# πΈ Mosaic Generator by Adrien Mery")
|
| 105 |
+
gr.Markdown("Transform your images into beautiful mosaics using colorful photo tiles. Includes comprehensive performance analysis!")
|
| 106 |
+
|
| 107 |
+
with gr.Tabs():
|
| 108 |
+
with gr.Tab("π¨ Mosaic Generator"):
|
| 109 |
+
with gr.Row():
|
| 110 |
+
with gr.Column(scale=2):
|
| 111 |
+
image_input = gr.Image(type="pil", label="Upload Image or Select Example", height=300)
|
| 112 |
+
with gr.Column(scale=1):
|
| 113 |
+
grid_slider = gr.Slider(8, 128, value=64, step=1, label="Mosaic Grid Resolution (NxN cells)")
|
| 114 |
+
color_slider = gr.Slider(2, 32, value=16, step=1, label="Color Palette Size (quantization)")
|
| 115 |
+
mosaic_btn = gr.Button("π¨ Generate Mosaic", variant="primary")
|
| 116 |
+
|
| 117 |
+
with gr.Row():
|
| 118 |
+
orig_out = gr.Image(label="Original (Resized & Quantized)")
|
| 119 |
+
seg_out = gr.Image(label="Grid Segmentation Preview")
|
| 120 |
+
mosaic_out = gr.Image(label="Final Mosaic Result")
|
| 121 |
+
|
| 122 |
+
performance_out = gr.Textbox(label="π Detailed Performance Metrics", interactive=False, lines=15)
|
| 123 |
+
|
| 124 |
+
gr.Examples(examples=examples, inputs=[image_input, grid_slider, color_slider], label="Example Images")
|
| 125 |
+
|
| 126 |
+
with gr.Tab("π Performance Benchmark"):
|
| 127 |
+
gr.Markdown("""
|
| 128 |
+
### Performance Analysis Tool
|
| 129 |
+
This tool runs your image through multiple grid sizes to analyze:
|
| 130 |
+
- **Processing time scaling** with grid complexity
|
| 131 |
+
- **Quality metrics** (MSE & SSIM) across different resolutions
|
| 132 |
+
- **Performance bottlenecks** in the pipeline
|
| 133 |
+
- **Optimal settings** for speed vs quality trade-offs
|
| 134 |
+
""")
|
| 135 |
+
|
| 136 |
+
with gr.Row():
|
| 137 |
+
benchmark_input = gr.Image(type="pil", label="Upload Image for Benchmarking", height=300)
|
| 138 |
+
benchmark_colors = gr.Slider(2, 32, value=16, step=1, label="Color Palette Size")
|
| 139 |
+
benchmark_btn = gr.Button("π¬ Run Performance Benchmark", variant="secondary")
|
| 140 |
+
|
| 141 |
+
gr.Examples(examples=benchmark_examples, inputs=[benchmark_input, benchmark_colors], label="Example Images for Benchmarking")
|
| 142 |
+
|
| 143 |
+
benchmark_plot = gr.Image(label="π Performance Analysis Charts")
|
| 144 |
+
benchmark_results = gr.Textbox(label="π Detailed Benchmark Results", interactive=False, lines=20)
|
| 145 |
|
| 146 |
+
mosaic_btn.click(
|
| 147 |
+
preprocess_and_mosaic,
|
| 148 |
+
inputs=[image_input, grid_slider, color_slider],
|
| 149 |
+
outputs=[orig_out, seg_out, mosaic_out, performance_out]
|
| 150 |
+
)
|
| 151 |
|
| 152 |
+
benchmark_btn.click(
|
| 153 |
+
performance_benchmark,
|
| 154 |
+
inputs=[benchmark_input, benchmark_colors],
|
| 155 |
+
outputs=[benchmark_plot, benchmark_results]
|
| 156 |
+
)
|
| 157 |
|
| 158 |
demo.launch()
|
logic/__pycache__/perfMetric.cpython-313.pyc
CHANGED
|
Binary files a/logic/__pycache__/perfMetric.cpython-313.pyc and b/logic/__pycache__/perfMetric.cpython-313.pyc differ
|
|
|
logic/perfMetric.py
CHANGED
|
@@ -6,6 +6,9 @@ import numpy as np
|
|
| 6 |
import cv2
|
| 7 |
from skimage.metrics import structural_similarity as ssim
|
| 8 |
import time
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
def mse(img1: np.ndarray, img2: np.ndarray) -> float:
|
| 11 |
"""Calculate Mean Squared Error between two images. Lower values = better similarity."""
|
|
@@ -28,3 +31,190 @@ def timed(func):
|
|
| 28 |
elapsed = time.time() - start
|
| 29 |
return result, elapsed
|
| 30 |
return wrapper
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
import cv2
|
| 7 |
from skimage.metrics import structural_similarity as ssim
|
| 8 |
import time
|
| 9 |
+
import matplotlib.pyplot as plt
|
| 10 |
+
import pandas as pd
|
| 11 |
+
from PIL import Image
|
| 12 |
|
| 13 |
def mse(img1: np.ndarray, img2: np.ndarray) -> float:
|
| 14 |
"""Calculate Mean Squared Error between two images. Lower values = better similarity."""
|
|
|
|
| 31 |
elapsed = time.time() - start
|
| 32 |
return result, elapsed
|
| 33 |
return wrapper
|
| 34 |
+
|
| 35 |
+
def create_performance_report(actual_grid_size: int, cell_size: int, n_colors: int,
|
| 36 |
+
actual_image_size: int, preprocess_time: float, seg_time: float,
|
| 37 |
+
tile_load_time: float, mosaic_time: float, metrics_time: float,
|
| 38 |
+
total_time: float, mse_val: float, ssim_val: float) -> str:
|
| 39 |
+
"""Generate a comprehensive performance report."""
|
| 40 |
+
performance_info = f"""
|
| 41 |
+
π PERFORMANCE METRICS
|
| 42 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 43 |
+
π§ CONFIGURATION
|
| 44 |
+
β’ Grid Size: {actual_grid_size}Γ{actual_grid_size} ({actual_grid_size**2:,} cells)
|
| 45 |
+
β’ Cell Size: {cell_size}Γ{cell_size} pixels
|
| 46 |
+
β’ Colors: {n_colors} quantized colors
|
| 47 |
+
β’ Image Size: {actual_image_size}Γ{actual_image_size} pixels
|
| 48 |
+
|
| 49 |
+
β±οΈ TIMING BREAKDOWN
|
| 50 |
+
β’ Preprocessing: {preprocess_time:.3f}s ({preprocess_time/total_time*100:.1f}%)
|
| 51 |
+
β’ Grid Segmentation: {seg_time:.3f}s ({seg_time/total_time*100:.1f}%)
|
| 52 |
+
β’ Tile Loading: {tile_load_time:.3f}s ({tile_load_time/total_time*100:.1f}%)
|
| 53 |
+
β’ Tile Mapping: {mosaic_time:.3f}s ({mosaic_time/total_time*100:.1f}%)
|
| 54 |
+
β’ Metrics Calculation: {metrics_time:.3f}s ({metrics_time/total_time*100:.1f}%)
|
| 55 |
+
β’ TOTAL TIME: {total_time:.3f}s
|
| 56 |
+
|
| 57 |
+
π SIMILARITY METRICS
|
| 58 |
+
β’ MSE: {mse_val:.2f} (Lower = Better, 0 = Perfect)
|
| 59 |
+
β’ SSIM: {ssim_val:.3f} (Higher = Better, 1 = Perfect)
|
| 60 |
+
|
| 61 |
+
π― QUALITY ASSESSMENT
|
| 62 |
+
β’ MSE Quality: {'Excellent' if mse_val < 100 else 'Good' if mse_val < 500 else 'Fair' if mse_val < 1000 else 'Poor'}
|
| 63 |
+
β’ SSIM Quality: {'Excellent' if ssim_val > 0.9 else 'Good' if ssim_val > 0.8 else 'Fair' if ssim_val > 0.6 else 'Poor'}
|
| 64 |
+
|
| 65 |
+
β‘ PERFORMANCE ANALYSIS
|
| 66 |
+
β’ Cells/second: {(actual_grid_size**2)/total_time:.0f}
|
| 67 |
+
β’ Efficiency: {'High' if total_time < 2 else 'Medium' if total_time < 5 else 'Low'}
|
| 68 |
+
β’ Memory Usage: ~{actual_image_size*actual_image_size*3/1024/1024:.1f}MB
|
| 69 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 70 |
+
"""
|
| 71 |
+
return performance_info
|
| 72 |
+
|
| 73 |
+
def run_performance_benchmark(preprocess_func, segment_func, load_tiles_func, map_tiles_func,
|
| 74 |
+
image: Image.Image, n_colors: int = 16):
|
| 75 |
+
"""Run comprehensive performance benchmark across different grid sizes."""
|
| 76 |
+
if image is None:
|
| 77 |
+
return None, "Please upload an image first!"
|
| 78 |
+
|
| 79 |
+
grid_sizes = [8, 16, 24, 32, 48, 64, 80, 96, 128]
|
| 80 |
+
results = []
|
| 81 |
+
|
| 82 |
+
width, height = image.size
|
| 83 |
+
if width != height:
|
| 84 |
+
min_size = min(width, height)
|
| 85 |
+
left = (width - min_size) // 2
|
| 86 |
+
top = (height - min_size) // 2
|
| 87 |
+
image = image.crop((left, top, left + min_size, top + min_size))
|
| 88 |
+
|
| 89 |
+
resized_img = preprocess_func['resize'](image, 400)
|
| 90 |
+
quantized_img, color_centers = preprocess_func['quantize'](resized_img, n_colors)
|
| 91 |
+
|
| 92 |
+
resized_np = np.array(quantized_img)
|
| 93 |
+
if resized_np.shape[-1] == 3:
|
| 94 |
+
resized_np = cv2.cvtColor(resized_np, cv2.COLOR_RGB2BGR)
|
| 95 |
+
|
| 96 |
+
for i, grid_size in enumerate(grid_sizes):
|
| 97 |
+
start_time = time.time()
|
| 98 |
+
|
| 99 |
+
cell_size = 400 // grid_size
|
| 100 |
+
actual_grid_size = 400 // cell_size
|
| 101 |
+
actual_image_size = actual_grid_size * cell_size
|
| 102 |
+
resized_np_cropped = resized_np[:actual_image_size, :actual_image_size]
|
| 103 |
+
|
| 104 |
+
# Time each step
|
| 105 |
+
grid_labels, seg_time = timed(segment_func)(resized_np_cropped, actual_grid_size, color_centers)
|
| 106 |
+
|
| 107 |
+
start_tile = time.time()
|
| 108 |
+
tiles, tile_colors = load_tiles_func('data/tiles', n_colors, cell_size)
|
| 109 |
+
tile_time = time.time() - start_tile
|
| 110 |
+
|
| 111 |
+
mosaic_img, mosaic_time = timed(map_tiles_func)(grid_labels, tiles, cell_size, color_centers, tile_colors)
|
| 112 |
+
|
| 113 |
+
total_time = time.time() - start_time
|
| 114 |
+
|
| 115 |
+
mse_val = mse(resized_np_cropped, mosaic_img)
|
| 116 |
+
ssim_val = ssim_metric(resized_np_cropped, mosaic_img)
|
| 117 |
+
|
| 118 |
+
results.append({
|
| 119 |
+
'Grid Size': f"{actual_grid_size}x{actual_grid_size}",
|
| 120 |
+
'Cells': actual_grid_size**2,
|
| 121 |
+
'Cell Size': cell_size,
|
| 122 |
+
'Segmentation (s)': seg_time,
|
| 123 |
+
'Tile Loading (s)': tile_time,
|
| 124 |
+
'Tile Mapping (s)': mosaic_time,
|
| 125 |
+
'Total Time (s)': total_time,
|
| 126 |
+
'Cells/sec': actual_grid_size**2 / total_time,
|
| 127 |
+
'MSE': mse_val,
|
| 128 |
+
'SSIM': ssim_val
|
| 129 |
+
})
|
| 130 |
+
|
| 131 |
+
return create_benchmark_plots(results)
|
| 132 |
+
|
| 133 |
+
def create_benchmark_plots(results):
|
| 134 |
+
"""Create performance benchmark visualization plots."""
|
| 135 |
+
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(12, 10))
|
| 136 |
+
|
| 137 |
+
cells = [r['Cells'] for r in results]
|
| 138 |
+
total_times = [r['Total Time (s)'] for r in results]
|
| 139 |
+
seg_times = [r['Segmentation (s)'] for r in results]
|
| 140 |
+
mapping_times = [r['Tile Mapping (s)'] for r in results]
|
| 141 |
+
mse_vals = [r['MSE'] for r in results]
|
| 142 |
+
ssim_vals = [r['SSIM'] for r in results]
|
| 143 |
+
|
| 144 |
+
# Plot 1: Total Time vs Grid Size
|
| 145 |
+
ax1.plot(cells, total_times, 'bo-', linewidth=2, markersize=6)
|
| 146 |
+
ax1.set_xlabel('Number of Cells')
|
| 147 |
+
ax1.set_ylabel('Total Time (seconds)')
|
| 148 |
+
ax1.set_title('Performance Scaling')
|
| 149 |
+
ax1.grid(True, alpha=0.3)
|
| 150 |
+
ax1.set_xscale('log')
|
| 151 |
+
|
| 152 |
+
# Plot 2: Time Breakdown
|
| 153 |
+
width = 0.35
|
| 154 |
+
x = np.arange(len(results))
|
| 155 |
+
ax2.bar(x - width/2, seg_times, width, label='Segmentation', alpha=0.8)
|
| 156 |
+
ax2.bar(x + width/2, mapping_times, width, label='Tile Mapping', alpha=0.8)
|
| 157 |
+
ax2.set_xlabel('Grid Configuration')
|
| 158 |
+
ax2.set_ylabel('Time (seconds)')
|
| 159 |
+
ax2.set_title('Time Breakdown by Operation')
|
| 160 |
+
ax2.set_xticks(x)
|
| 161 |
+
ax2.set_xticklabels([r['Grid Size'] for r in results], rotation=45)
|
| 162 |
+
ax2.legend()
|
| 163 |
+
ax2.grid(True, alpha=0.3)
|
| 164 |
+
|
| 165 |
+
# Plot 3: MSE vs Grid Size
|
| 166 |
+
ax3.plot(cells, mse_vals, 'ro-', linewidth=2, markersize=6)
|
| 167 |
+
ax3.set_xlabel('Number of Cells')
|
| 168 |
+
ax3.set_ylabel('MSE (Lower = Better)')
|
| 169 |
+
ax3.set_title('Image Quality (MSE)')
|
| 170 |
+
ax3.grid(True, alpha=0.3)
|
| 171 |
+
ax3.set_xscale('log')
|
| 172 |
+
|
| 173 |
+
# Plot 4: SSIM vs Grid Size
|
| 174 |
+
ax4.plot(cells, ssim_vals, 'go-', linewidth=2, markersize=6)
|
| 175 |
+
ax4.set_xlabel('Number of Cells')
|
| 176 |
+
ax4.set_ylabel('SSIM (Higher = Better)')
|
| 177 |
+
ax4.set_title('Image Quality (SSIM)')
|
| 178 |
+
ax4.grid(True, alpha=0.3)
|
| 179 |
+
ax4.set_xscale('log')
|
| 180 |
+
|
| 181 |
+
plt.tight_layout()
|
| 182 |
+
plt.savefig('performance_benchmark.png', dpi=150, bbox_inches='tight')
|
| 183 |
+
plt.close()
|
| 184 |
+
|
| 185 |
+
# Create summary report
|
| 186 |
+
df = pd.DataFrame(results)
|
| 187 |
+
summary = create_benchmark_summary(results, mse_vals, ssim_vals, df)
|
| 188 |
+
|
| 189 |
+
return 'performance_benchmark.png', summary
|
| 190 |
+
|
| 191 |
+
def create_benchmark_summary(results, mse_vals, ssim_vals, df):
|
| 192 |
+
"""Create a comprehensive benchmark summary report."""
|
| 193 |
+
summary = f"""
|
| 194 |
+
π¬ PERFORMANCE BENCHMARK RESULTS
|
| 195 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 196 |
+
|
| 197 |
+
π PERFORMANCE SCALING ANALYSIS:
|
| 198 |
+
β’ Best Performance: {results[0]['Grid Size']} ({results[0]['Total Time (s)']:.3f}s)
|
| 199 |
+
β’ Highest Quality: {max(results, key=lambda x: x['SSIM'])['Grid Size']} (SSIM: {max(results, key=lambda x: x['SSIM'])['SSIM']:.3f})
|
| 200 |
+
β’ Best Balance: {sorted(results, key=lambda x: x['Total Time (s)'] * (1-x['SSIM']))[0]['Grid Size']}
|
| 201 |
+
|
| 202 |
+
π COMPLEXITY ANALYSIS:
|
| 203 |
+
β’ 8x increase in cells: {results[-1]['Total Time (s)']/results[0]['Total Time (s)']:.1f}x slower
|
| 204 |
+
β’ Linear scaling: {'Yes' if results[-1]['Total Time (s)']/results[0]['Total Time (s)'] < 20 else 'No'}
|
| 205 |
+
β’ Processing efficiency: {np.mean([r['Cells/sec'] for r in results]):.0f} cells/sec average
|
| 206 |
+
|
| 207 |
+
π― QUALITY TRENDS:
|
| 208 |
+
β’ MSE Range: {min(mse_vals):.1f} - {max(mse_vals):.1f}
|
| 209 |
+
β’ SSIM Range: {min(ssim_vals):.3f} - {max(ssim_vals):.3f}
|
| 210 |
+
β’ Quality improves with grid size: {'Yes' if ssim_vals[-1] > ssim_vals[0] else 'No'}
|
| 211 |
+
|
| 212 |
+
π‘ RECOMMENDATIONS:
|
| 213 |
+
β’ For speed: Use {results[0]['Grid Size']} or {results[1]['Grid Size']}
|
| 214 |
+
β’ For quality: Use {results[-2]['Grid Size']} or {results[-1]['Grid Size']}
|
| 215 |
+
β’ For balance: Use {results[len(results)//2]['Grid Size']}
|
| 216 |
+
|
| 217 |
+
{df.to_string(index=False, float_format='%.3f')}
|
| 218 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 219 |
+
"""
|
| 220 |
+
return summary
|
performance_benchmark.png
ADDED
|
Git LFS Details
|
requirements.txt
CHANGED
|
@@ -1,7 +1,85 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiofiles==24.1.0
|
| 2 |
+
aiohappyeyeballs==2.6.1
|
| 3 |
+
aiohttp==3.12.15
|
| 4 |
+
aiosignal==1.4.0
|
| 5 |
+
annotated-types==0.7.0
|
| 6 |
+
anyio==4.10.0
|
| 7 |
+
attrs==25.3.0
|
| 8 |
+
audioop-lts==0.2.2
|
| 9 |
+
Brotli==1.1.0
|
| 10 |
+
certifi==2025.8.3
|
| 11 |
+
charset-normalizer==3.4.3
|
| 12 |
+
click==8.2.1
|
| 13 |
+
contourpy==1.3.3
|
| 14 |
+
cycler==0.12.1
|
| 15 |
+
datasets==4.1.1
|
| 16 |
+
dill==0.4.0
|
| 17 |
+
fastapi==0.116.1
|
| 18 |
+
ffmpy==0.6.1
|
| 19 |
+
filelock==3.19.1
|
| 20 |
+
fonttools==4.60.0
|
| 21 |
+
frozenlist==1.7.0
|
| 22 |
+
fsspec==2025.9.0
|
| 23 |
+
gradio==5.45.0
|
| 24 |
+
gradio_client==1.13.0
|
| 25 |
+
groovy==0.1.2
|
| 26 |
+
h11==0.16.0
|
| 27 |
+
hf-xet==1.1.9
|
| 28 |
+
httpcore==1.0.9
|
| 29 |
+
httpx==0.28.1
|
| 30 |
+
huggingface-hub==0.34.4
|
| 31 |
+
idna==3.10
|
| 32 |
+
imageio==2.37.0
|
| 33 |
+
Jinja2==3.1.6
|
| 34 |
+
joblib==1.5.2
|
| 35 |
+
kiwisolver==1.4.9
|
| 36 |
+
lazy_loader==0.4
|
| 37 |
+
markdown-it-py==4.0.0
|
| 38 |
+
MarkupSafe==3.0.2
|
| 39 |
+
matplotlib==3.10.6
|
| 40 |
+
mdurl==0.1.2
|
| 41 |
+
multidict==6.6.4
|
| 42 |
+
multiprocess==0.70.16
|
| 43 |
+
networkx==3.5
|
| 44 |
+
numpy==2.2.6
|
| 45 |
+
opencv-python==4.12.0.88
|
| 46 |
+
orjson==3.11.3
|
| 47 |
+
packaging==25.0
|
| 48 |
+
pandas==2.3.2
|
| 49 |
+
pillow==11.3.0
|
| 50 |
+
propcache==0.3.2
|
| 51 |
+
pyarrow==21.0.0
|
| 52 |
+
pydantic==2.11.7
|
| 53 |
+
pydantic_core==2.33.2
|
| 54 |
+
pydub==0.25.1
|
| 55 |
+
Pygments==2.19.2
|
| 56 |
+
pyparsing==3.2.5
|
| 57 |
+
python-dateutil==2.9.0.post0
|
| 58 |
+
python-multipart==0.0.20
|
| 59 |
+
pytz==2025.2
|
| 60 |
+
PyYAML==6.0.2
|
| 61 |
+
requests==2.32.5
|
| 62 |
+
rich==14.1.0
|
| 63 |
+
ruff==0.13.0
|
| 64 |
+
safehttpx==0.1.6
|
| 65 |
+
scikit-image==0.25.2
|
| 66 |
+
scikit-learn==1.7.2
|
| 67 |
+
scipy==1.16.1
|
| 68 |
+
semantic-version==2.10.0
|
| 69 |
+
shellingham==1.5.4
|
| 70 |
+
six==1.17.0
|
| 71 |
+
sniffio==1.3.1
|
| 72 |
+
starlette==0.47.3
|
| 73 |
+
threadpoolctl==3.6.0
|
| 74 |
+
tifffile==2025.9.9
|
| 75 |
+
tomlkit==0.13.3
|
| 76 |
+
tqdm==4.67.1
|
| 77 |
+
typer==0.17.4
|
| 78 |
+
typing-inspection==0.4.1
|
| 79 |
+
typing_extensions==4.15.0
|
| 80 |
+
tzdata==2025.2
|
| 81 |
+
urllib3==2.5.0
|
| 82 |
+
uvicorn==0.35.0
|
| 83 |
+
websockets==15.0.1
|
| 84 |
+
xxhash==3.5.0
|
| 85 |
+
yarl==1.20.1
|