Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import numpy as np | |
| from PIL import Image | |
| def pil_to_np(img: Image.Image) -> np.ndarray: | |
| if img.mode not in ("RGB", "RGBA", "L"): | |
| img = img.convert("RGB") | |
| if img.mode == "L": | |
| img = img.convert("RGB") | |
| arr = np.asarray(img).astype(np.float32) | |
| if arr.ndim == 2: | |
| arr = np.repeat(arr[..., None], 3, axis=2) | |
| if arr.shape[2] == 4: | |
| arr = arr[..., :3] | |
| return arr / 255.0 | |
| def np_to_pil(arr: np.ndarray) -> Image.Image: | |
| return Image.fromarray(np.clip(arr * 255.0, 0, 255).astype(np.uint8)) | |
| def resize_and_crop_to_grid(img: Image.Image, width: int, height: int, grid: int) -> Image.Image: | |
| img = img.convert("RGB").resize((width, height), Image.LANCZOS) | |
| H, W = img.height, img.width | |
| H2, W2 = (H // grid) * grid, (W // grid) * grid | |
| if H2 != H or W2 != W: | |
| left = (W - W2) // 2 | |
| top = (H - H2) // 2 | |
| img = img.crop((left, top, left + W2, top + H2)) | |
| return img | |
| def block_view(arr: np.ndarray, bh: int, bw: int) -> np.ndarray: | |
| H, W, C = arr.shape | |
| assert H % bh == 0 and W % bw == 0, "Dims must be divisible by block." | |
| shape = (H//bh, W//bw, bh, bw, C) | |
| strides = (arr.strides[0]*bh, arr.strides[1]*bw, arr.strides[0], arr.strides[1], arr.strides[2]) | |
| return np.lib.stride_tricks.as_strided(arr, shape=shape, strides=strides) | |
| def cell_means(arr: np.ndarray, grid: int) -> np.ndarray: | |
| H, W, _ = arr.shape | |
| bh, bw = H//grid, W//grid | |
| blocks = block_view(arr, bh, bw) | |
| # Use weighted mean with center bias for better detail preservation | |
| # Create a weight matrix that emphasizes the center of each block | |
| center_h, center_w = bh // 2, bw // 2 | |
| weights = np.zeros((bh, bw)) | |
| for i in range(bh): | |
| for j in range(bw): | |
| # Distance from center (normalized) | |
| dist_from_center = np.sqrt((i - center_h)**2 + (j - center_w)**2) | |
| max_dist = np.sqrt(center_h**2 + center_w**2) | |
| # Higher weight for pixels closer to center | |
| weights[i, j] = 1.0 - (dist_from_center / max_dist) * 0.5 | |
| # Normalize weights | |
| weights = weights / np.sum(weights) | |
| # Apply weighted mean | |
| weighted_means = np.zeros((grid, grid, 3)) | |
| for i in range(grid): | |
| for j in range(grid): | |
| block = blocks[i, j] | |
| for c in range(3): | |
| weighted_means[i, j, c] = np.sum(block[:, :, c] * weights) | |
| return weighted_means | |