cellmap_flow.portable.label_it
Label it’s segmentation of a prediction, written once for both modes.
What the Finetune tab’s Seed from Prediction makes of a model’s output over
the box on screen: the request’s options (seed_options), the channels a
seed reads (seed_channels; affinity_offsets for a model known by its
channel names alone), which served voxel lies under each annotation voxel
(placement, gather), the output as a probability (probability)
and the objects of the components method (components: threshold,
connected components, smallest size, per slice). The server calls these
from dashboard/routes/finetune/view_labels.py around its read of the
model server’s array; the browser from web/src/backend/routes/view-labels.ts
around the engine’s readOutput, through label_it_calls.py.
The box every tool covers is here too when the page asks for the field of
view (field_of_view_nm): what the viewer’s panel shows, at the slice on
screen, rather than a box around its centre.
The mutex watershed is the one method not here: mwatershed is Rust, with
no Pyodide wheel, so each mode runs its own on what affinities gives
(post.segment.mutex_watershed on the server, web/src/infer/affinity.ts
in the browser, parity-tested against it). The distance watershed and a
model’s own instances are the server’s alone (scikit-image, Cellpose); no
model the browser runs outputs either.
scipy is imported inside the functions that need it, never at the top: the browser’s Python starts with numpy alone, and chunkmirage’s worker loads a package the first time a call fails to import it, then calls again, so the first seed pays for scipy and opening a dataset does not.
Attributes
Functions
|
Bucket an observed (min, max) output range into an activation class; |
|
|
|
A form's "true"/"false" as a bool; anything else by Python's truth. |
|
A seed request's options, from its JSON body, with the defaults the |
|
The offsets of a model known by its channel names alone, or None |
|
The channels a seed reads, as a slice, or None for every one. |
|
Which voxel of a served array each annotation voxel of |
|
|
|
The prediction on the annotation grid: each annotation voxel the |
|
The prediction as a probability, (channels, z, y, x), 0.5 at the model's decision boundary. |
|
Where the model says foreground: its |
|
The mutex watershed's input: the probability of an affinity model's |
|
|
|
An id per connected object of |
|
The objects of the components method: the |
|
|
|
The size in nm (z, y, x) of the box the viewer's panel shows: the |
Module Contents
- cellmap_flow.portable.label_it.SEED_METHODS = ('components', 'mutex_watershed', 'distance_watershed', 'instances')
- cellmap_flow.portable.label_it.UNIT = 'unit'
- cellmap_flow.portable.label_it.SIGNED_UNIT = 'signed_unit'
- cellmap_flow.portable.label_it.UNBOUNDED = 'unbounded'
- cellmap_flow.portable.label_it.CONNECTIVITIES
- cellmap_flow.portable.label_it.classify_output_range(lo: float, hi: float) str | None
Bucket an observed (min, max) output range into an activation class; None for a flat one, max - min within the tolerance.
A flat output is no evidence: jrc_mus-livers_16nm_to_8nm_peroxisome gave -0.9595 everywhere on the server’s noise, read as a tanh’s [-1, 1], when its network ends in a Conv (logits); a sigmoid saturated everywhere would be as flat at 1. Whatever the values, a range they do not span says nothing of what the output can be.
- cellmap_flow.portable.label_it.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, None among them.
- cellmap_flow.portable.label_it.as_bool(value) bool
A form’s “true”/”false” as a bool; anything else by Python’s truth.
- cellmap_flow.portable.label_it.seed_options(data) dict
A seed request’s options, from its JSON body, with the defaults the routes give an absent one:
method(“components”),threshold(a probability, 0.5, the model’s own boundary),min_size(0),connectivity(1, faces) andper_slice(false).Raises ValueError, which both modes answer 400, for a threshold outside 0 to 1, a negative or non-integer size, a method not in SEED_METHODS and a connectivity that is not 1, 2 or 3. A
connectivitygiven as null is refused with the rest, not read as absent: the key is there.
- cellmap_flow.portable.label_it.affinity_offsets(channel_names)
The offsets of a model known by its channel names alone, or None when they name no affinity channel.
The server’s rule for a model whose script says none (
dashboard/routes/finetune/common.autodetect_output_type): a model with a channel named*_aff*is an affinity model, and its first affinity channels, up to three, compare each voxel with the next one along z, y and x in turn, whatever their names say after_aff.
- cellmap_flow.portable.label_it.seed_channels(output_type, offsets, select_channel=None)
The channels a seed reads, as a slice, or None for every one.
As the trainer targets them: the selected channel; else an affinity model’s offset channels, the first
len(offsets)(the rest, LSDs say, are masked out of its loss); else every channel, which a binary target is broadcast over.offsetsis a list of the model’s offsets. A slice past the model’s channels reads those there are (probability).
- cellmap_flow.portable.label_it.placement(lo, hi, voxel_size, dataset_offset_nm, translation, declared, shape, drawn=None)
Which voxel of a served array each annotation voxel of
[lo, hi)reads: the one its centre lies in, so a seed from a model served at another voxel size (any served model can seed, not only the one the volume is for) lies under that model’s layer.The volume’s grid is its
voxel_sizefromdataset_offset_nm, the centre of its voxel 0 (its OME translation, asfinetune/session/volume.volume_corner_nmreads it; None is 0). The served array’s is its OMEtranslation(voxel 0’s centre too) anddeclaredvoxel size, overshapevoxels;drawnis the voxel size Neuroglancer draws it at when that is another (viewer.layers.prediction_voxel_override), which keeps the served offset in voxels, so the array’s corner moves with it.Returns
(indices, lo, hi): per axis, the served index of each annotation voxel the array covers, and the box shrunk to those voxels; None when it covers none along some axis.
- cellmap_flow.portable.label_it.read_box(indices)
(lo, hi): the box of the served array the indices span, the one to read forgather.
- cellmap_flow.portable.label_it.gather(region, indices)
The prediction on the annotation grid: each annotation voxel the served voxel
placementgave it.regionis (channels, z, y, x), the served boxread_boxgives; with the two grids equal, all of it in order.
- cellmap_flow.portable.label_it.probability(prediction, output_class=None, channels=None)
The prediction as a probability, (channels, z, y, x), 0.5 at the model’s decision boundary.
The boundary depends on the output’s activation: 0.5 on [0, 1] output (a sigmoid already applied; the cellmap distance models end in one, and 0.5 is their object boundary), 0 on tanh’s [-1, 1], and 0 on unbounded output, logits or a signed distance alike. Each is turned into a probability, so
channels(a slice: the affinity channels, say) can be averaged and one threshold means the same for every model. A slice running past the model’s channels reads those there are; one starting past them is refused.output_classis the server’s (its network’s last op, or its probe’s: inference/runner.py), or read off the values when it has none, and taken as logits when they are flat (classify_output_range). Read off the values is a guess: logits that lie within [0, 1] read as probabilities. It is kept because the values are real predictions (the ranking’s under the paint, a seed’s in its box), nearer the truth than the probe’s noise, and a model whose graph says its activation never comes to it.
- cellmap_flow.portable.label_it.foreground_mask(prediction, output_class=None, channels=None, threshold=0.5)
Where the model says foreground: its
probability, averaged overchannels, overthreshold.thresholdis in probability whatever the activation: 0.5 is the model’s own boundary. Strictly over: a voxel at it is background.
- cellmap_flow.portable.label_it.affinities(prediction, output_class, offsets)
The mutex watershed’s input: the probability of an affinity model’s offset channels, the first
len(offsets)(asseed_channelstakes them; fewer when the model has fewer).
- cellmap_flow.portable.label_it.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.portable.label_it.connected_components(mask, connectivity=1, min_size=0, per_slice=False)
An id per connected object of
mask(its nonzero voxels): uint64, 0 for background and 1..n with no id skipped, numbered asscipy.ndimage.labelnumbers them.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.portable.label_it.components(prediction, output_class, channels, threshold=0.5, min_size=0, connectivity=1, per_slice=False)
The objects of the components method: the
foreground_maskof the prediction overchannels, an id per connected object (connected_components).
- cellmap_flow.portable.label_it.FIELD_OF_VIEW_MAX_VOXELS = 4194304
- cellmap_flow.portable.label_it.NEUROGLANCER_TOP_ROW_PX = 27
- cellmap_flow.portable.label_it.panel_px(viewer_px, state)
(across, down): the size in screen pixels of the panel the field of view is taken from, in a viewer frameviewer_px(width, height) pixels big showingstate(the viewer’s state, its JSON); None in a layout with no slice panel (“3d”) or one not in _PANEL_SHARE (a row of viewers).The page measures its frame, not the panel: in the server’s mode the frame holds neuroglancer’s own page, of another origin, whose panels the page cannot read. So the panel is the frame less neuroglancer’s top row (NEUROGLANCER_TOP_ROW_PX) and the side panels the state shows (_SIDE_PANELS), and then its share of what is left (_PANEL_SHARE).
- cellmap_flow.portable.label_it.field_of_view_nm(viewer_px, state, pixel_nm, depth_axis, display_dimensions, voxel_size, depth_nm=None) list
The size in nm (z, y, x) of the box the viewer’s panel shows: the box every Label it tool covers, centred where the viewer looks, when the page asks for the field of view.
In the plane, what the panel shows at its zoom: its size in screen pixels (
panel_pxofviewer_px, the page’s viewer frame, andstate, the viewer’s state as JSON) timespixel_nm, the nm one screen pixel spans (viewer.raw.view_of’s, the browser’sviewPixelNm): its width along the data axis it draws across, its height along the one it draws down (ai_annotate.screen_axesofdepth_axisin a viewer showingdisplay_dimensions). Alongdepth_axis, the axis the panel looks along by the AI annotation’s plane rule, it isdepth_nm(the Box field’s depth along it, when it gives one), else one annotation voxel ofvoxel_size(nm, z, y, x): the slice on screen.Raises ValueError, which both modes answer 400: without the frame’s size or the viewer’s zoom, in a layout with no slice panel or side panels that leave it none, and for a view of more than FIELD_OF_VIEW_MAX_VOXELS annotation voxels, saying how far to zoom in.