Source code for phenotypic.enhance._rolling_ball_remove_bg

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from phenotypic import Image

import numpy as np
from skimage.restoration import rolling_ball

from phenotypic.abc_ import ImageEnhancer


[docs] class RollingBallRemoveBG(ImageEnhancer): """ Rolling-ball background removal (ImageJ-style) for agar plates. Models the background as the surface traced by rolling a ball under the image intensity landscape, then subtracts it. For colony images, this effectively removes slow illumination gradients and agar shading while preserving colony structures. Use cases (agar plates): - Correct uneven backgrounds from scanner vignetting, lid glare, or agar thickness variations. - Improve segmentation of dark colonies on bright agar by flattening the background. Tuning and effects: - radius: Core scale of the rolling ball. Set larger than typical colony diameter so colonies are not smoothed into the background. Too small a radius will erode colonies and create halos. - kernel: Custom structuring element defining the ball shape. Providing a kernel overrides `radius` and allows non-spherical shapes if needed. - nansafe: Enable if your images contain masked/NaN regions (e.g., plate outside masked to NaN). When False, NaNs may propagate or cause artifacts. Caveats: - Overly small radius removes real features and can bias size/area metrics. - May introduce edge effects near the plate boundary; consider masking the plate region or using `nansafe` with an appropriate mask. Attributes: radius (int): Ball radius (in pixels) controlling the background scale; choose > colony diameter. kernel (np.ndarray): Optional custom kernel; overrides `radius` when set. nansafe (bool): Handle NaNs during computation to respect masked regions. """
[docs] def __init__( self, radius: int = 100, kernel: np.ndarray = None, nansafe: bool = False ): """ Parameters: radius (int): Rolling-ball radius (pixels). Use a value larger than colony diameter to avoid removing colony signal. Default 100. kernel (np.ndarray): Optional custom ball/footprint; when provided it overrides `radius`. nansafe (bool): If True, treat NaNs as missing data to avoid artifacts when using masked images (e.g., outside the plate). """ self.radius: int = radius self.kernel: np.ndarray = kernel self.nansafe: bool = nansafe
def _operate(self, image: Image): image.enh_gray[:] = image.enh_gray[:] - rolling_ball( image=image.enh_gray[:], radius=self.radius, kernel=self.kernel, nansafe=self.nansafe, ) return image