spacr.illumination¶
Workflow inputs and outputs¶
Illumination¶
Estimate and apply flat-field correction at configured stages. Keep corrected display values distinct from raw measurements and record the applied policy.
Open: Measure → Illumination.
Inputs and outputs below include conditional alternatives. The guidance and handoff notes say which route applies.
Inputs
Microscope images — Source image folder; original files, supported vendor files or imported TIFFs.
Outputs
Microscope images — Source image folder; original files, supported vendor files or imported TIFFs.
Illumination / flat-field correction for the measurement path.
The problem¶
No microscope lights a field of view evenly. A lamp profile, vignetting in
the objective, a tilted condenser and dirt on the optics together make the
same cell measure brighter at the centre of the field than at its edge –
routinely 10-40 % between the middle and a corner on a widefield screen.
Every intensity feature spaCR writes (*_mean_intensity,
*_percentile_*, the radial distribution, the texture channels that are
computed on intensity) therefore carries a position-dependent bias, and
because objects are not distributed identically over every well, that bias
does not average out: it survives into the per-well aggregate, and from there
into classification and regression as an effect that looks entirely real and
is entirely an artefact of the optics.
It is also the root cause of the plate-scale edge effects
spacr.plate_qc already detects and reports. That module reports them;
this module removes the bias from the measured intensities.
The model¶
Per channel, per plate:
observed(y, x) = dark + flat(y, x) * true(y, x)
flat is the multiplicative illumination field, normalised so its mean is
1 – the plate’s overall intensity level is preserved, so a corrected number
stays on the same scale as an uncorrected one and only its position
dependence is removed. dark is the additive camera offset. The
correction the hook applies is:
corrected = (observed - dark) / flat
What is estimated, and why¶
Retrospective, from the data itself: a per-pixel median across many fields of the plate, followed by a fit of a smooth low-order surface.
Why the median across fields. A pixel is covered by a cell in only a minority of the fields on a plate, so the across-field median at that pixel sees background almost every time and the objects drop out. Each field is first divided by its own median, so a densely-seeded field does not pull the estimate up because it has more cells in it – what is being averaged is the relative profile, not the brightness.
Why the surface fit on top. Illumination is a physically smooth,
low-frequency function of position: a lamp profile plus a vignette. Fitting a
low-order 2-D polynomial (default degree 4, 15 terms) to the per-pixel median
imposes exactly that prior, so residual object structure and photon noise
cannot leak into the gain map and be baked into every measurement on the
plate. The fit is trimmed twice against a MAD threshold, so a persistent
bright artefact – a fluorescent speck in the same place on every field –
is rejected rather than smeared into the surface. For illumination that is
genuinely not polynomial (a dust shadow, a sharply structured lamp) pass
estimator='smooth': the same per-pixel median, Gaussian-smoothed at
1/16 of the short side and interpolated back to full resolution.
Why not BaSiC. BaSiC’s low-rank + sparse decomposition is the better
estimator when you have hundreds of fields and a genuine dark-field to
recover, but it is an iterative optimisation with its own convergence
failure modes, and its dark-field term is only identifiable because of those
extra assumptions. From a single acquisition, dark and flat are not
separately identifiable at all: multiplying flat by a constant and
absorbing it into the per-field brightness leaves every observation
unchanged. Estimating a dark-field anyway – for instance from the per-pixel
minimum across fields, which is the usual shortcut – returns dark plus the
dimmest background, and subtracting it removes real signal. dark is
therefore not estimated: it is 0 unless you supply the camera offset you
measured from a dark frame, via illumination_dark.
Reaching the worker processes¶
spacr.measure.measure_crop() measures fields in a
multiprocessing.Pool. Under spawn / forkserver each worker is
a fresh interpreter with an empty hook registry, so a correction registered
only in the parent is applied to no field, and the run completes without an
error while every number is uncorrected. enable_illumination_correction()
therefore does more than register the hook: it writes the model path to
MODEL_ENV_VAR and appends spacr.illumination:install to
SPACR_MEASURE_HOOKS, which every start method inherits, so each worker
installs the correction for itself. worker_delivery_status() reports
whether that is actually in place, and enable_illumination_correction()
prints it.
Using it¶
Off by default. From a settings dict (the keys are registered through the
spacr.settings.register_defaults() seam, see
illumination_settings()):
settings = get_measure_crop_settings(settings={...})
settings['illumination_correction'] = True
prepare_illumination_correction(settings) # estimate, save, enable, QC
measure_crop(settings)
or explicitly:
model = estimate_illumination(src, channels=[0, 1, 2])
model.save('/data/plate1/illumination/illumination_model.npz')
illumination_qc(model, src, save_dir='/data/plate1/illumination')
enable_illumination_correction('/data/plate1/illumination/illumination_model.npz')
Nothing in this module runs unless one of those calls is made, and
disable_illumination_correction() returns the process to a state where
measure_crop measures exactly what it measured before.
In the GUI the same two routes exist and end here: the “Illumination Correction” category on the Measure panel, which turns the correction on for that Measure run, and the Illumination button on that screen’s masthead, which opens this module’s own settings form and Run button so the field can be estimated and QC’d without measuring the plate. Neither route is a tile: the module has no tile of its own.
Exceptions¶
Raised when requested illumination correction cannot be applied. |
Classes¶
The preprocessing hook that applies an |
|
The illumination estimate for one plate, for one or more channels. |
|
Estimated illumination fields for every plate in a source folder. |
|
One fitted/loaded model and the stage-neutral objects derived from it. |
|
Apply one illumination model exactly once per segmentation field. |
Functions¶
|
Turn the correction off, here and for any worker started afterwards. |
Turn the correction on, here and in every worker process. |
|
|
Estimate the illumination field from the merged fields in |
|
Plot and quantify the position-dependent bias before and after correction. |
|
Return a copy of |
|
Install the correction in this process from the environment. |
|
Read a saved model. Thin alias for |
Read and validate prior segmentation illumination without side effects. |
|
|
The plate a merged field belongs to, from its file name. |
|
Least-squares slope of intensity against distance from the field centre. |
|
Estimate, save, enable and QC the Measure correction. |
Prepare one reusable optical model without installing a Measure hook. |
|
Prepare correction for segmentation inputs without changing raw data. |
|
|
Register the illumination settings through the defaults seam. |
|
Raise before Measure corrects pixels that segmentation already corrected. |
|
Validate a |
|
Whether the correction will actually reach |
Module Contents¶
- exception spacr.illumination.IlluminationError[source]¶
Bases:
spacr.errors.ConfigurationErrorRaised when requested illumination correction cannot be applied.
A
spacr.errors.ConfigurationError, not a per-field data error: every failure this class reports (no fields to estimate from, a model that does not cover the plate being measured, a channel the model was never estimated for) is wrong for the whole run, so the run stops instead of measuring uncorrected pixels without notice.Initialize self. See help(type(self)) for accurate signature.
- class spacr.illumination.IlluminationCorrector(model: IlluminationModel, *, on_missing: str = 'error', verbose: bool = True)[source]¶
The preprocessing hook that applies an
IlluminationModel.Registered through
spacr.measure_hooks.register_preprocessing_hook(), so it is handed exactly the array the intensity measurements see – the channels named bysettings['channels'], selected out of the merged stack, before a single feature is computed.This class, not the hook machinery, handles the dtype round trip (see
spacr.measure_hooks.apply_preprocessing_hooks()). Integer input is corrected in float32 and returned by rounding to nearest and then clipping to the dtype’s range:round, not truncate. Truncation would shave a mean of 0.5 counts off every corrected pixel. Averaged over a 500-pixel object that does not wash out – it is a systematic, one-directional shift of exactly the kind this feature exists to remove. Rounding is unbiased.
clip, and count. A gain above 1 at the edge of the field can push a near-full-scale pixel past the top of a uint16. Clipping is the only option that keeps the dtype the hook contract requires, and it removes real signal, so every pixel that was below full scale before the correction and lands at full scale after it is counted and reported. Pixels that were already saturated are not counted: they were saturated at acquisition, not by the correction.
Float input is returned in its own float dtype with no rounding and no clipping at all – there is nothing to round to and no range to leave.
- Parameters:
model – the estimated
IlluminationModel.on_missing –
'error'(default) or'skip'for a field whose plate the model does not cover. The default fails the field, so a results table never mixes corrected and uncorrected fields.verbose – print the clipping reports.
Arm a corrector over a fitted illumination model.
- Parameters:
model – the fitted model to divide fields by.
on_missing – what to do with a field the model has no profile for –
'error'fails the field,'skip'measures it uncorrected and counts it.verbose – report the first few clipping events.
- Raises:
IlluminationError – if
on_missingis neither of the two.
- __call__(channel_arrays: numpy.ndarray, context) numpy.ndarray[source]¶
Return
channel_arrayscorrected, in the same shape and dtype.- Parameters:
channel_arrays –
(Y, X, C)or(Z, Y, X, C)intensities.context – the
spacr.measure_hooks.PreprocessingContext.
- class spacr.illumination.IlluminationField[source]¶
The illumination estimate for one plate, for one or more channels.
- Parameters:
plate – the plate key, or
ALL_PLATESwhen the model was estimated across every plate at once.channels – source channel indices, in the order they index
flatfield’s first axis. These are indices into the merged stack, i.e. exactly the values insettings['channels'].flatfield –
(C, Y, X)float32 multiplicative field, normalised so each channel’s mean is 1.0.corrected = (observed - dark) / flatfield.dark – per-channel additive offset subtracted before dividing. Zero unless the user supplied a measured camera offset – see the module docstring for why it is not estimated.
n_fields – how many fields the estimate was made from.
estimator –
'polynomial'or'smooth'.degree – polynomial degree, or 0 for the smooth estimator.
bin_size – the binning factor the per-pixel median was computed at. Illumination is low-frequency, so binning loses little of the field’s structure, lets many fields fit in memory at once and reduces noise in the median.
floored – pixels the fitted surface had to be floored at (see
FLAT_FLOOR_FRACTION). Non-zero means the fit went negative somewhere and the estimate should be looked at before it is trusted.darkfield – optional
(C, Y, X)spatial background subtracted on top ofdark. Only a vendor profile that ships its own background surface carries one; an estimated field never does.
- dark_stack(channels: Sequence[int]) numpy.ndarray[source]¶
(C,)additive offsets forchannels, ready to broadcast.- Parameters:
channels – source channel indices in the order required by the array being corrected.
- gain_stack(channels: Sequence[int]) numpy.ndarray[source]¶
(Y, X, C)multiplicative gains1 / flatfieldforchannels.Shaped for the array a preprocessing hook is handed, so applying the correction is one broadcast multiply.
- Parameters:
channels – source channel indices, in the order they appear along the last axis of the array being corrected.
- index_of(channel: int) int[source]¶
Position of source
channelalongflatfield’s first axis.- Parameters:
channel – a merged-stack channel index.
- Raises:
IlluminationError – if the model was never estimated for it. Correcting the channels that happen to be present and leaving the rest alone would put corrected and uncorrected numbers in the same table.
- nonuniformity() Dict[int, float][source]¶
Per channel,
(p98 - p2) / meanof the field, as a fraction.A single measure of how uneven the illumination is: 0.30 means the bright and dim ends of the field of view differ by 30 % of the mean, and therefore so does the same cell measured in those two places.
- class spacr.illumination.IlluminationModel[source]¶
Estimated illumination fields for every plate in a source folder.
- Parameters:
fields – plate key ->
IlluminationField. A model estimated withper_plate=Falseholds the single keyALL_PLATES, which matches every plate.meta – provenance – source folders, channels, when it was estimated, the settings it was estimated with. Written into the
.npzand read back, so a model on disk records what produced it.
- describe() str[source]¶
Every field’s
IlluminationField.describe(), one per line.
- field_for(plate: str) IlluminationField[source]¶
The
IlluminationFieldthat applies toplate.- Parameters:
plate – plate key whose estimated illumination field is needed.
- Raises:
IlluminationError – when nothing in the model covers it. There is no fallback to another plate’s field: illumination differs between acquisition sessions, which is why the default is one field per plate.
- classmethod load(path: str) IlluminationModel[source]¶
Read a model written by
save().- Parameters:
path – the
.npzfile.- Raises:
IlluminationError – when the file is missing or is not a spaCR illumination model, so a worker that cannot load the model stops instead of measuring uncorrected pixels.
- save(path: str) str[source]¶
Write the model to
pathas a compressed.npz.The path is what
enable_illumination_correction()puts in the environment, and what each worker process loads: the model has to be on disk for aspawnworker to be able to see it at all.- Parameters:
path – destination file. Parent folders are created.
- Returns:
the absolute path written.
- class spacr.illumination.PreparedIllumination[source]¶
One fitted/loaded model and the stage-neutral objects derived from it.
The saved model is deliberately not tagged
measurementorsegmentation: both stages may reuse the same optical estimate. The stage that applies it owns that provenance separately.- Parameters:
model – loaded or newly estimated illumination model.
corrector – corrector configured with the requested missing-plate policy, but not registered as a Measure preprocessing hook.
model_path – absolute path of the saved model.
model_sha256 – digest of the exact saved bytes at
model_path.qc_artifacts – QC figure paths written while preparing the model.
- class spacr.illumination.SegmentationIlluminationSession(prepared: PreparedIllumination, *, provenance_path: str, pipeline_style: str, resume: bool = False)[source]¶
Apply one illumination model exactly once per segmentation field.
Correction always receives a private copy.
correct()records that an in-memory input was corrected;mark_completed()is deliberately separate and is the only operation that persists a field id. A pipeline therefore marks a field only after its durable NPZ/mask output exists.- Parameters:
prepared – model/corrector returned by
prepare_illumination_model().provenance_path – destination
segmentation_application.json.pipeline_style –
'v1'or'v2'for the audit record.resume – restore explicitly completed fields from an existing compatible record without rewriting it; absence is an error. False starts a fresh regenerated-output session and atomically replaces any old completion claim with an explicit
preparedrecord.
Open a segmentation-input correction session and stamp its provenance.
- Parameters:
prepared – the validated illumination model and its QC artefacts.
provenance_path – where the application record is written.
pipeline_style – which segmentation pipeline this corrects for.
resume – continue a previous session, reading back which fields it already completed. Without it a fresh record is written stating that no field has yet been corrected – a new preprocessing run invalidates any earlier completion claim, and the explicit record keeps a half-finished run from being read as a finished one.
- correct(field_id: str, channel_arrays: numpy.ndarray, context) numpy.ndarray[source]¶
Correct a private copy of one raw field, refusing a second pass.
- Parameters:
field_id – identifier of the raw field, compared as a string; a field already corrected or marked complete raises
IlluminationError.channel_arrays – raw field intensities,
(Y, X, C)or(Z, Y, X, C); a copy is corrected and the input is left unchanged.context – the
spacr.measure_hooks.PreprocessingContextpassed to the prepared corrector; its file name selects the plate’s model.
- finish(expected_fields: Iterable[str]) None[source]¶
Mark the journal stage done after every expected field is durable.
- Parameters:
expected_fields – identifiers of every field the run should have completed; the set, compared as strings, must equal the completed set exactly or
IlluminationErroris raised.
- mark_completed(field_id: str) bool[source]¶
Persist
field_idafter its corrected pipeline output is durable.- Parameters:
field_id – identifier of a field already passed to
correct(), compared as a string; an uncorrected field raisesIlluminationError.- Returns:
Truewhen the record changed,Falsewhen the same completed field was marked again.
- spacr.illumination.disable_illumination_correction() bool[source]¶
Turn the correction off, here and for any worker started afterwards.
Unregisters the hook and removes this module’s entry from
SPACR_MEASURE_HOOKS– leaving any other extension’s entries alone – plus the two model variables.- Returns:
True if a correction was registered and has been removed.
- spacr.illumination.enable_illumination_correction(model, *, path: str | None = None, on_missing: str = 'error', verbose: bool = True) str[source]¶
Turn the correction on, here and in every worker process.
Three things happen; the third is what makes worker processes install the hook:
the model is saved to disk if it is not already there – a
spawnworker can only reach it through the file system;MODEL_ENV_VARandON_MISSING_ENV_VARare set;spacr.illumination:installis appended toSPACR_MEASURE_HOOKS(appended, not assigned – another extension may already be in there), and the registry is then consulted so that this process installs the hook through that same environment route.
- Parameters:
model – an
IlluminationModel, or the path to a saved one.path – where to save
modelwhen it is not already a path. Defaults to<first src>/../illumination/illumination_model.npz.on_missing –
'error'or'skip'; seeIlluminationCorrector.verbose – print what was enabled and whether workers will see it.
- Returns:
the registry key the hook is registered under.
- Raises:
IlluminationError – when the model cannot be saved or loaded.
- spacr.illumination.estimate_illumination(src, channels: Sequence[int], *, per_plate: bool = True, estimator: str = 'polynomial', degree: int = 4, max_fields: int = 50, grid: int = 256, dark: float = 0.0, verbose: bool = True) IlluminationModel[source]¶
Estimate the illumination field from the merged fields in
src.Retrospective: the field is estimated from the same images it corrects, with no calibration image. See the module docstring for what is estimated and why.
- Parameters:
src – the merged field folder
measure_cropreads, or a list of them (settings['src']accepts both).channels – merged-stack channel indices to estimate, i.e.
settings['channels']. One field is estimated per channel: two fluorophores go through different filters and vignette differently.per_plate – one field per plate (default) or one for everything. Per plate is the default because illumination differs between acquisition sessions – lamp age, a re-seated filter cube, a different objective – and pooling two sessions estimates neither.
estimator –
'polynomial'(default) or'smooth'.degree – polynomial degree. 4 gives 15 terms: enough for a lamp profile plus a vignette and a tilt, far too few to fit a cell.
max_fields – fields per plate to estimate from, sampled evenly across the sorted file list. 50 is well past the point where the across-field median stops moving, and bounds the memory.
grid – the per-pixel median is computed on a binned grid whose long side is at most this. Illumination is low-frequency, so binning loses little of the field’s structure, reduces photon noise and is what makes 50 fields fit in memory. The fitted surface is returned at full resolution.
dark – additive camera offset subtracted before dividing, in raw counts. Not estimated – see the module docstring.
verbose – print one line per estimated field.
- Returns:
- Raises:
IlluminationError – when
srcholds no merged fields, or a field is unreadable in a way that would make the estimate meaningless.
- spacr.illumination.illumination_qc(model: IlluminationModel, src, *, channels: Sequence[int] | None = None, save_dir: str | None = None, max_fields: int = 25, verbose: bool = True, stage: str | None = None) Dict[str, Any][source]¶
Plot and quantify the position-dependent bias before and after correction.
Three things, per plate and per channel:
the estimated field as an image, so a lamp profile that is really a dirty objective is visible rather than inferred;
the position-versus-intensity trend before and after, measured on the same fields the estimate came from – the curve that should be flat after correction and is not before it;
a number: the residual slope of intensity against distance from the centre of the field, before and after, and the percentage of that bias the correction removed.
- Parameters:
model – the estimated model.
src – the merged field folder(s) to measure the trend on.
channels – channels to report; defaults to the model’s own.
save_dir – where the figure goes. Defaults to
<first src>/../illumination. Pass''to skip the figure and compute only the numbers.max_fields – fields per plate to measure the trend over.
verbose – print the per-channel summary.
stage – optional consumer label such as
'segmentation_input'. When supplied it appears in the figure title and filename, preventing segmentation and measurement QC artifacts from being confused.
- Returns:
{plate: {channel: {...metrics...}}}with, per channel,slope_before,slope_after,bias_removed_pct,nonuniformity_pct,gain_min,gain_maxandn_fields; plus, when a figure was written, one extra key'_figures'mapping each plate to the path of its PNG.
- spacr.illumination.illumination_settings(settings=None)[source]¶
Return a copy of
settingswith the illumination defaults filled in.- Parameters:
settings – values to seed, exactly like every
set_default_*inspacr.settings.- Returns:
the settings dict with the illumination defaults applied.
- spacr.illumination.install() str[source]¶
Install the correction in this process from the environment.
This is the zero-argument installer
SPACR_MEASURE_HOOKSnames, and the only route that survives aspawn/forkserverworker: the worker is a fresh interpreter, so it imports this module and calls this function for itself, reading the model fromMODEL_ENV_VAR.- Returns:
the registry key the hook was registered under.
- Raises:
IlluminationError – if the environment does not name a readable model, so a worker that cannot load the model stops instead of measuring uncorrected pixels.
- spacr.illumination.load_illumination_model(path: str) IlluminationModel[source]¶
Read a saved model. Thin alias for
IlluminationModel.load().- Parameters:
path – the
.npzwritten byIlluminationModel.save().
- spacr.illumination.load_segmentation_illumination_resume(settings: Mapping[str, Any], *, provenance_path: str, pipeline_style: str, expected_fields: Iterable[str], verbose: bool | None = None) PreparedIllumination[source]¶
Read and validate prior segmentation illumination without side effects.
This is the
preprocess=Falseentry point. The application record is authoritative: its exact model path is loaded and its digest, metadata, pipeline style, and completed-field set are checked before the caller may trust existing normalised mask NPZ files. No model is fitted, no QC or application record is written, no pixels are corrected, and no Measure hook is installed.- Parameters:
settings – run settings;
illumination_correctionmust be true, andillumination_model(when set),illumination_on_missingandverboseare read.provenance_path – path of the prior segmentation application record (JSON); its
model_pathis resolved relative to this file’s folder when not absolute.pipeline_style – segmentation pipeline style,
'v1'or'v2'(case-insensitive); any other value raisesIlluminationError.expected_fields – identifiers of the mask fields already on disk; the record’s completed-field set must equal them exactly.
- spacr.illumination.plate_of_field(file_name: str) str[source]¶
The plate a merged field belongs to, from its file name.
spaCR names merged fields
<plateID>_<wellID>_<fieldID>.npy(seespacr.io), so the plate is the first underscore-separated token. A name with no underscore is its own plate, which keeps a hand-assembled folder working instead of silently pooling it.- Parameters:
file_name – file name or stem, with or without directories.
- spacr.illumination.position_intensity_slope(intensities: Sequence[float], coordinates: numpy.ndarray, shape: Tuple[int, int]) float[source]¶
Least-squares slope of intensity against distance from the field centre.
A successful illumination correction brings this slope close to zero. The same statistic is used on pixels (the QC images) and on objects (the requirement that the same cell not measure brighter in the middle of the field).
Intensities are divided by their own mean and the radius is normalised so that 0 is the centre of the field and 1 is a corner, so the slope reads as the fraction of the mean intensity gained or lost between the centre of the field and its corner. -0.30 means a corner object measures 30 % of the mean below a central one.
- Parameters:
intensities – one value per position.
coordinates –
(N, 2)array of(row, col)positions in pixels.shape –
(Y, X)shape of the field the positions live in.
- Returns:
the slope, or 0.0 when there is nothing to fit.
- spacr.illumination.prepare_illumination_correction(settings: Mapping[str, Any], *, verbose: bool | None = None)[source]¶
Estimate, save, enable and QC the Measure correction.
A pipeline calls this before
measure_crop. The Illumination button on the Measure masthead runs it on its own, which writes the model and its QC figures without a measure run; a later measure run can reuse the model throughillumination_model.It does nothing and returns None unless
settings['illumination_correction']is True. The shipped default is False: the correction is opt-in, so a run that does not set it is measured uncorrected. When verbose, a call with the setting off prints thatillumination_correctionis False, because from a settings form the no-op otherwise looks like a Run button that does nothing.- Parameters:
settings – a
measure_cropsettings dict. Readsillumination_correction,illumination_model,illumination_estimator,illumination_degree,illumination_per_plate,illumination_max_fields,illumination_dark,illumination_on_missing,illumination_qc,illumination_vendor_profile,illumination_vendor_channel_map, plussrcandchannels.verbose – overrides
settings['verbose'].
- Returns:
the
IlluminationModelthat was enabled, or None.
- spacr.illumination.prepare_illumination_model(settings: Mapping[str, Any], *, src=None, channels: Sequence[int] | None = None, qc_stage: str | None = None, verbose: bool | None = None) PreparedIllumination | None[source]¶
Prepare one reusable optical model without installing a Measure hook.
This is the direct consumer of the
illumination_*settings. It estimates, loads or reads a vendor flat-field profile into the model once, ensures a fitted model is saved, hashes the exact saved bytes, optionally writes stage-labelled QC, and builds a corrector. Applying that corrector belongs to the caller’s stage.- Parameters:
settings – settings carrying the illumination controls. A non-empty
illumination_vendor_profilereplaces the estimate with the vendor’s own flat field;illumination_vendor_channel_mapoptionally assigns persisted channels to vendor channels/planes.illumination_modelstill wins over both.src – optional raw field folder override. Defaults to
settings['src'].channels – optional persisted intensity-axis positions. Defaults to
settings['channels'].qc_stage – optional stage label included in QC filenames/titles.
verbose – override
settings['verbose'].
- Returns:
a prepared model/corrector, or
Nonewhen correction is off.
- spacr.illumination.prepare_segmentation_illumination(settings: Mapping[str, Any], *, src=None, channels: Sequence[int] | None = None, pipeline_style: str, verbose: bool | None = None) SegmentationIlluminationSession | None[source]¶
Prepare correction for segmentation inputs without changing raw data.
The returned session is not a Measure hook. V1/V2 adapters hand it raw field copies, then explicitly mark fields complete after their durable segmentation output exists. The application record is stored beside the current run’s source folder, even when the optical model is shared from an external path, so two runs cannot overwrite one another’s completion set.
- Parameters:
settings – run settings carrying the illumination controls read by
prepare_illumination_model(), andsrcwhensrcis not given.pipeline_style – segmentation pipeline style,
'v1'or'v2'(case-insensitive); any other value raisesIlluminationError.
- spacr.illumination.register_illumination_settings(replace: bool = False) bool[source]¶
Register the illumination settings through the defaults seam.
Called once at import. Uses
spacr.settings.register_defaults()rather than appending tospacr/settings.py, so this module owns its own knobs.Types, tooltips and the module description are contributed; categories are not.
spacr.settings.categoriesis one shared, ordered map that every settings panel walks, and its growth is guarded by an exact-equality test against a hand-kept list. A key contributed at import time is in that map only in a session that imported this module, so contributing categories would make that test’s result depend on which files pytest was pointed at.The illumination keys are still filed under a heading – “Illumination Correction” in
spacr.settings.categories– and Measure’s panel offers every one of them, becausemeasure_cropcallsprepare_illumination_correction()itself and these are the keys that call reads. The heading is written in that map by hand for the reason above: it has to exist for every process that groups the Measure settings, not only for one that happened to import this module.- Parameters:
replace – re-register over an existing registration.
- Returns:
True if it registered, False if it was already registered.
- spacr.illumination.validate_measurement_illumination_inputs(settings: Mapping[str, Any], *, src=None) Dict[str, Dict[str, Any]][source]¶
Raise before Measure corrects pixels that segmentation already corrected.
Segmentation is allowed to correct only its private model input. If a mask run ever records that it instead changed the persisted intensities, Measure must not install another gain over those pixels: doing so squares the optical field while producing entirely plausible numbers. A missing application record is the legacy/raw case and remains valid; a present record must prove the current
segmentation-input-onlycontract.This check is deliberately read-only. It neither creates an illumination folder nor repairs a malformed record, and it does nothing when Measure’s own illumination correction is off.
- Parameters:
settings – resolved Measure settings.
src – optional merged-folder override; defaults to
settings['src']and accepts the same folder-or-list shape.
- Returns:
absolute application-record paths mapped to their validated JSON objects; an empty dict means no segmentation record was present.
- Raises:
IlluminationError – when a present record is unreadable or cannot prove that persisted intensity pixels remain raw.
- spacr.illumination.validate_segmentation_illumination_resume(prepared: PreparedIllumination, *, provenance_path: str, pipeline_style: str, expected_fields: Iterable[str]) Dict[str, Any][source]¶
Validate a
preprocess=Falsemask resume without writing anything.Normalised mask NPZ files cannot prove which intensity state Cellpose saw. A bypassed preprocessing stage therefore proceeds only when a prior application record names the same model bytes and pipeline style and covers exactly the fields already on disk. This function never fits a model, creates a record, corrects pixels, or updates the run journal.
- Parameters:
prepared – the loaded model and corrector whose model path and digest the record must name.
provenance_path – path of the prior segmentation application record (JSON) to read.
pipeline_style – segmentation pipeline style the record must match,
'v1'or'v2'(case-insensitive).expected_fields – identifiers of the mask fields already on disk; the record’s completed-field set, compared as strings, must equal them exactly.
- Returns:
the validated existing application record.
- Raises:
IlluminationError – for an absent or incompatible record, model, pipeline style, or completed-field set.
- spacr.illumination.worker_delivery_status(start_method: str | None = None) Tuple[bool, str][source]¶
Whether the correction will actually reach
measure_crop’s workers.The failure checked for raises no error: a hook registered only in the parent process is a no-op in every
spawnworker, the run completes, and the numbers are uncorrected although correction was enabled.- Parameters:
start_method – the pool start method to judge against. Defaults to whatever
SPACR_START_METHODselects, falling back to the platform default – i.e. whatspacr.measure.measure_crop()will use.- Returns:
(ok, message).okis False whenever a field could be measured uncorrected without anything saying so.
Nested helpers¶
- _lenient_profile_json._value(match)¶
Quote a bare profile value while preserving JSON booleans and null.
spacr/illumination.py:885