face-intel / cores /vision /decode.py
Marwan
Restructure + add reverse face search (PimEyes-style)
f5eeb1c
Raw
History Blame Contribute Delete
3.33 kB
"""Decode / encode β€” bytes ↔ numpy ↔ base64 ↔ URL."""
from __future__ import annotations
import base64
from typing import Optional
import cv2
import numpy as np
import requests
# --------------------------------------------------------------------------- #
# Bytes ↔ numpy
# --------------------------------------------------------------------------- #
def bytes_to_numpy(image_bytes: bytes) -> np.ndarray:
"""Decode raw image bytes into an OpenCV BGR numpy array."""
nparr = np.frombuffer(image_bytes, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if img is None:
raise ValueError("Could not decode image bytes. Unsupported format or corrupted data.")
return img
def numpy_to_bytes(img: np.ndarray, fmt: str = ".jpg", quality: int = 90) -> bytes:
"""Encode a BGR numpy array to raw bytes."""
params = [cv2.IMWRITE_JPEG_QUALITY, quality] if fmt.lower() in (".jpg", ".jpeg") else []
ok, buffer = cv2.imencode(fmt, img, params)
if not ok:
raise ValueError("Could not encode image.")
return buffer.tobytes()
# --------------------------------------------------------------------------- #
# Base64
# --------------------------------------------------------------------------- #
def base64_to_numpy(b64_string: str) -> np.ndarray:
"""Decode a base64-encoded image string into a BGR numpy array."""
if "," in b64_string:
b64_string = b64_string.split(",", 1)[1]
raw = base64.b64decode(b64_string)
return bytes_to_numpy(raw)
def numpy_to_base64(img: np.ndarray, fmt: str = ".jpg", quality: int = 85) -> str:
"""Encode a BGR numpy array as a base64 string."""
return base64.b64encode(numpy_to_bytes(img, fmt, quality)).decode("utf-8")
# --------------------------------------------------------------------------- #
# URL
# --------------------------------------------------------------------------- #
_DEFAULT_HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"}
def url_to_bytes(url: str, timeout: int = 15) -> bytes:
"""Download a URL and return raw bytes."""
resp = requests.get(url, headers=_DEFAULT_HEADERS, timeout=timeout, stream=True)
resp.raise_for_status()
return resp.content
def url_to_numpy(url: str, timeout: int = 15) -> np.ndarray:
"""Download an image from a URL and return it as a BGR numpy array."""
return bytes_to_numpy(url_to_bytes(url, timeout))
# --------------------------------------------------------------------------- #
# Format sniffing (magic bytes)
# --------------------------------------------------------------------------- #
_IMAGE_SIGNATURES = {
b"\xff\xd8\xff": "jpeg",
b"\x89PNG\r\n\x1a\n": "png",
b"GIF87a": "gif",
b"GIF89a": "gif",
b"BM": "bmp",
b"II*\x00": "tiff",
b"MM\x00*": "tiff",
}
def sniff_format(data: bytes) -> Optional[str]:
"""Identify image format from magic bytes. Returns None if unknown."""
if not data or len(data) < 12:
return None
for sig, fmt in _IMAGE_SIGNATURES.items():
if data.startswith(sig):
if sig == b"RIFF" and data[8:12] != b"WEBP":
continue
return fmt
# RIFF/WEBP (4-byte prefix overlap with RIFF)
if data[:4] == b"RIFF" and data[8:12] == b"WEBP":
return "webp"
return None