# contentClassifier.py - Lightweight Content Detection # FROZEN - DO NOT MODIFY import numpy as np from PIL import Image from collections import Counter class ContentClassifier: """Lightweight content detection - FROZEN.""" def __init__(self): self.categories = [ 'simple_graphic', 'human_hair', 'human', 'anime', 'logo_icon', 'product_white_bg', 'general_photo', 'complex' ] def classify(self, image: Image.Image) -> dict: """Classify image content.""" if image.mode != 'RGB': image = image.convert('RGB') small = image.copy() small.thumbnail((150, 150), Image.Resampling.LANCZOS) np_img = np.array(small) h, w = np_img.shape[:2] signals = { 'dimensions': (w, h), 'aspect_ratio': h / w if w > 0 else 0, 'border_uniformity': self._border_uniformity(np_img), 'edge_density': self._edge_density(np_img), 'color_complexity': self._color_complexity(small), 'skin_score': self._skin_score(np_img), 'border_connected': self._border_connected(np_img), 'texture': self._texture(np_img) } category = self._classify(signals) confidence = self._calculate_confidence(category, signals) return { 'category': category, 'confidence': confidence, 'signals': signals } def _border_uniformity(self, np_img: np.ndarray) -> float: h, w = np_img.shape[:2] border_pixels = [] step = max(1, min(h, w) // 10) for x in range(0, w, step): border_pixels.append(tuple(np_img[0, x][:3])) border_pixels.append(tuple(np_img[h-1, x][:3])) for y in range(0, h, step): border_pixels.append(tuple(np_img[y, 0][:3])) border_pixels.append(tuple(np_img[y, w-1][:3])) if not border_pixels: return 0.0 unique = len(set(border_pixels)) return 1 - (unique / len(border_pixels)) def _edge_density(self, np_img: np.ndarray) -> float: gray = np.mean(np_img, axis=2).astype(np.float32) grad_x = np.abs(gray[:, 1:] - gray[:, :-1]) grad_y = np.abs(gray[1:, :] - gray[:-1, :]) edges = (grad_x > 25).sum() + (grad_y > 25).sum() total = (gray.shape[0] - 1) * gray.shape[1] + gray.shape[0] * (gray.shape[1] - 1) return edges / total if total > 0 else 0 def _color_complexity(self, image: Image.Image) -> float: quantized = image.quantize(colors=32) unique = len(quantized.getcolors()) return min(1.0, unique / 32) def _skin_score(self, np_img: np.ndarray) -> float: h, w = np_img.shape[:2] pixels = [] step = max(1, min(h, w) // 5) for y in range(0, h, step): for x in range(0, w, step): pixels.append(np_img[y, x][:3]) skin = 0 for r, g, b in pixels: if (r > 60 and g > 40 and b > 20 and r > g and r > b and abs(r - g) < 60 and abs(r - b) < 60): skin += 1 return skin / len(pixels) if pixels else 0 def _border_connected(self, np_img: np.ndarray) -> float: h, w = np_img.shape[:2] border_colors = set() border_colors.add(tuple(np_img[0, 0][:3])) border_colors.add(tuple(np_img[0, w-1][:3])) border_colors.add(tuple(np_img[h-1, 0][:3])) border_colors.add(tuple(np_img[h-1, w-1][:3])) interior_colors = set() step = max(1, min(h, w) // 4) for y in range(h//4, 3*h//4, step): for x in range(w//4, 3*w//4, step): interior_colors.add(tuple(np_img[y, x][:3])) overlap = border_colors & interior_colors return len(overlap) / max(len(border_colors), 1) def _texture(self, np_img: np.ndarray) -> float: gray = np.mean(np_img, axis=2).astype(np.float32) variance = np.var(gray) return min(1.0, variance / 5000) def _classify(self, signals: dict) -> str: s = signals # Simple graphic if (s['color_complexity'] < 0.3 and s['edge_density'] > 0.3 and s['border_uniformity'] > 0.7): return 'simple_graphic' # Human with hair if (s['skin_score'] > 0.15 and s['texture'] > 0.3 and s['edge_density'] > 0.2): return 'human_hair' # Human if s['skin_score'] > 0.1: return 'human' # Anime if (s['skin_score'] < 0.08 and s['color_complexity'] > 0.3 and s['texture'] < 0.3 and s['edge_density'] > 0.3): return 'anime' # Logo/icon if (s['edge_density'] > 0.4 and s['color_complexity'] < 0.3 and s['border_uniformity'] > 0.6): return 'logo_icon' # Product on white bg if (s['border_uniformity'] > 0.6 and s['color_complexity'] < 0.5 and s['edge_density'] < 0.4): return 'product_white_bg' # General photo if s['color_complexity'] > 0.3: return 'general_photo' return 'complex' def _calculate_confidence(self, category: str, signals: dict) -> float: base = 0.7 if category == 'simple_graphic': if signals['border_uniformity'] > 0.8: base += 0.2 elif category == 'human_hair': if signals['skin_score'] > 0.2 and signals['texture'] > 0.4: base += 0.2 elif category == 'human': if signals['skin_score'] > 0.15: base += 0.2 return min(1.0, base)