Venket / src /augmentation /albumentations_effects.py
venki101's picture
Add files using upload-large-folder tool
1a12965 verified
Raw History Blame Contribute Delete
3.47 kB
"""Thin, deterministic wrappers around Albumentations transforms.
Every wrapper collapses the transform's own randomized magnitude range down
to values derived from our ``strength in [0, 1]`` convention, and executes
via a freshly seeded ``A.Compose`` so results are fully reproducible under
:mod:`src.utils.random_utils` seed derivation rather than Albumentations'
global random state.
"""
from __future__ import annotations
import albumentations as A
import numpy as np
def _run(transform: "A.BasicTransform", image: np.ndarray, seed: int) -> np.ndarray:
pipeline = A.Compose([transform], seed=seed, p=1.0)
return pipeline(image=image)["image"]
def motion_blur(image: np.ndarray, strength: float, seed: int) -> np.ndarray:
"""Directional motion blur; ``strength`` controls kernel size (3..21 px)."""
k = int(round(3 + strength * 18))
k = k + 1 if k % 2 == 0 else k
k = max(3, min(k, 21))
return _run(A.MotionBlur(blur_limit=(k, k), p=1.0), image, seed)
def gaussian_blur(image: np.ndarray, strength: float, seed: int) -> tuple[np.ndarray, float]:
"""Isotropic Gaussian blur; ``strength`` controls sigma (0.2..4.0 px)."""
sigma = round(0.2 + strength * 3.8, 3)
out = _run(A.GaussianBlur(blur_limit=0, sigma_limit=(sigma, sigma), p=1.0), image, seed)
return out, sigma
def perspective_warp(image: np.ndarray, strength: float, seed: int) -> np.ndarray:
"""Subtle perspective distortion; ``strength`` controls corner-jitter scale."""
scale = round(0.01 + strength * 0.09, 4)
return _run(A.Perspective(scale=(scale, scale), keep_size=True, fit_output=False, p=1.0), image, seed)
def contrast_shift(image: np.ndarray, strength: float, seed: int) -> np.ndarray:
"""Global contrast shift; ``strength`` controls the max +/- magnitude."""
mag = round(strength * 0.45, 4)
t = A.RandomBrightnessContrast(brightness_limit=(0.0, 0.0), contrast_limit=(-mag, mag), p=1.0)
return _run(t, image, seed)
def gamma_shift(image: np.ndarray, strength: float, seed: int) -> tuple[np.ndarray, int]:
"""Gamma correction; ``strength`` controls deviation from gamma=100."""
delta = int(round(strength * 45))
lo, hi = max(100 - delta, 40), 100 + delta
out = _run(A.RandomGamma(gamma_limit=(lo, hi), p=1.0), image, seed)
return out, lo if lo != hi else lo
def jpeg_compression(image: np.ndarray, min_quality: int, max_quality: int, seed: int) -> tuple[np.ndarray, int]:
"""JPEG re-compression artifact simulation over ``[min_quality, max_quality]``."""
rng = np.random.default_rng(seed)
quality = int(rng.integers(min_quality, max_quality + 1))
out = _run(A.ImageCompression(compression_type="jpeg", quality_range=(quality, quality), p=1.0), image, seed)
return out, quality
def salt_and_pepper(image: np.ndarray, strength: float, seed: int) -> np.ndarray:
"""Salt-and-pepper impulse noise; ``strength`` controls the affected pixel fraction."""
amount = round(0.002 + strength * 0.09, 5)
t = A.SaltAndPepper(amount=(amount, amount), salt_vs_pepper=(0.45, 0.55), p=1.0)
return _run(t, image, seed)
def sensor_noise(image: np.ndarray, strength: float, seed: int) -> np.ndarray:
"""Gaussian sensor/scanner noise; ``strength`` controls the noise std as a fraction of range."""
std = round(0.01 + strength * 0.12, 5)
t = A.GaussNoise(std_range=(std, std), mean_range=(0.0, 0.0), per_channel=False, p=1.0)
return _run(t, image, seed)