Source code for phenotypic.refine._small_object_remover
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from phenotypic._core._image import Image
from skimage.morphology import remove_small_objects
from ..abc_ import ObjectRefiner
[docs]
class SmallObjectRemover(ObjectRefiner):
"""Remove objects smaller than a minimum area from the detection mask.
Eliminates dust, condensation specks, and noise fragments that appear
as tiny labeled objects after thresholding. Reduces false positives
and stabilizes colony counts.
Args:
min_size: Minimum object area in pixels to keep. Objects below this
threshold are removed. Typical range: 20--200 depending on
image resolution. Default: 64.
Returns:
Image: Input image with ``objmask`` and ``objmap`` updated to
exclude small objects.
Best For:
- Cleaning up salt-and-pepper artifacts after detection.
- Removing fragmented debris around large colonies.
- Post-processing after aggressive enhancement or thresholding.
Consider Also:
- :class:`BorderObjectRemover` for removing partial colonies at
image edges (size-independent).
- :class:`LowCircularityRemover` for removing non-circular artifacts
regardless of size.
See Also:
:doc:`/how_to/notebooks/refine_noisy_boundaries` for a walkthrough
of refinement operations.
:doc:`/explanation/refinement_strategies` for choosing the right
refinement sequence.
"""
[docs]
def __init__(self, min_size=64):
"""Initialize the remover.
Args:
min_size (int): Minimum object area (in pixels) to keep. Higher
values remove more small artifacts and fragmented edges,
generally improving mask cleanliness but risking loss of tiny
colonies.
"""
self.min_size = min_size
def _operate(self, image: Image) -> Image:
objmap = image.objmap[:]
# remove_small_objects warns when given a label image with a single
# non-zero label (treats it as ambiguous binary vs labeled). Pass a
# boolean array in that case; re-label afterwards if needed.
if objmap.max() <= 1:
cleaned = remove_small_objects(
objmap.astype(bool), min_size=self.min_size
)
image.objmap[:] = cleaned.astype(objmap.dtype)
else:
image.objmap[:] = remove_small_objects(objmap, min_size=self.min_size)
return image