Spaces:
Sleeping
Sleeping
File size: 1,469 Bytes
ca4cce7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import base64
import hashlib
import io
from typing import Tuple
from PIL import Image, ImageStat
def decode_data_url(value: str) -> Image.Image:
"""Decode a base64 data URL (or raw base64) into a normalized RGB image."""
if not value:
raise ValueError("image_base64 is required")
payload = value.split(",", 1)[1] if "," in value else value
try:
raw = base64.b64decode(payload, validate=True)
image = Image.open(io.BytesIO(raw))
image.load()
return image.convert("RGB")
except Exception as exc:
raise ValueError("Invalid base64 image") from exc
def image_fingerprint(image: Image.Image, size: Tuple[int, int] = (16, 16)) -> str:
"""Perceptual-ish hash suitable for avoiding repeat OCR on nearly identical frames."""
thumb = image.convert("L").resize(size)
pixels = list(thumb.getdata())
mean = sum(pixels) / len(pixels)
bits = "".join("1" if pixel >= mean else "0" for pixel in pixels)
return hashlib.sha256(bits.encode()).hexdigest()[:24]
def image_quality(image: Image.Image) -> dict:
gray = image.convert("L")
stat = ImageStat.Stat(gray)
brightness = stat.mean[0]
# Variance is a cheap CPU-only sharpness signal; browser performs the primary check.
variance = stat.var[0]
return {
"brightness": round(brightness, 2),
"contrast": round(variance ** 0.5, 2),
"acceptable": 35 <= brightness <= 225 and variance >= 20,
}
|