phenotypic.refine.AsymmetricSpurTrimmer#

class phenotypic.refine.AsymmetricSpurTrimmer(symmetry_threshold: float = 0.5, n_angular_bins: int = 6, n_annuli: int = 100, pelt_penalty: float = 5.0, smoothing_window: int = 3, method: Literal['distance', 'intensity'] = 'distance', beehive_threshold: float | None = None, max_trim_fraction: float = 0.25, min_cc_area: int = 50, min_object_area: int = 100)[source]

Bases: ObjectRefiner

Trim spurs and web-like noise beyond each colony’s symmetric envelope.

Reuses the symmetric-radius machinery from MeasureSymmetricZones to locate, per colony, the radius past which growth stops being angularly symmetric (R_sym). Every mask pixel beyond R_sym is a candidate for removal. Candidates are segmented into connected components and, when beehive_threshold is provided, classified by their topology: CCs with many enclosed holes per pixel (reticulated “beehive” noise) are removed, while nearly linear branches (holes per pixel ≈ 0) are preserved.

Compared to the measurement-time version in MeasureSymmetricZones, this refiner is deliberately less harsh:

  • The default symmetry_threshold is 3/6 rather than 4/6 so R_sym lands further from the inoculum core.

  • Per-CC segmentation localizes the decision — trimming one noisy spur never touches a legitimate branch on the other side of the colony.

  • A safety cap (max_trim_fraction) aborts trimming for any colony where the proposal would remove more than the given fraction of its pixels, protecting uniformly asymmetric morphologies.

Parameters:
  • symmetry_threshold (float) – Minimum angular coverage (fraction of n_angular_bins populated) required for growth to count as symmetric. Lower values push R_sym outward, shrinking the candidate region. Defaults to 3/6.

  • n_angular_bins (int) – Number of uniform angular bins used for the coverage diagnostic that feeds R_sym. Defaults to 6.

  • n_annuli (int) – Target number of equal-area annuli for the radial density profile. Auto-scaled down for small colonies. Defaults to 100.

  • pelt_penalty (float) – Penalty controlling PELT changepoint sensitivity for the inoculum core detection. Defaults to 5.0.

  • smoothing_window (int) – Moving-average window (in annuli) applied to the angular coverage profile before the R_sym threshold test. Defaults to 3.

  • method (Literal['distance', 'intensity']) – Inoculum-centre estimator. "distance" uses the peak of the Euclidean distance transform; "intensity" uses the intensity-weighted centroid. Defaults to "distance".

  • beehive_threshold (float | None) – Minimum holes-per-pixel density required to trim a candidate connected component. When None (default), every CC past R_sym is trimmed — the “pure R_sym” mode. When a float, CCs with (1 - euler_number) / area below the threshold are kept as legitimate linear branches.

  • max_trim_fraction (float) – Safety cap on the fraction of a colony’s pixels that may be removed in a single application. If the proposal exceeds this fraction, trimming is aborted for that colony. Defaults to 0.25.

  • min_cc_area (int) – Minimum candidate-CC area (pixels) required to make a topological decision. Smaller CCs are kept unchanged because Euler statistics are unreliable on tiny regions. Defaults to 50.

  • min_object_area (int) – Minimum colony area (pixels) below which the refiner skips the colony entirely. Defaults to 100.

Returns:

Input image with objmap updated; objmask refreshes automatically via the accessor.

Return type:

Image

Best For:
  • Filamentous-fungi detections where Dijkstra-reconnected bridges occasionally produce thin asymmetric spurs off a symmetric body.

  • Plates where noise manifests as beehive / reticulated web structures while legitimate hyphae remain linear.

Consider Also:
  • SmallObjectRemover for spurious noise distinguished by size alone rather than spatial relationship to the colony body.

  • LowCircularityRemover when the whole colony should be judged by shape, not just its outer extent.

Examples

Pure R_sym trimming (default — every CC past the symmetric envelope is removed). On the synthetic yeast plate the colonies are already compact/symmetric so the op is a no-op; this example simply shows that wiring the refiner into a detection pipeline does not break it:

>>> from phenotypic.data import load_synth_yeast_plate
>>> from phenotypic.detect import OtsuDetector
>>> from phenotypic.refine import AsymmetricSpurTrimmer
>>> plate = load_synth_yeast_plate()
>>> detected = OtsuDetector().apply(plate)
>>> trimmer = AsymmetricSpurTrimmer()
>>> refined = trimmer.apply(detected)
>>> bool(refined.objmap[:].max() >= 0)
True

Two-stage beehive-gated trim — legitimate linear branches past the envelope are preserved; only topologically web-like regions are removed:

>>> trimmer = AsymmetricSpurTrimmer(beehive_threshold=0.002)
>>> refined = trimmer.apply(detected)
>>> bool(refined.objmap[:].max() >= 0)
True

Methods

__init__

apply

Applies the operation to an image, either in-place or on a copy.

widget

Return (and optionally display) the root widget.

__del__()

Automatically stop tracemalloc when the object is deleted.

__getstate__()

Prepare the object for pickling by disposing of any widgets.

This ensures that UI components (which may contain unpickleable objects like input functions or thread locks) are cleaned up before serialization.

Note

This method modifies the object state by calling dispose_widgets(). Any active widgets will be detached from the object.

apply(image, inplace=False)

Applies the operation to an image, either in-place or on a copy.

Parameters:
  • image (Image) – The arr image to apply the operation on.

  • inplace (bool) – If True, modifies the image in place; otherwise, operates on a copy of the image.

Returns:

The modified image after applying the operation.

Return type:

Image

widget(image: Image | None = None, show: bool = False) Widget

Return (and optionally display) the root widget.

Parameters:
  • image (Image | None) – Optional image to visualize. If provided, visualization controls will be added to the widget.

  • show (bool) – Whether to display the widget immediately. Defaults to False.

Returns:

The root widget.

Return type:

ipywidgets.Widget

Raises:

ImportError – If ipywidgets or IPython are not installed.