bgremove / contentClassifier.py
andevs's picture
Create contentClassifier.py
cc1d1af verified
Raw
History Blame Contribute Delete
6.01 kB
# 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)