NiranjanSathish's picture
Upload 41 files
f647a80 verified
"""
main.py - OPTIMIZED
Complete mosaic generator with Numba + parallel optimizations.
"""
import numpy as np
import cv2
from pathlib import Path
from typing import Tuple, Dict, Optional
import time
import matplotlib.pyplot as plt
from ImagePreprocessor import ImagePreprocessor
from contextual_Mosaic_Builder import ContextualMosaicGenerator, ImageContext
from Performance_metrics import PerformanceEvaluator
def create_advanced_mosaic(image_path: str,
tile_folder: str = "extracted_images",
grid_size: Tuple[int, int] = (64, 64),
tile_size: Tuple[int, int] = (32, 32),
diversity_factor: float = 0.15,
enable_rotation: bool = True,
enable_face_detection: bool = False,
colour_bins: int = 8,
apply_quantization: bool = False,
n_colors: int = 12,
use_numba: bool = True,
use_parallel: bool = True,
evaluate_quality: bool = False,
show_visualizations: bool = False,
verbose: bool = False) -> Tuple[np.ndarray, Optional[Dict], Optional[ImageContext]]:
"""
Create advanced mosaic - FULLY OPTIMIZED.
Args:
image_path: Path to input image
tile_folder: Path to tile images folder
grid_size: Grid dimensions (rows, cols)
tile_size: Individual tile size (width, height)
diversity_factor: Tile diversity factor (0.0-0.5)
enable_rotation: Whether to enable 4-way tile rotation
enable_face_detection: Whether to enable face detection
colour_bins: Number of color bins for subgrouping
apply_quantization: Whether to apply color quantization
n_colors: Number of colors for quantization
use_numba: Use Numba JIT compilation (recommended)
use_parallel: Use parallel processing (recommended)
evaluate_quality: Whether to calculate quality metrics
show_visualizations: Whether to display analysis
verbose: Enable detailed logging
Returns:
Tuple of (mosaic_image, quality_metrics, context_analysis)
"""
if verbose:
print(f"Advanced Mosaic Generator (Numba={'ON' if use_numba else 'OFF'}, Parallel={'ON' if use_parallel else 'OFF'})")
print(f"Image: {image_path}")
print(f"Grid: {grid_size[0]}x{grid_size[1]} = {np.prod(grid_size):,} tiles")
print(f"Tile size: {tile_size[0]}x{tile_size[1]}")
total_start = time.time()
# Initialize generator
cache_filename = f"cache_{tile_size[0]}x{tile_size[1]}_bins{colour_bins}{'_rot' if enable_rotation else ''}.pkl"
generator = ContextualMosaicGenerator(
cache_file=cache_filename,
tile_folder=tile_folder,
tile_size=tile_size,
colour_bins=colour_bins,
enable_rotation=enable_rotation,
enable_face_detection=enable_face_detection,
verbose=verbose,
use_numba=use_numba
)
# Preprocess image
target_width = grid_size[1] * tile_size[0]
target_height = grid_size[0] * tile_size[1]
preprocessor = ImagePreprocessor(
target_resolution=(target_width, target_height),
grid_size=grid_size,
verbose=verbose
)
processed_image = preprocessor.load_and_preprocess_image(
image_path,
apply_quantization=apply_quantization,
n_colors=n_colors
)
if processed_image is None:
raise ValueError("Failed to preprocess image")
# Analyze context (optional)
context = None
if enable_face_detection or show_visualizations:
context = generator.analyze_image_context(processed_image)
# Generate mosaic
mosaic, context = generator.create_contextual_mosaic(
processed_image,
grid_size,
diversity_factor,
context=context,
use_parallel=use_parallel
)
# Visualizations (optional)
if show_visualizations and context is not None:
generator.visualize_context_analysis(processed_image, context)
# Quality evaluation (optional)
metrics = None
if evaluate_quality:
evaluator = PerformanceEvaluator()
metrics = evaluator.evaluate_mosaic_quality(processed_image, mosaic, image_path)
if show_visualizations:
evaluator.visualize_quality_comparison(processed_image, mosaic, metrics)
total_time = time.time() - total_start
if verbose:
print(f"\n✅ Total time: {total_time:.2f}s")
if metrics:
print(f"Quality score: {metrics['overall_quality']:.1f}/100")
return mosaic, metrics, context
def create_mosaic_for_gradio(image_array: np.ndarray,
tile_folder: str = "extracted_images",
grid_size: int = 64,
tile_size: int = 32,
diversity_factor: float = 0.15,
enable_rotation: bool = True) -> Tuple[np.ndarray, str]:
"""Gradio-optimized mosaic creation."""
try:
grid_tuple = (grid_size, grid_size)
tile_tuple = (tile_size, tile_size)
temp_path = "temp_gradio_input.jpg"
cv2.imwrite(temp_path, cv2.cvtColor(image_array, cv2.COLOR_RGB2BGR))
mosaic, metrics, context = create_advanced_mosaic(
image_path=temp_path,
tile_folder=tile_folder,
grid_size=grid_tuple,
tile_size=tile_tuple,
diversity_factor=diversity_factor,
enable_rotation=enable_rotation,
enable_face_detection=False,
use_numba=True,
use_parallel=True,
evaluate_quality=True,
show_visualizations=False,
verbose=False
)
Path(temp_path).unlink(missing_ok=True)
status = f"""Mosaic Generated Successfully!
Configuration:
• Grid: {grid_size}×{grid_size} = {grid_size**2:,} tiles
• Tile size: {tile_size}×{tile_size} pixels
• Optimizations: Numba JIT + Parallel
• Quality score: {metrics['overall_quality']:.1f}/100"""
return mosaic, status
except Exception as e:
return None, f"Error: {str(e)}"
if __name__ == "__main__":
IMAGE_PATH = "Images/EmmaPotrait.jpg"
TILE_FOLDER = "extracted_images"
if not Path(TILE_FOLDER).exists():
print(f"Tile folder not found: {TILE_FOLDER}")
exit(1)
if not Path(IMAGE_PATH).exists():
print(f"Image not found: {IMAGE_PATH}")
exit(1)
print("Creating optimized mosaic (Numba + Parallel)...")
mosaic, metrics, context = create_advanced_mosaic(
image_path=IMAGE_PATH,
tile_folder=TILE_FOLDER,
grid_size=(64, 64),
tile_size=(64, 64),
diversity_factor=0.15,
enable_rotation=True,
enable_face_detection=False,
apply_quantization=False,
use_numba=True,
use_parallel=True,
evaluate_quality=True,
show_visualizations=False,
verbose=True
)
if mosaic is not None:
print("✅ Mosaic generation completed!")
if metrics:
print(f"Quality score: {metrics['overall_quality']:.1f}/100")
cv2.imwrite("output_mosaic.jpg", cv2.cvtColor(mosaic, cv2.COLOR_RGB2BGR))
print("Saved: output_mosaic.jpg")