# graphicProcessor.py - Classical Fallback for Graphics # FROZEN - DO NOT MODIFY 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] # Find background colors bg_colors = self._find_background_colors(np_img) # Create mask mask = np.ones((h, w), dtype=np.uint8) * 255 # Flood fill from border with each color for bg_color in bg_colors: self._flood_fill_from_border(np_img, mask, bg_color) # Check if mask is suspicious fg_ratio = np.sum(mask > 128) / (h * w) if fg_ratio < 0.05 or fg_ratio > 0.95: # Try with different tolerance 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) # Apply mask 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))