Spaces:
Running
Running
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| import io | |
| def load_image(source) -> np.ndarray: | |
| """ | |
| Load an image from a file path, PIL Image, bytes, BytesIO, | |
| or Streamlit UploadedFile. Returns BGR numpy array. | |
| """ | |
| if isinstance(source, np.ndarray): | |
| return source | |
| if isinstance(source, str): | |
| img = cv2.imread(source) | |
| if img is None: | |
| raise FileNotFoundError(f"Cannot read image: {source}") | |
| return img | |
| # BytesIO or file-like (Streamlit UploadedFile) | |
| if hasattr(source, "read"): | |
| data = source.read() | |
| elif isinstance(source, (bytes, bytearray)): | |
| data = source | |
| else: | |
| # Try reading as bytes | |
| data = bytes(source.getvalue()) if hasattr(source, "getvalue") else bytes(source) | |
| arr = np.frombuffer(data, np.uint8) | |
| img = cv2.imdecode(arr, cv2.IMREAD_COLOR) | |
| if img is None: | |
| # Fallback via PIL | |
| pil_img = Image.open(io.BytesIO(data)).convert("RGB") | |
| img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) | |
| return img | |
| def save_image(image: np.ndarray, path: str, quality: int = 95) -> None: | |
| """Save a BGR numpy array to disk.""" | |
| ext = path.rsplit(".", 1)[-1].lower() | |
| params = [] | |
| if ext in ("jpg", "jpeg"): | |
| params = [cv2.IMWRITE_JPEG_QUALITY, quality] | |
| elif ext == "png": | |
| params = [cv2.IMWRITE_PNG_COMPRESSION, 3] | |
| cv2.imwrite(path, image, params) | |
| def resize_keep_aspect(image: np.ndarray, max_size: int = 1024) -> np.ndarray: | |
| """Resize image so the longest side <= max_size, maintaining aspect ratio.""" | |
| h, w = image.shape[:2] | |
| scale = min(max_size / h, max_size / w, 1.0) | |
| if scale == 1.0: | |
| return image | |
| new_w, new_h = int(w * scale), int(h * scale) | |
| return cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_AREA) | |
| def image_to_bytes(image: np.ndarray, fmt: str = "PNG") -> bytes: | |
| """Convert BGR numpy array to encoded bytes.""" | |
| rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | |
| pil_img = Image.fromarray(rgb) | |
| buf = io.BytesIO() | |
| pil_img.save(buf, format=fmt) | |
| return buf.getvalue() | |