itasc-cellpose¶
Standalone Cellpose segment + track tool. It works on one or two channels:
One channel: run a local Cellpose-SAM model for native masks, then link them across time with
laptrackinto tracked labels, a self-contained “segment then track” product.Two channels: joint mode (and only joint mode). The first channel is the anchor (segmented + tracked); the second channel’s foreground is flowed onto it, giving one second-channel object per anchor object, sharing its track id.
It does not need the rest of the ITASC pipeline. Every result is added to the napari viewer as a layer, and there is no output directory: you save whichever layers you want via napari’s own Save Selected Layers. There is no nucleus/cell vocabulary; conventionally Channel 1 is the nucleus and Channel 2 the cell, but nothing assumes it.
The integrated ITASC app uses this distribution’s Cellpose runner and divergence maps for its in-app stage; those modules still ship here and are imported directly by the orchestrator. This README covers the standalone napari surface, which is the segment + track tool.
Install¶
pip install itasc-cellpose # package + Qt-free helpers
pip install "itasc-cellpose[cellpose]" # + the Cellpose-SAM model
pip install "itasc-cellpose[cellpose,laptrack]" # + the laptrack tracker
This pulls in itasc-core. Everything installs into the shared itasc.*
namespace (PEP 420), so import itasc.cellpose works with or without the full
orchestrator. The model (cellpose, torch, torchvision) is the [cellpose]
extra and laptrack/pandas are the [laptrack] extra, both imported lazily,
so importing the package does not require them.
Use¶
napari plugin: add the Cellpose Segment + Track widget. Each channel takes its input from the active image layer: select an image in the viewer and click the channel’s
⧉pill to bind it. There is no file loading and no layout to declare. That pill then doubles as a status light: it stays lit while its bound layer is in the viewer and goes dark (releasing the channel) when the layer is removed.Channel 1: the anchor stack (typically the nucleus).
Channel 2: optional second stack (typically the cell).
Every plane is segmented individually, so the input shape needs no
2D/2D+t/3D/ 3D+tselection. Axis identity only matters for tracking, and is inferred: the last two axes areY, X; of the remaining leading axes the shorter isZand the longer is time (the preview status shows the inferredT/Z).Channel 1 carries the single-channel pipeline and surfaces three maps from a single Cellpose pass: the native masks, the sigmoid probability map, and the flow (HSV-coloured by direction). Preview (▷) runs them on the current frame only so you can tune diameter / min-size / gamma and the Prob threshold (a
[0, 1]cutoff read in the prob-map image’s own space,0.5= Cellpose’s default; reversed through the inverse sigmoid to the rawcellprobCellpose thresholds, where lower finds more and larger masks and higher is stricter), the Flow error tolerance (Cellpose’sflow_threshold, relabelled so its direction reads right: it is the per-mask flow-error budget, so higher is more permissive;0.4default,0disables the QC and keeps every mask; this, not Prob threshold, is usually the knob that gates how many masks survive) and Iterations (niterflow steps,0= auto) against what you see; Segment (▶) runs the whole stack and streams each frame into the viewer as it is computed, so the masks/prob/flow layers fill in live instead of appearing only at the end. Track (⊳) links the masks axis-by-axis: it stitches thezaxis by overlap (so an object spanning planes becomes one), then tracks time by motion with laptrack (max-distance / frame-gap, in the Channel 2 & tracking parameters section). Results land as layers tagged[Channel 1](… masks,… prob,… flow,… tracked, and… preview/… prob preview/… flow preview); save whichever you want via napari.Channel 2 is never segmented on its own: it is always run jointly. Once a second channel is set its two actions mirror Channel 1’s: Preview (▷) runs the joint assignment on the current frame so you can tune the Channel-2 params first, and Run (▶) commits it over the whole stack. Either way Channel 1 is segmented + tracked, then each Channel-2 foreground pixel is flowed along Cellpose’s flow field (blended with a pull toward the nearest Channel-1 object) and assigned to one. You get one Channel-2 object per Channel-1 object, sharing its track id:
[Channel 1] trackedand[Channel 2] trackedare paired by construction (Channel 2 is tracked by inheriting Channel 1’s tracks, not a separate tracker). Channel 2 & tracking parameters: Diameter/Min size/Gamma shape its Cellpose flow field; FG threshold (foreground cutoff on the sigmoid), Flow weight (Cellpose flow vs. pull-to-anchor) and Max assign radius (foreground farther than this from any anchor is left unassigned) drive the assignment; Max distance / Max frame gap tune the Channel-1 tracker that both the joint anchor and Channel 1’s own Track action run.The embedded Correction panel (the ultrack/OverlapDB-free cell corrector) edits whatever Labels layer is currently active (typically
[Channel 2] tracked) in place, with the full DB-free toolkit: select (left-click), spawn (middle-click empty space), erase (middle-click a cell orDelete), merge (Ctrl+left), swap / attach to track (Ctrl+right), grow / link the selected track (Ctrl+middle), draw / split (Shift+ left / right-drag), plus fill-holes and stranded-fragment cleanup andCtrl+Zundo. A built-in retracker re-links the tracks from the current frame outward by geometric similarity:Eforward,Qbackward (the Retrack max dist parameter gates a match). It targets 2D+t (single-Z) labels; save the corrected layer via napari.Headless / scripting:
import tifffile from itasc.cellpose import cellpose_runner, native_masks, track_laptrack stack = cellpose_runner.to_tzyx(tifffile.imread("cell.tif"), "2D+t") params = cellpose_runner.CellParams(diameter=0.0, min_size=0, gamma=1.0) masks = native_masks.run_cell_masks_stack(stack, params) # (T, Z, Y, X) tracked = track_laptrack.track_masks(masks, max_distance=15.0) # tracked labels
I/O contract¶
Input: any 2-D..4-D image layer per channel, bound from the active layer via the channel’s
⧉pill (there is no file loading). There is no required0_input/layout and no layout to declare. Every plane is segmented individually; for tracking the shorter leading axis is read asZ, the longer as time. Channel 1 is required; Channel 2 is optional (and turns the run into joint mode). The headless API below still reads.tiffiles directly.Output: napari layers, not files. Masks/tracked/preview are added as
int32Labels layers tagged[Channel 1]/[Channel 2](singleton-Z squeezed to(T, Y, X)for 2D+t data); the user saves them with napari’s Save Selected Layers. The headless API above still returns plain(T, Z, Y, X)arrays.