spacr.crop_source

Resolve, filter and cut the images used to train a classifier.

The crop source has two main values, named as in the other spaCR panels: LOAD IMAGES and STREAM IMAGES. Training previously used its own terms (pre_generated / on_demand) for the same choice, so the annotation and training panels presented one setting under two sets of names.

png — load pre-generated images (default)

Read crops previously written by the measurement workflow. path_string filters paths by substring and file_type filters by image extension. This source performs no cropping.

merged — stream images

Extract crops during training from merged/*.npy arrays. extract_channels selects the intensity planes and object_array selects the labelled mask plane that defines each object’s extent. When coordinate_columns are configured, database coordinates instead define fixed bounding-box crops.

generate — generate images, then load them

Materialize a complete crop set on disk before training, then read it through the same file-backed path as png. This is a preprocessing action rather than a streaming source.

The stored values did not change. png and merged are what spacr.crops.resolve_crop_source has always read, so a settings file written under either vocabulary means what it always meant: pre_generated, load_images and auto all arrive as LOAD IMAGES, on_demand and stream_images as STREAM IMAGES. CROP_SOURCE_ALIASES is that migration, in one place, so a value written by a renamed panel is still accepted.

Why streaming exists. Pre-cutting every crop writes a copy of the dataset to disk before a single epoch runs, and every change of crop size or channel selection writes another. Cutting as training runs costs a slice per object and no disk at all.

Bounding box versus object. A bounding box is the smallest rectangle containing the object; an object crop masks everything outside it away. Both are useful – the background around a cell is sometimes signal and sometimes contamination – so it is a setting. Database-sourced objects can only ever be bounding boxes: a coordinate has no outline to mask against.

Exceptions

CropSourceError

A crop source that cannot produce images, and why.

Functions

crop_at(→ Optional[numpy.ndarray])

Cut a fixed box centred on a coordinate.

crop_object(→ Optional[numpy.ndarray])

Cut one object out of a merged array.

crops_from_merged(→ List[Tuple[int, numpy.ndarray]])

Every object's crop from one merged array.

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

Return the settings used only by the other crop sources, for greying out.

mask_plane_for(→ int)

Which plane of the merged array holds object_array's masks.

matches_path(→ bool)

Whether one crop belongs in the dataset.

normalise_extension(→ str)

The extension file_type names, without its dot and lower-cased.

object_bounds(→ Optional[Tuple[int, int, int, int]])

(row0, row1, col0, col1) of one labelled object, or None if absent.

resolve_source(→ str)

Return the canonical crop source (png, merged or generate).

select_crops(→ List[str])

The crops a settings dict selects, in the order given.

stream_planes(→ List[int])

Which planes of a merged array become image channels, by either name.

validate(→ str)

Check that a settings dict can produce crops and return its source.

Module Contents

exception spacr.crop_source.CropSourceError[source]

Bases: ValueError

A crop source that cannot produce images, and why.

Initialize self. See help(type(self)) for accurate signature.

spacr.crop_source.crop_at(array: numpy.ndarray, row: float, column: float, *, channels: Sequence[int], size: int) → numpy.ndarray | None[source]

Cut a fixed box centred on a coordinate.

Used for objects taken from a database. Only a bounding box is possible, because a coordinate has no outline to mask against.

Parameters:
  • array – the merged stack, (H, W, planes). Its rank is not checked as crop_object() checks it, so a 2-D image raises IndexError from the slice rather than a CropSourceError.

  • row – centre on the FIRST axis – an image row, not y. Floats are rounded half-to-even, Python’s rule, so a centroid of 2.5 lands on row 2 while 3.5 lands on row 4.

  • column – centre on the second axis; rounded the same way.

  • channels – which planes become image channels, in the order given, so [2, 0] returns them swapped. A bare int counts as a one-plane list. Not bounds-checked here as it is in crop_object(): a plane the array does not have raises IndexError, and a negative one silently counts back from the last plane. An empty list yields a zero-channel crop rather than None.

  • size – the positive side length returned. Odd sizes keep the rounded coordinate at index size // 2. A box crossing an array edge is zero-padded rather than clipped or rescaled, preserving its centre and pixel scale.

Returns:

(size, size, len(channels)) as float32, or None when the box falls entirely off the array.

Raises:

CropSourceError – channels is None or is not planes, or size is not positive.

spacr.crop_source.crop_object(array: numpy.ndarray, mask: numpy.ndarray, label: int, *, channels: Sequence[int], shape: str = 'bounding_box', size: int | None = None, padding: int = 0) → numpy.ndarray | None[source]

Cut one object out of a merged array.

Parameters:
  • array – the merged stack, (H, W, planes).

  • mask – the plane holding this object’s labels.

  • label – which object.

  • channels – which planes become image channels, in order.

  • shape – bounding_box keeps the rectangle’s contents; object zeroes everything outside the object itself. The background around a cell is sometimes signal and sometimes contamination, which is why this is a choice rather than a default.

  • size – resize the result to size × size when given. It must be positive; None preserves the object’s natural bounding box.

Returns:

(h, w, len(channels)), or None if the object is not there.

Raises:

CropSourceError – a plane the array does not have, or an explicit size that is not positive.

spacr.crop_source.crops_from_merged(array: numpy.ndarray, settings: Mapping[str, Any], *, labels: Sequence[int] | None = None) → List[Tuple[int, numpy.ndarray]][source]

Every object’s crop from one merged array.

Parameters:
  • array – merged (height, width, planes) image whose configured object-mask plane supplies the labels and whose other planes supply the crop pixels.

  • settings – crop settings used to choose the object mask, extracted channels, crop shape and optional fixed image size.

  • labels – only these objects; by default every label in the mask.

Returns:

(label, image) pairs, skipping objects that are not present.

Raises:

CropSourceError – a setting that makes cutting impossible.

spacr.crop_source.inapplicable_settings(source: str) → Tuple[str, ...][source]

Return the settings used only by the other crop sources, for greying out.

Greyed, never removed (INVARIANTS 6): a key absent from the dict makes the pipeline fall back to its own default, which can differ from the value the module needs, without a warning.

Any spelling CROP_SOURCE_ALIASES knows is accepted, because what a panel has in hand is the value stored in the settings file, not the name this module resolved it to.

Parameters:

source – the crop source whose settings stay active; any spelling in CROP_SOURCE_ALIASES, matched case-insensitively. An unknown source raises CropSourceError.

spacr.crop_source.mask_plane_for(object_array: str, settings: Mapping[str, Any]) → int[source]

Which plane of the merged array holds object_array’s masks.

Read from the *_mask_dim settings the mask step already writes, so the two cannot disagree about which plane is which.

Parameters:
  • object_array – the object name (e.g. cell, nucleus); lower-cased and used to build the <name>_mask_dim setting key.

  • settings – the settings mapping the <name>_mask_dim plane index is read from.

Raises:

CropSourceError – the object has no mask plane, naming the setting that would give it one.

spacr.crop_source.matches_path(path: str, *, path_string: str = '', file_type: Any = '') → bool[source]

Whether one crop belongs in the dataset.

Two independent tests are applied: the object type, as a substring of the path (e.g. cell_png), and the file format, as the extension. Keeping them separate allows selections such as “every nucleus crop, any format” or “every TIFF, any object”.

Parameters:

path – the crop’s file path, tested as a string for the path_string substring and for its extension.

spacr.crop_source.normalise_extension(file_type: Any) → str[source]

The extension file_type names, without its dot and lower-cased.

The setting previously held path substrings such as 'cell_png', duplicating png_type. It now names only an extension: '.TIF' and 'tif' both normalise to 'tif', and 'tiff' to 'tiff'.

Parameters:

file_type – an extension such as '.TIF', 'tif' or 'cell_png' (only the part after the last underscore is kept); empty or None gives ''.

Raises:

CropSourceError – an extension spaCR cannot read, named alongside the ones it can.

spacr.crop_source.object_bounds(mask: numpy.ndarray, label: int) → Tuple[int, int, int, int] | None[source]

(row0, row1, col0, col1) of one labelled object, or None if absent.

Half-open on the far edge, like every other slice in Python, so the caller can index with it directly rather than remembering to add one.

Parameters:
  • mask – 2-D label image holding the object.

  • label – the label value of the object to bound.

spacr.crop_source.resolve_source(settings: Mapping[str, Any]) → str[source]

Return the canonical crop source (png, merged or generate).

Every spelling in CROP_SOURCE_ALIASES resolves, so a settings file written by any released spaCR panel is accepted. An unset value means LOAD IMAGES, the default in every panel.

Parameters:

settings – the settings mapping; its crop_source value is looked up in CROP_SOURCE_ALIASES, and an empty value means png.

Raises:

CropSourceError – an unrecognised source. The source is not guessed, because a wrong guess would train on different images without error.

spacr.crop_source.select_crops(paths: Iterable[str], settings: Mapping[str, Any]) → List[str][source]

The crops a settings dict selects, in the order given.

Parameters:
  • paths – candidate crop file paths.

  • settings – the settings mapping; path_string (or, failing that, png_type) and file_type are passed to matches_path().

spacr.crop_source.stream_planes(settings: Mapping[str, Any]) → List[int][source]

Which planes of a merged array become image channels, by either name.

channel_arrays is the current spelling and extract_channels the older one; both are a list of plane indices and both are still written to settings files, so both are read here. The current spelling wins when a file carries both, because that is the one the panel is editing.

Parameters:

settings – the settings mapping; channel_arrays is read first, then extract_channels.

Raises:

CropSourceError – neither is set, naming the one to set.

spacr.crop_source.validate(settings: Mapping[str, Any]) → str[source]

Check that a settings dict can produce crops and return its source.

Run before training, so a missing plane setting is reported before dataset building starts; the error message names the setting to fix.

Parameters:

settings – the training settings mapping to check: the crop source, plus file_type for png or the plane, crop-shape, coordinate and mask settings for a streamed source.

Raises:

CropSourceError – with what to change.