Source code for phenotypic.refine._grid_oversized_object_remover
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from phenotypic import GridImage
import numpy as np
from phenotypic.abc_ import GridObjectRefiner
from phenotypic.tools.constants_ import BBOX, OBJECT
[docs]
class GridOversizedObjectRemover(GridObjectRefiner):
"""Remove objects that are larger than their grid cell allows.
Intuition:
In pinned colony grids, each cell should contain at most one colony of
limited extent. Objects spanning nearly an entire cell width/height are
often merged colonies, agar edges, or segmentation spillover. Removing
these oversized objects improves the reliability of per-cell analysis.
Why this is useful for agar plates:
Grid-based assays assume spatial confinement. Oversized detections
disrupt row/column statistics and bias growth comparisons. Filtering
them stabilizes downstream measurements.
Use cases:
- Dropping merged blobs that span adjacent positions.
- Removing strong edge artifacts near the plate rim that intrude into
the grid.
Caveats:
- If genuine colonies expand to fill the cell (late time points), this
remover may exclude real growth.
- Highly irregular grids or mis-registered edges can cause over-
removal; ensure grid metadata is accurate.
Attributes:
(No public attributes)
Examples:
.. dropdown:: Remove objects larger than their grid cell allows
>>> from phenotypic.refine import GridOversizedObjectRemover
>>> op = GridOversizedObjectRemover()
>>> image = op.apply(image, inplace=True) # doctest: +SKIP
"""
def _operate(self, image: GridImage) -> GridImage:
"""
Applies operations on the given GridImage to remove objects based on maximum width and height constraints.
This method processes the grid metadata of a `GridImage` object to identify objects
that exceed the maximum calculated width and height. It sets such objects to a
background value of 0 in the object's mapping array. This helps filter out undesired
large objects in the image.
Args:
image (GridImage): The arr grid image containing grid metadata and object map.
Returns:
GridImage: The processed grid image with specified objects removed.
"""
row_edges = image.grid.get_row_edges()
col_edges = image.grid.get_col_edges()
grid_info = image.grid.info()
# To simplify calculation use the max width & distance
max_width = max(col_edges[1:] - col_edges[:-1])
max_height = max(row_edges[1:] - row_edges[:-1])
# Calculate the width and height of each object
grid_info.loc[:, "width"] = (
grid_info.loc[:, str(BBOX.MAX_CC)] - grid_info.loc[:, str(BBOX.MIN_CC)]
)
grid_info.loc[:, "height"] = (
grid_info.loc[:, str(BBOX.MAX_RR)] - grid_info.loc[:, str(BBOX.MIN_RR)]
)
# Find objects that are past the max height & width
over_width_obj = grid_info.loc[:, "width"] >= max_width
over_height_obj = grid_info.loc[:, "height"] >= max_height
oversized_obj_labels = grid_info.loc[
over_width_obj | over_height_obj, OBJECT.LABEL
].unique()
# Set the target objects to the background val of 0
image.objmap[np.isin(image.objmap[:], oversized_obj_labels)] = 0
return image