Spaces:
Sleeping
Sleeping
| """ | |
| Web-based interface for photo mosaic creation using Gradio | |
| Author: [Your Name] | |
| Date: November 2025 | |
| Version: 2.0 | |
| """ | |
| import gradio as gr | |
| import numpy as np | |
| from PIL import Image | |
| import time | |
| from pathlib import Path | |
| # Import custom mosaic generation modules | |
| from mosaic_generator import ( | |
| TileManager, | |
| MosaicBuilder, | |
| compute_similarity_metrics, | |
| format_metrics, | |
| config | |
| ) | |
| def initialize_tile_system(): | |
| """Load and prepare tile collection for mosaic generation""" | |
| print("π¨ Loading tile collection...") | |
| manager = TileManager(tiles_path=config.DEFAULT_TILE_DIRECTORY) | |
| print(f"β Successfully loaded {len(manager)} tile images") | |
| return manager | |
| # Global tile management system | |
| tile_system = initialize_tile_system() | |
| def process_mosaic_request(uploaded_img, rows, cols): | |
| """ | |
| Process user request to generate photo mosaic | |
| Parameters: | |
| uploaded_img: PIL Image object from user upload | |
| rows: Number of rows in mosaic grid | |
| cols: Number of columns in mosaic grid | |
| Returns: | |
| tuple: Generated mosaic image and status information | |
| """ | |
| # Input validation | |
| if uploaded_img is None: | |
| return None, "β οΈ No image provided. Please upload an image first." | |
| try: | |
| # Initialize mosaic generator with user-specified grid | |
| generator = MosaicBuilder(tile_system, grid_layout=(rows, cols)) | |
| # Track execution time | |
| time_start = time.time() | |
| result_mosaic = generator.create_mosaic(uploaded_img) | |
| time_elapsed = time.time() - time_start | |
| # Prepare original image for metric comparison | |
| original_resized = uploaded_img.resize( | |
| (result_mosaic.shape[1], result_mosaic.shape[0]), | |
| Image.Resampling.LANCZOS | |
| ) | |
| # Calculate quality metrics | |
| quality_metrics = compute_similarity_metrics(original_resized, result_mosaic) | |
| # Build status report | |
| status_report = [] | |
| status_report.append("β Mosaic creation completed successfully!") | |
| status_report.append("") | |
| status_report.append(f"β±οΈ Execution time: {time_elapsed:.3f}s") | |
| status_report.append(f"π Grid configuration: {rows}Γ{cols} = {rows * cols} tiles") | |
| status_report.append(f"π¨ Available tiles: {len(tile_system)}") | |
| status_report.append("") | |
| status_report.append(format_metrics(quality_metrics)) | |
| status_report.append("") | |
| status_report.append(f"πΌοΈ Result dimensions: {result_mosaic.shape[1]}Γ{result_mosaic.shape[0]} pixels") | |
| status_text = "\n".join(status_report) | |
| # Convert numpy array to PIL for display | |
| output_img = Image.fromarray(result_mosaic) | |
| return output_img, status_text | |
| except Exception as error: | |
| error_report = f"β Processing failed: {str(error)}" | |
| print(error_report) | |
| import traceback | |
| traceback.print_exc() | |
| return None, error_report | |
| def build_interface(): | |
| """Construct the Gradio web interface""" | |
| interface = gr.Blocks(title=config.UI_TITLE, theme=gr.themes.Soft()) | |
| with interface: | |
| gr.Markdown(f"# {config.UI_TITLE}") | |
| gr.Markdown(config.UI_DESCRIPTION) | |
| with gr.Row(): | |
| # Left panel - inputs and controls | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π€ Source Image") | |
| source_image = gr.Image( | |
| label="Upload your image", | |
| type="pil", | |
| height=400 | |
| ) | |
| gr.Markdown("### βοΈ Grid Configuration") | |
| row_slider = gr.Slider( | |
| minimum=config.MIN_GRID_SIZE, | |
| maximum=config.MAX_GRID_SIZE, | |
| value=config.DEFAULT_GRID_SIZE[0], | |
| step=1, | |
| label="Vertical tiles (rows)" | |
| ) | |
| col_slider = gr.Slider( | |
| minimum=config.MIN_GRID_SIZE, | |
| maximum=config.MAX_GRID_SIZE, | |
| value=config.DEFAULT_GRID_SIZE[1], | |
| step=1, | |
| label="Horizontal tiles (columns)" | |
| ) | |
| submit_btn = gr.Button( | |
| "π¨ Create Mosaic", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # Right panel - outputs | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π₯ Generated Mosaic") | |
| result_image = gr.Image( | |
| label="Your mosaic", | |
| type="pil", | |
| height=400 | |
| ) | |
| result_info = gr.Textbox( | |
| label="Processing Details", | |
| lines=15, | |
| max_lines=20 | |
| ) | |
| # Add example images if available | |
| test_image_path = Path("tests/test_512x512.png") | |
| if test_image_path.exists(): | |
| gr.Markdown("### πΈ Sample Images") | |
| sample_configs = [] | |
| if Path("tests/test_256x256.png").exists(): | |
| sample_configs.append(["tests/test_256x256.png", 16, 16]) | |
| if test_image_path.exists(): | |
| sample_configs.append(["tests/test_512x512.png", 32, 32]) | |
| sample_configs.append(["tests/test_512x512.png", 48, 48]) | |
| if sample_configs: | |
| gr.Examples( | |
| examples=sample_configs, | |
| inputs=[source_image, row_slider, col_slider], | |
| label="Try these examples" | |
| ) | |
| # Application footer | |
| gr.Markdown(""" | |
| **CS5130 Lab 5** | High-Performance Photo Mosaic System v2.0 | |
| """) | |
| # Wire up the interface | |
| submit_btn.click( | |
| fn=process_mosaic_request, | |
| inputs=[source_image, row_slider, col_slider], | |
| outputs=[result_image, result_info] | |
| ) | |
| return interface | |
| def main(): | |
| """Application entry point""" | |
| print("\n" + "="*70) | |
| print("π Launching Optimized Photo Mosaic Generator") | |
| print("="*70) | |
| print(f"π Tile inventory: {len(tile_system)} images") | |
| print(f"π Standard grid: {config.DEFAULT_GRID_SIZE[0]}Γ{config.DEFAULT_GRID_SIZE[1]}") | |
| print(f"π Access at: http://localhost:7860") | |
| print("="*70 + "\n") | |
| web_interface = build_interface() | |
| web_interface.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False | |
| ) | |
| if __name__ == "__main__": | |
| main() |