Spaces:
Sleeping
Sleeping
| import numpy as np | |
| import cv2 | |
| from sklearn.cluster import KMeans | |
| from PIL import Image | |
| from logic.validation import ValidationError, ensure_positive_int | |
| IMAGE_SIZE = 400 | |
| SAMPLE_SIZE = 50000 | |
| def resize_img(image: Image.Image, size: int = IMAGE_SIZE) -> Image.Image: | |
| """Resize an image to a square of the requested size. | |
| Args: | |
| image (PIL.Image.Image): Image to resize. | |
| size (int, optional): Target side length in pixels. Defaults to ``IMAGE_SIZE``. | |
| Returns: | |
| PIL.Image.Image: Cropped and resized copy in RGB. | |
| Raises: | |
| ValidationError: If ``size`` is not positive. | |
| Example: | |
| >>> resized = resize_img(Image.open('input.png'), 512) | |
| """ | |
| ensure_positive_int(size, "Image size", minimum=32) | |
| width, height = image.size | |
| if width != height: | |
| min_size = min(width, height) | |
| left = (width - min_size) // 2 | |
| top = (height - min_size) // 2 | |
| image = image.crop((left, top, left + min_size, top + min_size)) | |
| resized_img = image.resize((size, size), Image.Resampling.LANCZOS) | |
| return resized_img | |
| def color_quantize(image: Image.Image, n_colors: int = 16): | |
| """Reduce the number of colors with KMeans clustering. | |
| Args: | |
| image (PIL.Image.Image): Image to quantize. | |
| n_colors (int, optional): Number of clusters. Defaults to 16. | |
| Returns: | |
| tuple[PIL.Image.Image, np.ndarray]: Quantized image and cluster centers in BGR order. | |
| Raises: | |
| ValidationError: If ``n_colors`` is outside ``[2, 64]``. | |
| """ | |
| ensure_positive_int(n_colors, "Color palette size", minimum=2, maximum=64) | |
| img_np = np.array(image) | |
| original_shape = img_np.shape | |
| img_flat = img_np.reshape(-1, 3) | |
| sample_size = min(SAMPLE_SIZE, img_flat.shape[0]) | |
| indices = np.random.choice(img_flat.shape[0], sample_size, replace=False) | |
| img_sample = img_flat[indices] | |
| kmeans = KMeans( | |
| n_clusters=n_colors, | |
| random_state=42, | |
| init='k-means++', | |
| n_init=5, | |
| max_iter=100, | |
| tol=1e-3, | |
| algorithm='lloyd' | |
| ) | |
| kmeans.fit(img_sample) | |
| labels = kmeans.predict(img_flat) | |
| quantized_flat = kmeans.cluster_centers_[labels].astype(np.uint8) | |
| quantized_img_np = quantized_flat.reshape(original_shape) | |
| quantized_img = Image.fromarray(quantized_img_np) | |
| color_centers = kmeans.cluster_centers_.astype(np.uint8) | |
| color_centers = color_centers[:, [2, 1, 0]] # Swap R and B channels | |
| return quantized_img, color_centers | |