Mosaic_Generator / src /quantization.py
Teoman21's picture
-done mosaic generator
4376584
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')
}