Style / image_utils.py
nexusbert's picture
modularization
ab2012f
import base64
from PIL import Image
import requests
from io import BytesIO
import numpy as np
def is_placeholder_image(image: Image.Image) -> bool:
img_array = np.array(image)
if len(img_array.shape) != 3:
return True
height, width = img_array.shape[:2]
gray = np.mean(img_array, axis=2)
unique_colors = len(np.unique(gray))
if unique_colors < 10:
return True
black_white_ratio = np.sum((gray < 20) | (gray > 235)) / (height * width)
if black_white_ratio > 0.8:
return True
std_dev = np.std(gray)
if std_dev < 15:
return True
sample_size = min(100, height // 10, width // 10)
if sample_size < 2:
return False
step_h = height // sample_size
step_w = width // sample_size
grid_pattern = True
for i in range(0, height - step_h, step_h):
for j in range(0, width - step_w, step_w):
block = gray[i:i+step_h, j:j+step_w]
block_std = np.std(block)
if block_std > 30:
grid_pattern = False
break
if not grid_pattern:
break
if grid_pattern and black_white_ratio > 0.5:
return True
return False
def load_image_from_url(url_or_base64: str) -> Image.Image:
try:
if url_or_base64.startswith("data:image"):
header, encoded = url_or_base64.split(",", 1)
image_data = base64.b64decode(encoded)
return Image.open(BytesIO(image_data)).convert("RGB")
else:
response = requests.get(url_or_base64, timeout=10)
response.raise_for_status()
return Image.open(BytesIO(response.content)).convert("RGB")
except Exception as e:
raise ValueError(f"Failed to load image: {str(e)}")
def filter_valid_images(images: list) -> list:
valid_images = []
for img in images:
if not img or not isinstance(img, str) or img.strip() in ["", "string", "null", "undefined"]:
continue
try:
pil_image = load_image_from_url(img)
if not is_placeholder_image(pil_image):
valid_images.append(pil_image)
else:
print(f"[IMAGE FILTER] Ignoring placeholder/empty image")
except Exception as e:
print(f"[IMAGE FILTER] Warning: Failed to load image: {e}, skipping")
continue
return valid_images