Source code for phenotypic.enhance._clahe

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from phenotypic._core._image import Image

from skimage.exposure import equalize_adapthist

from phenotypic.abc_ import ImageEnhancer


[docs] class CLAHE(ImageEnhancer): """Boost local contrast in detect_mat using adaptive histogram equalization. Divides detect_mat into tiles and equalizes the histogram within each tile, with a clip limit that prevents excessive noise amplification. Faint colonies become more visible and easier to threshold, even when illumination varies across the plate. For a discussion of contrast enhancement strategies, see :doc:`/explanation/what_enhancement_does`. Args: kernel_size: Tile size for local equalization. Smaller tiles reveal tiny colonies but amplify agar texture; larger tiles produce smoother results. ``None`` auto-selects based on image size (typically min(height, width) / 15). Default: ``None``. clip_limit: Maximum local contrast amplification. Typical range: 0.005--0.05. Lower values suppress noise; higher values make faint colonies stand out more. Default: 0.01. Returns: Image: Input image with ``detect_mat`` contrast-enhanced. ``rgb`` and ``gray`` are unchanged. Raises: ValueError: If the detect_mat value range is invalid. Best For: - Plates with faint or translucent colonies that blend into agar. - Uneven illumination (vignetting, shadows from plate lids). - Pre-conditioning before global thresholding (Otsu, Triangle). - Early time-point plates where colonies are barely visible. Consider Also: - :class:`ContrastStretching` for a simpler global contrast adjustment when illumination is already uniform. - :class:`HomomorphicFilter` when the primary problem is a large-scale illumination gradient rather than local contrast. - :class:`UnsharpMask` when edges need sharpening rather than contrast boosting. References: [1] S. M. Pizer et al., "Adaptive histogram equalization and its variations," *Computer Vision, Graphics, and Image Processing*, vol. 39, no. 3, pp. 355--368, Sep. 1987. See Also: :doc:`/tutorials/notebooks/03_enhancing_before_detection` for a visual walkthrough of CLAHE before detection. :doc:`/how_to/notebooks/enhance_low_contrast` for a comparison of contrast enhancement methods. """
[docs] def __init__( self, kernel_size: int | None = None, clip_limit: float = 0.01, ): """ Parameters: kernel_size (int | None): Tile size for adaptive equalization. Smaller tiles enhance very local contrast (revealing tiny colonies) but can amplify agar texture; larger tiles produce smoother, gentler effects. None selects an automatic size based on image dimensions. clip_limit (float): Maximum local contrast amplification. Lower values reduce noise/halo amplification; higher values make faint colonies stand out more but can emphasize dust or condensation. """ self.kernel_size: int = kernel_size self.clip_limit: float = clip_limit
def _operate(self, image: Image) -> Image: try: image.detect_mat[:] = equalize_adapthist( image=image.detect_mat[:], kernel_size=self.kernel_size if self.kernel_size else self._auto_kernel_size(image), clip_limit=self.clip_limit, nbins=2 ** int(image.bit_depth), ) return image except RuntimeError as e: raise ValueError(f"Value Range: {image.detect_mat.val_range()}") from e @staticmethod def _auto_kernel_size(image: Image) -> int: return int(min(image.gray.shape[:1]) * (1.0 / 15.0))