spacr.qt.cpu_modes

The CPU detectors: a histogram’s worth of thresholds, and propagation.

Make Masks’ plain-threshold mode was Otsu and only Otsu. Otsu asks one question of a histogram – where is the cut that separates it into two groups with the least variance inside each – and it is a good question for a field with two clear populations and a poor one for everything else. A field that is mostly background, or whose objects are a thin bright tail, has been thresholded better by Li’s minimum cross entropy or by the triangle method since before spaCR existed, and both are one call away in scikit-image.

So the threshold algorithms here are NAMES OF A LEVEL AND NOTHING ELSE. Each is one line in spacr.qt.mask_engine.GLOBAL_THRESHOLDS or spacr.qt.mask_engine.LOCAL_THRESHOLDS, and everything around the level – the smoothing, the threshold correction, the bright or dark side, filling holes, the watershed split, the border rule, the minimum area – is the code Otsu already went through. Choosing Li instead of Otsu changes where one number comes from and nothing else, which is exactly what it should change.

Maxima + propagate finds bright centres in a blurred image and uses them as markers for a watershed on inverted intensity. A per-seed intensity cut then trims each basin, or a common intensity mask limits the watershed. This can separate touching objects when they have distinct detected centres; it does not implement CellProfiler’s distance/intensity propagation cost. The seed count is measured before hole filling and area filtering, so it can exceed the number of surviving labels. See spacr.qt.mask_engine.maxima_propagate_instances() for all four rules.

WHAT IS NOT HERE, AND WHY. Local MEAN and local GAUSSIAN thresholding are not offered again: they are the Adaptive threshold mode, which runs the organelle engine’s adaptive branch with a block size and an offset. Local OTSU is not offered again either: it is the “Local threshold (uneven illumination)” switch in plain Otsu mode, used by whole-image detection. Other named thresholds ignore saved Local Otsu and class-count settings; Multi-Otsu alone uses the selected class count and band in both scopes. Plain Otsu retains its legacy magnifier preprocessing, while the other thresholds use the whole-image engine on the requested crop. Niblack uses T = m - k*s; Sauvola uses T = m*(1 + k*(s/R - 1)), where m and s are the local mean and standard deviation. The engine supplies float32 values without rescaling their range, so scikit-image’s default Sauvola R is 1. These formulas are different, and changing the intensity scale can change Sauvola’s result.

Classes

CpuParams

Everything the CPU modes read, as one hashable value.

Functions

engine_algorithm(→ str)

The name spacr.qt.mask_engine knows mode by.

guidance(→ str)

What mode suits, as one sentence a picker can show.

modes(→ Tuple[str, ...])

Every mode this module adds, in the box's order.

propagate(image, params, *[, min_area, fill_holes])

Grow objects out of the local maxima of image.

provenance(→ Dict[str, object])

The parameters this mode actually read, for a mask's ledger entry.

puncta(image, parent_labels[, params, measurements])

Find noise-standardised centre-pixel puncta within unchanged parents.

secondary(image, primary, params, *[, min_area, ...])

Grow secondary labels from the existing primary-mask identities.

threshold_modes(→ Tuple[str, ...])

The modes that are a threshold algorithm, Multi-Otsu included.

Module Contents

class spacr.qt.cpu_modes.CpuParams[source]

Bases: NamedTuple

Everything the CPU modes read, as one hashable value.

One tuple for the same reason spacr.qt.organelle_modes.MethodParams is one: it rides on the magnifier’s request key, and a mode that falls back to another must still find its own settings in it.

Parameters:
  • local_k – dimensionless local contrast weight; default 0.2 for both modes. Niblack uses T = m - k*s: increasing k lowers the threshold, admitting more bright pixels and fewer dark pixels. Sauvola uses T = m*(1 + k*(s/R - 1)). The engine passes floats without range rescaling, giving scikit-image’s default R = 1. Its response to k depends on the local mean m and deviation s; positive k does not guarantee rejection of a flat background.

  • propagate_sigma – the Gaussian blur before the maxima are found, in pixels. SEPARATE FROM THE IMAGE ENHANCEMENT CHAIN’S DENOISE, which has already run by the time a detector sees the image: this one exists because the blur that makes one object have one centre is usually far stronger than the blur anyone wants the object’s EDGE measured through, and the propagation measures the edge on the same blurred image. Leave the chain’s denoise off unless the field is genuinely noisy, or the two blurs compound.

  • propagate_min_distance – the smallest gap between two seeds, in pixels; about one object radius.

  • propagate_seed_level – how bright a maximum must be to be a seed.

  • propagate_seed_percentile – read the seed level as a percentile of the blurred image rather than as an absolute intensity.

  • propagate_exclude_border – drop seeds near the edge.

  • propagate_stop – a key of spacr.qt.mask_engine.PROPAGATE_STOPS.

  • propagate_stop_value – the fraction, intensity or percentile the stop rule reads.

  • propagate_stop_algorithm – which global threshold provides the floor under the threshold stop rule.

  • secondary_growth – intensity or distance watershed for secondary objects; maxima detection ignores this setting.

  • puncta_sigmas – scale-normalised LoG widths in image pixels.

  • puncta_k – candidate response threshold in propagated pixel-noise units.

  • puncta_center_pixels – number of pixels nearest each subpixel centre, from 1 to 81 in the nine-by-nine measurement window.

  • puncta_min_corrected – minimum centre mean minus local annulus median, in native intensity units. Equality is retained.

  • puncta_min_distance – peak-local-maximum neighbourhood in pixels; scale-dependent nonmaximum suppression follows it.

  • puncta_edge_margin – minimum distance from the parent boundary in pixels.

spacr.qt.cpu_modes.engine_algorithm(mode: str) → str[source]

The name spacr.qt.mask_engine knows mode by.

Multi-Otsu is asked for by a class count rather than by name, so it maps back to otsu; the engine’s classes parameter is what makes it multi-level. Everything else is its own name.

Parameters:

mode – the detector mode key to map to an engine algorithm.

spacr.qt.cpu_modes.guidance(mode: str) → str[source]

What mode suits, as one sentence a picker can show.

Parameters:

mode – the detector mode key, such as otsu or li.

spacr.qt.cpu_modes.modes() → Tuple[str, ...][source]

Every mode this module adds, in the box’s order.

spacr.qt.cpu_modes.propagate(image: numpy.ndarray, params: CpuParams, *, min_area: int = 0, fill_holes: bool = True)[source]

Grow objects out of the local maxima of image.

A thin wrapper on spacr.qt.mask_engine.maxima_propagate_instances(), so the screen has one place to turn its controls into that call’s keywords.

Parameters:
  • image – the 2-D field or region, already through the chain.

  • params – the settings as the panel holds them.

  • min_area – the smallest object to keep, in pixels.

  • fill_holes – close the holes inside each grown object.

Returns:

a spacr.qt.mask_engine.PropagateResult.

spacr.qt.cpu_modes.provenance(mode: str, params: CpuParams) → Dict[str, object][source]

The parameters this mode actually read, for a mask’s ledger entry.

Parameters:
  • mode – the selected detector mode key.

  • params – the CPU-mode settings carried by the detection request.

Returns:

{field: value}, JSON-safe; empty for a mode that reads none of them – a global threshold reads only the Otsu category’s own settings, which the entry already carries.

spacr.qt.cpu_modes.puncta(image, parent_labels, params=DEFAULT_PARAMS, *, measurements=False)[source]

Find noise-standardised centre-pixel puncta within unchanged parents.

Parameters:
  • image – original finite two-dimensional channel intensities.

  • parent_labels – matching nonnegative integer parent labels.

  • params – candidate, centre-pixel and native-intensity inclusion settings.

  • measurements – return (labels, candidates) instead of labels alone; candidate rows include rejected centres and exact overlapping centre means.

Returns:

int32 labels, optionally with the candidate measurement DataFrame.

spacr.qt.cpu_modes.secondary(image: numpy.ndarray, primary: numpy.ndarray, params: CpuParams, *, min_area: int = 0, fill_holes: bool = True)[source]

Grow secondary labels from the existing primary-mask identities.

Parameters:
  • image – prepared 2-D field or magnifier crop.

  • primary – matching integer primary labels; no seeds are detected.

  • params – shared growth settings; centre-finding settings are ignored.

  • min_area – minimum grown area, including the primary footprint.

  • fill_holes – fill holes per label before the area filter.

Returns:

mask_engine.SecondaryResult with exact IDs and relationship diagnostics.

spacr.qt.cpu_modes.threshold_modes() → Tuple[str, ...][source]

The modes that are a threshold algorithm, Multi-Otsu included.