| |
| |
|
|
| import numpy as np |
| from PIL import Image |
| from collections import deque, Counter |
|
|
| class GraphicProcessor: |
| """Classical fallback for simple graphics - FROZEN.""" |
| |
| def __init__(self): |
| self.tolerance = 25 |
| |
| def remove_background(self, image: Image.Image) -> Image.Image: |
| """Remove background using flood fill.""" |
| if image.mode != 'RGBA': |
| image = image.convert('RGBA') |
| |
| np_img = np.array(image) |
| h, w = np_img.shape[:2] |
| |
| |
| bg_colors = self._find_background_colors(np_img) |
| |
| |
| mask = np.ones((h, w), dtype=np.uint8) * 255 |
| |
| |
| for bg_color in bg_colors: |
| self._flood_fill_from_border(np_img, mask, bg_color) |
| |
| |
| fg_ratio = np.sum(mask > 128) / (h * w) |
| if fg_ratio < 0.05 or fg_ratio > 0.95: |
| |
| mask = np.ones((h, w), dtype=np.uint8) * 255 |
| for bg_color in bg_colors: |
| self._flood_fill_from_border(np_img, mask, bg_color, tolerance=15) |
| |
| |
| result = np_img.copy() |
| result[mask == 0, 3] = 0 |
| |
| return Image.fromarray(result, 'RGBA') |
| |
| def _find_background_colors(self, np_img: np.ndarray) -> list: |
| h, w = np_img.shape[:2] |
| border_pixels = [] |
| |
| for x in range(w): |
| border_pixels.append(tuple(np_img[0, x][:3])) |
| border_pixels.append(tuple(np_img[h-1, x][:3])) |
| for y in range(h): |
| border_pixels.append(tuple(np_img[y, 0][:3])) |
| border_pixels.append(tuple(np_img[y, w-1][:3])) |
| |
| counter = Counter(border_pixels) |
| return [color for color, _ in counter.most_common(3)] |
| |
| def _flood_fill_from_border(self, np_img: np.ndarray, mask: np.ndarray, bg_color: tuple, tolerance: int = 25): |
| h, w = np_img.shape[:2] |
| queue = deque() |
| visited = set() |
| |
| for x in range(w): |
| queue.append((0, x)) |
| queue.append((h-1, x)) |
| visited.add((0, x)) |
| visited.add((h-1, x)) |
| for y in range(h): |
| queue.append((y, 0)) |
| queue.append((y, w-1)) |
| visited.add((y, 0)) |
| visited.add((y, w-1)) |
| |
| dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)] |
| br, bg, bb = bg_color |
| |
| while queue: |
| y, x = queue.popleft() |
| r, g, b = np_img[y, x][:3] |
| |
| color_diff = np.sqrt((r - br)**2 + (g - bg)**2 + (b - bb)**2) |
| |
| if color_diff < tolerance: |
| mask[y, x] = 0 |
| for dy, dx in dirs: |
| ny, nx = y + dy, x + dx |
| if 0 <= ny < h and 0 <= nx < w and (ny, nx) not in visited: |
| queue.append((ny, nx)) |
| visited.add((ny, nx)) |