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_componentsof 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
Functions
|
|
|
A form's "true"/"false" as a bool; anything else by Python's truth. |
|
|
|
An id per connected object of |
|
Objects from affinities: |
|
Objects from a distance map: higher deeper inside an object, |
|
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
valueas scipy’s connectivity for anndim-D array: 1 up tondim.Forms send strings, so “2” is 2. A value past
ndim(3 for one 2D slice) isndim: 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)
labelswith objects of fewer thanmin_sizevoxels made background.The rest are numbered 1..n again, in the order they had.
labelsmust 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.agglomjoins voxels along edges whose affinity is abovebiasand 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 belowbiasis 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 forconnected_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,
thresholdat its boundary.Foreground is
distance > threshold. Each object grows from a marker, by a watershed of-distanceinside 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_depthabove 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 thanpeak_depthdoes 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.