Spaces:
Sleeping
Sleeping
File size: 1,326 Bytes
b527c11 | 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 | """Illumination correction for nail/skin crops.
Shades-of-Gray (Finlayson & Trezzi 2004) — Minkowski p-norm generalisation
of the gray-world assumption. Standard in photometric calibration pipelines
and what the Tilburg/Sanquin BNAIC paper used (p=6).
"""
from __future__ import annotations
import numpy as np
def shades_of_gray(img: np.ndarray, p: int = 6) -> np.ndarray:
"""Apply Shades-of-Gray colour constancy with Minkowski exponent p.
Args:
img: HxWx3 uint8 OR float in [0,1].
p: Minkowski exponent. p=1 is gray-world, p=inf is max-RGB.
BNAIC used p=6 — a robust middle ground.
Returns:
Corrected HxWx3 uint8.
"""
was_uint8 = img.dtype == np.uint8
x = img.astype(np.float64)
if was_uint8:
x = x / 255.0
# per-channel Lp norm of pixel intensities
Lp = np.power(np.mean(np.power(x, p), axis=(0, 1)), 1.0 / p) # shape (3,)
# normalise so the corrected image preserves overall brightness
# scale by sqrt(3) / ||Lp||_2 so the illuminant is treated as a unit vector toward gray
norm = np.sqrt((Lp ** 2).sum()) + 1e-12
illuminant = Lp / norm * np.sqrt(3)
corrected = x / illuminant
corrected = np.clip(corrected, 0.0, 1.0)
return (corrected * 255.0).astype(np.uint8)
|