Source code for phenotypic.enhance._subtract_opening
from __future__ import annotations
from typing import Annotated, Literal, TYPE_CHECKING
import cv2
if TYPE_CHECKING:
from phenotypic._core._image import Image
from phenotypic.abc_ import BackgroundSubtraction
from phenotypic.sdk_.mixin import FootprintMixin
from phenotypic.sdk_.typing_ import TuneSpec
[docs]
class SubtractOpening(BackgroundSubtraction, FootprintMixin):
"""Subtract background from ``detect_mat`` via OpenCV-accelerated morphological opening.
Computes the white top-hat transform (original minus morphological
opening) using OpenCV's C++/SIMD backend, isolating bright foreground
structures smaller than the structuring element while discarding
slow-varying background intensity. Significantly faster than
scikit-image equivalents for high-throughput workflows.
For algorithm details, see :doc:`/explanation/what_enhancement_does`.
Best For:
- Fast background subtraction for high-throughput plate screening
or parameter sweeps.
- Removing uneven illumination gradients and agar shading before
colony detection.
- Large-batch pipelines where speed is a priority and a flat
structuring element is acceptable.
- Drop-in acceleration when :class:`SubtractRollingBall` is the
accuracy reference but runtime is the constraint.
Consider Also:
- :class:`SubtractRollingBall` for parabolic background estimation
that handles gradual, non-uniform intensity ramps more
accurately.
- :class:`SubtractGaussian` for Gaussian-based subtraction with
continuous control over the background scale.
- :class:`WhiteTophatEnhance` when you want to retain only the
extracted small bright structures rather than a corrected image.
Args:
shape: Structuring element geometry. Accepted values: ``'disk'``
(default) for isotropic removal suited to round colonies;
``'square'`` for fastest computation; ``'diamond'`` as a
compromise between the two.
width: Diameter of the structuring element in pixels. Must exceed
the largest colony diameter to avoid including colony pixels
in the background estimate. Typical range: 31--101. Default:
51.
n_iter: Number of morphological opening iterations. Additional
iterations intensify background removal at the cost of
eroding fine colony structure. Default: 1.
Returns:
Image: Input image with ``detect_mat`` containing only foreground
structures smaller than the structuring element. ``rgb`` and
``gray`` are unchanged.
See Also:
:doc:`/tutorials/notebooks/03_enhancing_before_detection` for a
visual walkthrough of background subtraction on plate images.
:doc:`/explanation/what_enhancement_does` for background on
morphological background removal strategies.
"""
shape: Literal["square", "diamond", "disk"] = "disk"
# TODO: review bound (unverified vs literature)
width: Annotated[int, TuneSpec(31, 101, step=2)] = 51
n_iter: Annotated[int, TuneSpec(1, 3)] = 1
def _operate(self, image: Image) -> Image:
image.detect_mat[:] = cv2.morphologyEx(
src=image.detect_mat[:],
op=cv2.MORPH_TOPHAT,
kernel=self._make_footprint(shape=self.shape, width=self.width),
iterations=self.n_iter,
)
return image