Source code for phenotypic.detect._minimum_detector
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from phenotypic._core._image import Image
from skimage.filters import threshold_minimum
from skimage.segmentation import clear_border
from ..abc_ import ThresholdDetector
[docs]
class MinimumDetector(ThresholdDetector):
"""Detect colonies by finding the valley between two histogram peaks.
Locate the intensity minimum (valley) between the two dominant peaks of
the image histogram and threshold at that point. This works well when
colonies and background form two clearly separated intensity populations,
as the valley provides a natural separation boundary. For a full
comparison see :doc:`/explanation/detection_strategies_compared`.
Args:
ignore_zeros: Exclude zero-intensity pixels from threshold
computation. Enable for plates with black borders or masked
regions; disable only when zero is a meaningful intensity value.
Default: True.
ignore_borders: Remove colonies touching image edges via
``clear_border()``. Recommended for grid-based colony counting
to eliminate partial colonies at plate boundaries. Default: True.
Returns:
Image: Input image with ``objmask`` set to binary mask and
``objmap`` set to labeled connected components.
Raises:
ValueError: If the histogram has no clear bimodal distribution and
no valley can be found.
Best For:
* High-contrast plates where colony and background intensities form
two distinct, well-separated histogram peaks.
* Standardised imaging setups producing consistently bimodal
histograms across plates.
* Images where the intensity gap between colonies and agar is wide
and the valley is unambiguous.
Consider Also:
* :class:`OtsuDetector` when the histogram is bimodal but peaks
are broad or partially overlapping.
* :class:`LiDetector` when the histogram is unimodal or weakly
bimodal and a cross-entropy criterion is more appropriate.
* :class:`HysteresisDetector` when colony brightness varies and a
single valley-based threshold under-segments faint regions.
See Also:
:doc:`/tutorials/notebooks/02_detecting_colonies`
Step-by-step tutorial for basic colony detection.
:doc:`/how_to/notebooks/choose_detection_algorithm`
Guide for selecting the right detector for your plate images.
:doc:`/explanation/detection_strategies_compared`
In-depth comparison of all detection strategies.
"""
def __init__(self, ignore_zeros: bool = False, ignore_borders: bool = True):
self.ignore_zeros = ignore_zeros
self.ignore_borders = ignore_borders
def _operate(self, image: Image) -> Image:
"""Binarizes the given image matrix using the Minimum threshold method.
This function modifies the arr image by applying a binary mask to
its enhanced matrix (`detect_mat`). The binarization threshold is
automatically determined using Minimum method. The resulting binary
mask is stored in the image's `objmask` attribute.
Args:
image (Image): The arr image object. It must have an `detect_mat`
attribute, which is used as the basis for creating the binary mask.
Returns:
Image: The arr image object with its `objmask` attribute updated
to the computed binary mask other_image.
"""
enh_matrix = image.detect_mat[:]
nbins = 2**image.bit_depth
mask = image.detect_mat[:] >= threshold_minimum(
enh_matrix[enh_matrix != 0] if self.ignore_zeros else enh_matrix,
nbins=nbins,
)
mask = clear_border(mask) if self.ignore_borders else mask
image.objmask = mask
return image
# Set the docstring so that it appears in the sphinx documentation
MinimumDetector.apply.__doc__ = MinimumDetector._operate.__doc__