Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import numpy as np | |
| from PIL import Image | |
| from sklearn.cluster import KMeans | |
| from .utils import pil_to_np, np_to_pil | |
| from .config import Config | |
| def apply_uniform_quantization(image: Image.Image, levels: int) -> Image.Image: | |
| """ | |
| Apply uniform color quantization to reduce color variations. | |
| Args: | |
| image: Input PIL Image | |
| levels: Number of quantization levels per channel | |
| Returns: | |
| Quantized PIL Image | |
| """ | |
| img_array = pil_to_np(image) | |
| # Quantize each channel uniformly | |
| quantized = np.zeros_like(img_array) | |
| for channel in range(3): | |
| # Create quantization levels | |
| channel_data = img_array[:, :, channel] | |
| # Uniform quantization | |
| quantized_channel = np.round(channel_data * (levels - 1)) / (levels - 1) | |
| quantized_channel = np.clip(quantized_channel, 0, 1) | |
| quantized[:, :, channel] = quantized_channel | |
| return np_to_pil(quantized) | |
| def apply_kmeans_quantization(image: Image.Image, k_colors: int) -> Image.Image: | |
| """ | |
| Apply K-means clustering for color quantization. | |
| Args: | |
| image: Input PIL Image | |
| k_colors: Number of colors to reduce to | |
| Returns: | |
| Quantized PIL Image | |
| """ | |
| img_array = pil_to_np(image) | |
| h, w, c = img_array.shape | |
| # Reshape image to list of pixels | |
| pixels = img_array.reshape(-1, c) | |
| # Apply K-means clustering | |
| kmeans = KMeans(n_clusters=k_colors, random_state=42, n_init=10) | |
| kmeans.fit(pixels) | |
| # Replace each pixel with its cluster center | |
| labels = kmeans.labels_ | |
| quantized_pixels = kmeans.cluster_centers_[labels] | |
| # Reshape back to image | |
| quantized_img = quantized_pixels.reshape(h, w, c) | |
| return np_to_pil(quantized_img) | |
| def apply_color_quantization(image: Image.Image, config: Config) -> Image.Image: | |
| """ | |
| Apply color quantization based on configuration. | |
| Args: | |
| image: Input PIL Image | |
| config: Configuration object | |
| Returns: | |
| Quantized PIL Image | |
| """ | |
| if config.use_uniform_q: | |
| return apply_uniform_quantization(image, config.q_levels) | |
| elif config.use_kmeans_q: | |
| return apply_kmeans_quantization(image, config.k_colors) | |
| else: | |
| # No quantization | |
| return image | |
| def analyze_quantization_effect(original: Image.Image, quantized: Image.Image) -> dict: | |
| """ | |
| Analyze the effect of quantization on the image. | |
| Args: | |
| original: Original image | |
| quantized: Quantized image | |
| Returns: | |
| Dictionary with analysis results | |
| """ | |
| orig_array = pil_to_np(original) | |
| quant_array = pil_to_np(quantized) | |
| # Calculate differences | |
| diff = np.abs(orig_array - quant_array) | |
| # Calculate statistics | |
| mse = np.mean((orig_array - quant_array) ** 2) | |
| psnr = 20 * np.log10(1.0 / np.sqrt(mse)) if mse > 0 else float('inf') | |
| # Count unique colors | |
| orig_colors = len(np.unique(orig_array.reshape(-1, 3), axis=0)) | |
| quant_colors = len(np.unique(quant_array.reshape(-1, 3), axis=0)) | |
| return { | |
| 'mse': float(mse), | |
| 'psnr': float(psnr), | |
| 'mean_difference': float(np.mean(diff)), | |
| 'max_difference': float(np.max(diff)), | |
| 'original_colors': orig_colors, | |
| 'quantized_colors': quant_colors, | |
| 'color_reduction_ratio': orig_colors / quant_colors if quant_colors > 0 else float('inf') | |
| } | |