Spaces:
Sleeping
Sleeping
| """Saliency map computation using pretrained MSI-Net (fallback to heuristic).""" | |
| import numpy as np | |
| from PIL import Image | |
| from scipy.stats import entropy as scipy_entropy | |
| from typing import Dict, Optional | |
| def _compute_heuristic_saliency(img: Image.Image) -> np.ndarray: | |
| """ | |
| Fallback saliency using luminance contrast and color variance. | |
| Returns a pseudo-saliency map in [0,1]. | |
| """ | |
| arr = np.array(img.convert("RGB")).astype(np.float32) | |
| gray = arr.mean(axis=2) | |
| # Compute local contrast via gradient magnitude | |
| dx = np.abs(np.diff(gray, axis=1, append=gray[:, -1:])) | |
| dy = np.abs(np.diff(gray, axis=0, append=gray[-1:, :])) | |
| grad = np.sqrt(dx**2 + dy**2) | |
| # Normalize | |
| sal = grad / (grad.max() + 1e-8) | |
| return sal.astype(np.float32) | |
| def compute_saliency_features(img: Image.Image, saliency_map: Optional[np.ndarray] = None) -> Dict[str, float]: | |
| """ | |
| Compute saliency-based features from an image. | |
| If MSI-Net fails or is not loaded, falls back to heuristic. | |
| """ | |
| if saliency_map is None: | |
| saliency_map = _compute_heuristic_saliency(img) | |
| sal_flat = saliency_map.ravel() | |
| sal_probs = sal_flat / (sal_flat.sum() + 1e-8) | |
| features = {} | |
| # 1. Peak saliency | |
| features["peak_saliency"] = float(saliency_map.max()) | |
| # 2. Mean saliency | |
| features["mean_saliency"] = float(saliency_map.mean()) | |
| # 3. Saliency entropy (spatial spread) | |
| max_entropy = np.log(len(sal_flat) + 1e-8) | |
| features["saliency_entropy"] = float(scipy_entropy(sal_probs + 1e-10)) / max_entropy | |
| # 4. Top-20% fraction | |
| threshold = 0.8 * features["peak_saliency"] | |
| features["top20_fraction"] = float((saliency_map > threshold).sum()) / (saliency_map.size + 1e-8) | |
| # 5. Center saliency (central third) | |
| H, W = saliency_map.shape | |
| h3, w3 = max(1, H // 3), max(1, W // 3) | |
| center_zone = saliency_map[h3:2*h3, w3:2*w3] | |
| features["center_saliency"] = float(center_zone.mean()) | |
| # 6. Saliency uniformity (lower = more varied = more interesting) | |
| features["saliency_uniformity"] = float(saliency_map.std() / (features["mean_saliency"] + 1e-8)) | |
| return features | |