cellmap_flow.post.segment

Instance segmenters: from what a model predicts to an id per object.

Plain functions on numpy arrays, shared by the postprocessors a served layer runs (post.postprocessors) and by the Finetune tab’s “Seed from Prediction” (dashboard/routes/finetune/view_labels.py), so a model’s objects come out the same in both. Which one fits follows from what the model outputs, not from its name:

  • a probability, or any map with a foreground threshold: connected_components of the thresholded mask. Touching objects stay one object.

  • affinities to the neighbours at given offsets: mutex_watershed. The model says where two voxels belong apart, so touching objects split.

  • a distance to the object boundary: distance_watershed, which cuts touching objects apart where the distance dips between their centres.

  • integer instance labels of the model’s own (Cellpose’s masks): relabel_instances.

Each returns uint64 labels, 0 for background and 1..n for the objects with no id skipped, so labels.max() is how many there are.

connectivity is scipy’s (ndimage.generate_binary_structure): which neighbours touch. 1, faces only (6 in 3D, 4 in a 2D slice), is the default everywhere: a one-voxel background wall painted with the brush cuts an object under it, where with 3 (all 26 neighbours) voxels across a diagonal wall still touch. 2 adds the edge neighbours (18 in 3D, 8 in 2D).

The segmentation libraries are imported inside the functions: the postprocessors import this module, and every chain is read through them, in processes that never segment anything (tests/utils/test_import_hygiene).

Attributes

CONNECTIVITIES

Functions

as_connectivity(→ int)

value as scipy's connectivity for an ndim-D array: 1 up to ndim.

as_bool(→ bool)

A form's "true"/"false" as a bool; anything else by Python's truth.

remove_small(labels[, min_size])

labels with objects of fewer than min_size voxels made background.

connected_components(mask[, connectivity, min_size, ...])

An id per connected object of mask (its nonzero voxels).

mutex_watershed(affinities, offsets[, bias, min_size])

Objects from affinities: (channels, z, y, x), one channel per offset, in [0, 1].

distance_watershed(distance[, threshold, markers, ...])

Objects from a distance map: higher deeper inside an object, threshold at its boundary.

relabel_instances(labels[, split_disconnected, ...])

A model's own integer instance labels, numbered 1..n (0 stays background).

Module Contents

cellmap_flow.post.segment.CONNECTIVITIES
cellmap_flow.post.segment.as_connectivity(value, ndim=3) → int

value as scipy’s connectivity for an ndim-D array: 1 up to ndim.

Forms send strings, so “2” is 2. A value past ndim (3 for one 2D slice) is ndim: every neighbour, which is what it asked for. Raises ValueError for anything that is not 1, 2 or 3.

cellmap_flow.post.segment.as_bool(value) → bool

A form’s “true”/”false” as a bool; anything else by Python’s truth.

cellmap_flow.post.segment.remove_small(labels, min_size=0)

labels with objects of fewer than min_size voxels made background.

The rest are numbered 1..n again, in the order they had. labels must already be numbered without large gaps (any segmenter’s output): the sizes are counted per id.

cellmap_flow.post.segment.connected_components(mask, connectivity=1, min_size=0, per_slice=False)

An id per connected object of mask (its nonzero voxels).

per_slice: each z slice of a (z, y, x) mask is labelled on its own, in 2D, its ids following the slice before’s. For data whose objects are 2D (what Cellpose sees), or annotations painted slice by slice: an object touching itself across slices is still one per slice. min_size: objects of fewer voxels are background (specks a threshold let through); per slice, each slice’s piece is counted alone.

cellmap_flow.post.segment.mutex_watershed(affinities, offsets, bias=0.0, min_size=0)

Objects from affinities: (channels, z, y, x), one channel per offset, in [0, 1].

mwatershed.agglom joins voxels along edges whose affinity is above bias and keeps them apart along those below it, strongest edges first. Every voxel ends up in some fragment, background included, so a fragment whose mean affinity (over all the channels) is below bias is background: it is where the model sees no object. offsets: the voxel offset each channel compares, as the model was trained with; a list longer than the channels is cut to them. min_size: as for connected_components.

cellmap_flow.post.segment.distance_watershed(distance, threshold=0.5, markers='peaks', peak_depth=0.05, marker_threshold=0.9, connectivity=1, min_size=0)

Objects from a distance map: higher deeper inside an object, threshold at its boundary.

Foreground is distance > threshold. Each object grows from a marker, by a watershed of -distance inside the foreground, so two touching objects meet where the distance dips between their centres: the neck a threshold alone would leave joined. markers:

  • “peaks” (default): the distance’s maxima that stand at least peak_depth above the lowest point on any path to a higher one (h-maxima). A noisy plateau inside one object is one marker, and a neck shallower than peak_depth does not split.

  • “threshold”: the connected parts of distance > marker_threshold, the objects’ cores. For a model whose distance saturates inside objects, where the peaks are flat.

The defaults are for a probability-like map (0.5 at the boundary, as the cellmap distance models’ sigmoid gives, and Seed from Prediction makes of any output); for a distance in voxels, give the threshold and depth in voxels. A foreground part no marker reaches is an object of its own, so nothing the threshold calls foreground is lost.

cellmap_flow.post.segment.relabel_instances(labels, split_disconnected=False, connectivity=1, min_size=0)

A model’s own integer instance labels, numbered 1..n (0 stays background).

split_disconnected: each id’s connected parts become objects of their own. For labels whose ids are unique only within a block (a Cellpose server numbers each chunk from 1), read across several blocks: the same id in two blocks is two objects, and they do not touch.