Spaces:
Sleeping
Sleeping
File size: 2,506 Bytes
88b5236 | 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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | """
General utility functions for mvtec-anomaly-benchmark.
Provides formatting, statistics, and image processing helpers.
"""
import numpy as np
from PIL import Image
# =============================================================================
# FORMATTING
# =============================================================================
def format_metric(value, decimals: int = 4) -> str:
"""
Formats a metric value for printing.
Args:
value: Numeric value or None
decimals: Number of decimal places
Returns:
Formatted string
"""
if isinstance(value, float):
return f"{value:.{decimals}f}"
return str(value) if value is not None else "N/A"
# =============================================================================
# STATISTICS
# =============================================================================
def safe_mean(values: list) -> float | None:
"""
Calculates mean ignoring None values.
Args:
values: List of numeric values (may contain None)
Returns:
Mean value or None if no valid values
"""
valid = [v for v in values if v is not None]
return sum(valid) / len(valid) if valid else None
# =============================================================================
# IMAGE PROCESSING
# =============================================================================
def resize_to_match(array: np.ndarray, target_shape: tuple) -> np.ndarray:
"""
Resizes an array to match the target shape.
Args:
array: Input numpy array (2D, values 0-1)
target_shape: Target (height, width) tuple
Returns:
Resized array
"""
if array.shape == target_shape:
return array
scaled = (array * 255).astype(np.uint8)
pil_img = Image.fromarray(scaled)
pil_img = pil_img.resize((target_shape[1], target_shape[0]), Image.BILINEAR)
return np.array(pil_img) / 255.0
def scale_efficientad_score(score: float) -> float:
"""
Scales EfficientAD anomaly score to be more interpretable.
Args:
score: Raw anomaly score
Returns:
Scaled score (0-1 range, pushed towards extremes)
"""
if score < 0.5:
# Good: use power function to push low (e.g. 0.4998 -> ~0.25)
return (score * 2) ** 2 / 4
else:
# Anomaly: steep sigmoid to push high (e.g. 0.5063 -> ~0.96)
k = 500
return 1 / (1 + np.exp(-k * (score - 0.5)))
|