spacr.qt.detect_chain¶
Optional image enhancement before detection and label cleanup afterward.
In Make Masks, Apply enables the configured chain for detection and display; Compare previews it without enabling it. Processing uses copies: files on disk and the original values reported by the hover readout remain unchanged.
CHAIN_ORDER fixes the sequence:
percentile stretch -> background -> PSF -> restoration -> denoise -> contrast -> sharpen
-> detect -> morphology -> split
The optional percentile stretch belongs to Make Masks, outside Chain.
Its levels come from the whole field before a magnifier region is cropped, so
moving the box does not redefine the percentile levels.
Background subtraction precedes PSF processing, deep restoration and denoising. Denoising precedes contrast to
avoid amplifying noise; contrast precedes sharpening to avoid stretching its
halos. Morphology precedes splitting because it changes which pixels are
connected. prepare() runs background, PSF, restoration, denoise, contrast and sharpen;
finish() runs morphology and split after the selected detector.
Disabled steps return their input unchanged. heavy_steps() identifies
enabled steps that warrant a progress warning; non-local means can take
minutes on a 2,000 px field. Whole-image runs retain progress and Cancel
controls. Selecting a background method does not enable denoising.
The contrast stage is itself a fixed sequence of curves through one trip to
the unit interval, CONTRAST_ORDER:
percentile clip -> gamma -> log -> sqrt -> CLAHE -> histogram equalisation
The clip runs first so that a hot pixel cannot define the interval the curves are drawn on; the curves are monotone, so their order only changes the shape of the composite curve and never which pixel is brighter.
THE SAME CHAIN REACHES MASK GENERATION. The image steps – everything before
detect – are written as Mask settings by chain_settings(), one
enhance_<field> key per SETTINGS_FIELDS entry, and read back by
spacr.psf_pipeline.prepare_chain(), which the V1 and V2 Mask pipelines
and the Mask Live preview apply to every selected segmentation channel after
illumination correction and before normalization, at the stage the PSF
already ran. Morphology and split act on a detector’s labels and are Make
Masks’ own; a plate run’s Cellpose labels are not reshaped by them. The Mask
settings remove_background, background and signal_to_noise are
per-channel intensity floors applied by normalization afterwards, and
spacr.object._preprocess_batch() is the organelle batches’ own
rolling ball and CLAHE; neither is configured here.
Enhancement changes the objects proposed for curation. Models trained on enhanced images require matching preprocessing at inference; this module does not configure the training or inference pipeline.
Classes¶
One pre- and post-detection chain, as a value a request can carry. |
Functions¶
|
The slowly varying background under |
|
The chain's image steps as the Mask settings that apply them. |
|
The switched-on steps in one line, for a status line or a tooltip. |
|
What the detector labelled, opened or closed and then split. |
|
The switched-on steps slow enough to warn about, in words. |
|
Whether any step of the chain is switched on. |
|
Whether |
|
Whether |
|
The image a detector is to read, with optional cooperative cancellation. |
|
The chain as it goes into a mask's ledger entry. |
|
The Mask setting that carries a chain field. |
|
The switched-on steps, in order, in the words a caption uses. |
Module Contents¶
- class spacr.qt.detect_chain.Chain[source]¶
Bases:
NamedTupleOne pre- and post-detection chain, as a value a request can carry.
An immutable tuple including any captured PSF kernel, so it is hashable and goes into the magnifier’s request key: the same box under two different chains is two different questions and must not be answered from one cached result.
Every field’s default is the step switched off, so
NO_CHAINis “detect the image as it is” and an old session that knows nothing about this chain keeps behaving as it did.- Parameters:
background – one of
BACKGROUND_METHODS.background_radius – the ball’s or the top-hat disk’s radius, in pixels. Set it comfortably larger than the largest object: a radius under the object size eats the objects along with the background.
background_scale – the fraction of full size the background is ESTIMATED at, 0.1 to 1.0. See
background_surface()for what that buys and what it costs; 1.0 is scikit-image’s own answer, exactly.denoise – one of
DENOISE_METHODS.denoise_strength – the Gaussian’s sigma in pixels, the median’s and the bilateral’s disk radius, or the non-local means’ cut-off in multiples of the estimated noise.
gamma – the exponent the intensities are raised to on 0..1. Below 1 lifts the dim end (faint objects become visible), above 1 pushes it down. 1.0 is off.
clahe – contrast-limited adaptive histogram equalisation.
clahe_tile – the side of one CLAHE tile, in pixels.
clahe_clip – CLAHE’s clip limit, 0..1. Higher is more contrast and more amplified noise.
equalize – global histogram equalisation.
sharpen – an unsharp mask.
sharpen_radius – the blur radius the mask is built from, in pixels: about the scale of the edges to sharpen.
sharpen_amount – how much of the mask is added back.
morphology – one of
MORPHOLOGY_OPS, applied to what was detected.openseparates objects joined by a thin bridge,closejoins objects broken into pieces,open_closedoes both in that order.morphology_radius – the disk radius, in pixels.
split – a distance-transform watershed on what was detected, cutting an object with two centres in two. It is the Otsu mode’s “Split objects that touch”, offered to every other method.
psf_operation –
none,convolveordeconvolve. Runs after background subtraction and before denoising. Off by default.psf – immutable calibrated two-dimensional kernel. Required when PSF processing is enabled; missing/invalid kernels stop detection.
psf_sampling_um – image pixel spacing in YX order, in micrometers. Must match the kernel; no implicit resampling is performed.
psf_iterations – Richardson–Lucy iterations, 1..200.
psf_error – actionable loading/validation error when no kernel is ready.
restoration – enable isolated Cellpose 3 restoration after PSF and before classical denoising. Off by default. Run preparation on a worker.
restoration_plan – immutable loaded model identity and diameter in pixels. Model output uses normalized units, not calibrated fluorescence.
restoration_error – loading error shown instead of silently using unprocessed data when restoration was explicitly requested.
percentile_clip – clip each plane to two percentiles of its own intensities before the contrast curves, so a hot pixel or a dead one cannot define the interval the curves are drawn on. The intensities keep their units; nothing is stretched.
percentile_low – the lower percentile, 0..100.
percentile_high – the upper percentile, 0..100, above the lower.
log – a logarithmic transform on 0..1,
log(1 + gain·x) / log(1 + gain): it compresses the bright end and lifts the dim one, more strongly than a gamma below 1 does near zero.log_gain – the factor the unit-interval intensities are scaled by before the logarithm. Larger compresses harder; as it goes to zero the curve goes to the identity.
sqrt – a square root on 0..1, the curve gamma 0.5 draws, offered by name.
- spacr.qt.detect_chain.background_surface(image: numpy.ndarray, chain: Chain) numpy.ndarray[source]¶
The slowly varying background under
image, atimage’s size.Estimate the background on a smaller copy at
Chain.background_scale, then resize the surface to the input shape. The radius shrinks with the image to preserve its relative extent. This approximates slowly varying illumination while reducing both the pixel count and neighbourhood size.At scale 1.0, call
rolling_ballorwhite_tophatat full resolution and return its exact result. Smaller images also use full resolution when downsampling would crossMIN_BACKGROUND_SIDE. Full-resolution estimation can be slow: on a 1,994 px uint16 field converted to float32, CPU rolling-ball timings were 0.3 s at radius 5, 0.9 s at 10, 4.1 s at 25 and 14.5 s at 50. At the default radius 50 and scale 0.5, the same field took about a second. Timings depend on the hardware and image; callers should run this outside the GUI thread.- Parameters:
image – the field or region, as float.
chain – the chain, for its background method, radius and scale.
- Returns:
the background, the same shape as
image; zeros when the chain subtracts no background.
- spacr.qt.detect_chain.chain_settings(chain: Chain = NO_CHAIN) Dict[str, object][source]¶
The chain’s image steps as the Mask settings that apply them.
One
enhance_<field>perSETTINGS_FIELDSentry, each cast to the plain type its default has, so the mapping is what a settings file holds and whatspacr.psf_pipeline.prepare_chain()reads back into an equal chain.NO_CHAINgives the defaults, which is what a settings file that knows nothing about the chain means.- Parameters:
chain – the chain to write out.
- Returns:
setting name to plain value, in
SETTINGS_FIELDSorder.
- spacr.qt.detect_chain.describe(chain: Chain, *, percentile_stretch: bool = False) str[source]¶
The switched-on steps in one line, for a status line or a tooltip.
- Parameters:
chain – the configured pre- and post-detection steps to inspect.
percentile_stretch – whether to include the screen’s initial percentile stretch before the steps in the chain.
- Returns:
the steps separated by arrows, or an empty string when the chain does nothing.
- spacr.qt.detect_chain.finish(labels: numpy.ndarray, chain: Chain, intensity: numpy.ndarray | None = None) numpy.ndarray[source]¶
What the detector labelled, opened or closed and then split.
Morphology and the split are both questions about WHICH PIXELS ARE ONE OBJECT, so both are asked of the detection as a whole: the labels are read as a foreground, reshaped, and labelled again. The ids therefore change, which costs nothing here – Make Masks renumbers every object it pastes into a mask (
spacr.qt.mask_engine._paste_region_objects()).- Parameters:
labels – the detector’s label image.
chain – what to do to it.
intensity – the image the detector read, used as the watershed’s landscape where it is given.
- Returns:
labelsitself when neither step is switched on.
- spacr.qt.detect_chain.heavy_steps(chain: Chain) Tuple[str, ...][source]¶
The switched-on steps slow enough to warn about, in words.
- Parameters:
chain – the configured pre- and post-detection steps to inspect.
- Returns:
the names, in
CHAIN_ORDER; empty when nothing switched on is heavy.
- spacr.qt.detect_chain.is_active(chain: Chain) bool[source]¶
Whether any step of the chain is switched on.
- Parameters:
chain – the configured pre- and post-detection steps to inspect.
- spacr.qt.detect_chain.post_active(chain: Chain) bool[source]¶
Whether
finish()would change what the detector labelled.- Parameters:
chain – the configured pre- and post-detection steps to inspect.
- spacr.qt.detect_chain.pre_active(chain: Chain) bool[source]¶
Whether
prepare()would change the image at all.Asked before a copy is made: a chain with nothing switched on must hand the detector the very array it would have had, not a float copy of it.
- Parameters:
chain – the configured pre- and post-detection steps to inspect.
- spacr.qt.detect_chain.prepare(image: numpy.ndarray, chain: Chain, *, cancel=None, strict: bool = False) numpy.ndarray[source]¶
The image a detector is to read, with optional cooperative cancellation.
Background, PSF, deep restoration, denoise, contrast, then sharpen –
CHAIN_ORDER, whose docstring says why that order and not another. The percentile stretch is the screen’s, applied to the whole field beforeimagewas cut from it.Legacy filter failures are logged and skipped unless
strictis set. PSF/restoration failures and cancellation propagate so detection cannot silently use an unprocessed image when an explicitly calibrated operation was requested. This is reached from a mouse-move (the readout under the cursor) and from the magnifier, so an exception here is one per mouse event: a missing optional package filled the console with tracebacks once (PyWavelets, 2026-09-22) and made the screen unusable. The detector then reads the image as far as the chain got, and the log says which step was dropped. A plate run passesstrict=True: a mask made from an image a step was silently dropped from would be presented as the mask the settings asked for.- Parameters:
image – the field, or the magnifier’s box region cut from it. Never modified.
chain – what to do to it.
cancel – callable or Event; checked between stages, inside PSF iterations and while awaiting restoration. Cancellation raises
spacr.point_spread.ProcessingCancelled.strict – raise a failing step’s error instead of logging it and handing on the image as far as the chain got.
- Returns:
imageitself when nothing is switched on – so a detector reading an untouched field reads the very array and not a float copy – and otherwise a new float32 array of the same shape.
- spacr.qt.detect_chain.provenance(chain: Chain, *, percentile_stretch: bool = False) Dict[source]¶
The chain as it goes into a mask’s ledger entry.
ONLY THE STEPS THAT RAN, plus the order they ran in, so an entry says what was done rather than listing fourteen defaults around it; a chain with nothing on records nothing but the switch that was off. The order is written out because it is what makes the entry enough to reproduce the mask: the same steps in another order are another mask.
- Parameters:
chain – the chain the detection used.
percentile_stretch – whether the screen’s “detect on the normalized image” was on – the chain’s first stage, which is the screen’s and not this module’s.
- Returns:
a JSON-safe dict, empty of steps when none ran.
- spacr.qt.detect_chain.setting_name(field: str) str[source]¶
The Mask setting that carries a chain field.
- Parameters:
field – a
Chainfield name fromSETTINGS_FIELDS.- Returns:
enhance_<field>.
- spacr.qt.detect_chain.step_names(chain: Chain, *, percentile_stretch: bool = False) Tuple[str, ...][source]¶
The switched-on steps, in order, in the words a caption uses.
English, and each name is one row a caller can translate on its own – the alternative, one row per combination of fifteen fields, is a catalog nobody can fill.
- Parameters:
chain – the chain to describe.
percentile_stretch – whether the screen’s stretch was on.
- Returns:
the names, in
CHAIN_ORDER; empty when nothing ran.
Nested helpers¶
- prepare.check()¶
Stop between enhancement stages when the supplied callback or event is cancelled.
spacr/qt/detect_chain.py:569