Source code for phenotypic.enhance._white_tophat_enhance
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from phenotypic._core._image import Image
import numpy as np
from skimage.morphology import white_tophat
from phenotypic.abc_ import ImageEnhancer
[docs]
class WhiteTophatEnhance(ImageEnhancer):
"""Isolate small bright structures in ``detect_mat`` with the white top-hat transform.
Computes the white top-hat (original minus morphological opening) and
retains the result, extracting bright features smaller than the
structuring element while suppressing larger background structures.
Highlights small bright colonies, inocula, or specks against uneven
illumination.
For algorithm details, see :doc:`/explanation/what_enhancement_does`.
Args:
shape: Footprint geometry. ``'disk'`` (default) preserves rounded
colony shapes; ``'diamond'`` is computationally efficient;
``'square'`` can align with sensor grid artifacts.
width: Maximum bright-object size (pixels) targeted for extraction.
Set slightly larger than the maximum size of colonies you want
to isolate. ``None`` (default) derives a small value from
image dimensions.
Returns:
Image: Input image with ``detect_mat`` containing only the
extracted small bright structures. ``rgb`` and ``gray`` are
unchanged.
Raises:
ValueError: If an unsupported footprint shape is provided.
Best For:
- Isolating small bright colonies from larger background structures.
- Highlighting faint small colonies against uneven illumination.
- Extracting tiny bright specks for detection or quantification.
- Preprocessing before detecting small colony phenotypes.
Consider Also:
- :class:`SubtractWhiteTophat` when you want to suppress (not
isolate) small bright artifacts.
- :class:`OpeningSubtractBg` for OpenCV-accelerated white top-hat
background subtraction.
- :class:`MultiscaleLoGEnhancer` for scale-invariant blob detection
that responds to both small and large colonies.
See Also:
:doc:`/tutorials/notebooks/03_enhancing_before_detection` for a
visual walkthrough of morphological enhancement on plate images.
"""
def __init__(self, shape: str = "disk", width: int = None):
super().__init__()
self.shape = shape
self.width = width
def _operate(self, image: Image) -> Image:
white_tophat_results = white_tophat(
image.detect_mat[:],
footprint=self._get_footprint(
self._get_footprint_width(detection_matrix=image.detect_mat[:]),
),
)
image.detect_mat[:] = white_tophat_results
return image
def _get_footprint_width(self, detection_matrix: np.ndarray) -> int:
if self.width is None:
return int(np.min(detection_matrix.shape) * 0.004)
else:
return self.width
def _get_footprint(self, width: int) -> np.ndarray:
match self.shape:
# Use shared ImageEnhancer utility for common 2D shapes
case "disk" | "square" | "diamond":
return self._make_footprint(shape=self.shape, width=width)
case _:
raise ValueError(f"Unsupported footprint shape: {self.shape}")