This guide explains how to use ultrack for cell tracking with segmentation ensemble in napari-tmidas.
Ultrack is a versatile and scalable cell tracking method that addresses the challenges of tracking cells across 2D, 3D, and multichannel timelapse recordings. It's especially powerful in complex and crowded tissues where segmentation is often ambiguous.
The segmentation ensemble approach allows ultrack to evaluate multiple candidate segmentations from different methods (e.g., Cellpose, ConvPaint) and select the most consistent tracking solution.
- Segmentation Ensemble: Combine multiple segmentation methods for robust tracking
- Versatile: Supports both TYX (2D+time) and TZYX (3D+time) data
- Optimized Solver: Optional Gurobi integration for improved performance
- Automatic Environment Management: Creates and manages a dedicated conda environment
- Auto-Repair: Automatically detects and installs missing packages in existing environments
- GPU Acceleration: Full support for modern NVIDIA GPUs including Blackwell architecture
The ultrack environment in napari-tmidas includes several custom patches to ensure compatibility with modern dependencies and GPU architectures:
Issue: CuPy (used by ultrack) does not support NVIDIA Blackwell architecture GPUs (compute capability 12.0, sm_120).
Solution: Custom PyTorch implementation of labels_to_contours function
- Replaces ultrack's CuPy-based implementation with PyTorch
- PyTorch 2.5+ nightly builds support Blackwell sm_120
- Produces identical output to the original CuPy version
- Included inline in generated tracking scripts for portability
Location: torch_labels_to_contours.py
Issue 1: scikit-image 0.26.0 and earlier have issues with read-only zarr arrays, causing "buffer source array is read-only" errors.
Issue 2: scikit-image 0.26.0 deprecated the min_size parameter in morphology.remove_small_objects(), replacing it with max_size.
Solution: Automatic installation of scikit-image dev version
- Environment manager checks scikit-image version during setup
- If < 0.26.1: Automatically installs dev version from GitHub with read-only array fix
- If 0.26.1+ stable is available: Auto-upgrades to stable release
- Runtime patch to ultrack's
hierarchy.pyfor deprecated parameter compatibility
Installation command (automatic):
pip install --upgrade git+https://github.com/scikit-image/scikit-image.git@mainFiles patched:
/path/to/ultrack/env/lib/python3.11/site-packages/ultrack/core/segmentation/hierarchy.py
Issue: When CuPy is installed but CUDA is unavailable, ultrack fails to assign xp = np fallback, causing undefined variable errors.
Solution: Runtime patch to ultrack's cuda.py
- Adds missing
xp = npassignment when CUDA is unavailable - Ensures smooth fallback to NumPy operations
Files patched:
/path/to/ultrack/env/lib/python3.11/site-packages/ultrack/utils/cuda.py
These patches enable:
- ✅ Full GPU acceleration on latest NVIDIA hardware (RTX 50 series, etc.)
- ✅ Compatibility with scikit-image 0.26+
- ✅ Robust CPU fallback when GPU is unavailable
- ✅ No manual intervention required - most patches auto-apply during environment creation
Note: For detailed patch information, see ultrack_environment_patches.md.
Before running ultrack tracking, you need to generate segmentation labels using one or more methods:
- Cellpose Segmentation: Generate labels with suffix
_cp_labels.tif - ConvPaint Prediction: Generate labels with suffix
_convpaint_labels.tif - Other segmentation methods: Any method that produces labeled images
The more segmentation methods you use in the ensemble, the more robust the tracking will be.
Your data should be:
- TYX: Time series of 2D images (T=time, Y=height, X=width)
- TZYX: Time series of 3D images (T=time, Z=depth, Y=height, X=width)
-
Segment your data using multiple methods:
- Run "Cellpose-SAM Segmentation" processing function
- Run "ConvPaint Prediction" processing function
- (Optional) Run other segmentation methods
-
Run Ultrack Tracking:
- Select "Track Cells with Ultrack (Segmentation Ensemble)" from processing functions
- Configure parameters (see below)
- Run batch processing
About Default Values: Our parameter defaults are based on ultrack's multi-color ensemble example (not the class defaults). The ensemble example demonstrates real biological tracking and uses values that prevent fragmentation. The class defaults (-0.001 for weights) are often too weak and cause track fragmentation.
Important: These defaults work well for typical biological data with continuous cell movement. However, parameter tuning is dataset-specific - see the troubleshooting section below for guidance on adjusting parameters based on your results.
_cp_labels.tif,_convpaint_labels.tif
Comma-separated list of label file suffixes. The function will look for files with these suffixes to build the ensemble.
Example: If your raw image is sample_001.tif, ultrack will look for:
sample_001_cp_labels.tifsample_001_convpaint_labels.tif
IMPORTANT - File Loading:
- Order matters: The first suffix in the list is the "primary" suffix
- Load ONLY the first suffix: Select files like
*_cp_labels.tifin the file loader - Avoid loading all suffixes: If you load both
*_cp_labels.tifAND*_convpaint_labels.tif, they will be skipped as duplicates - Why: The function automatically finds all ensemble members based on the suffix list
Output naming:
- Input:
sample_001_cp_labels.tif(andsample_001_convpaint_labels.tif) - Output:
sample_001_ultrack.tif← Label suffix is stripped, only one output per sample
(leave empty for default solver)
- Empty: Use default solver (free, slightly slower)
- License Key: Enter your Gurobi academic license key for faster solving
Important: The license key only needs to be entered ONCE during the first-time ultrack environment creation. After the initial setup, leave this field empty on subsequent runs.
To get an academic Gurobi license:
- Register at Gurobi's website with your academic email
- Navigate to named academic license page
- Follow instructions to get your license key
- First time only: Enter the key in the parameter field (e.g.,
abc123-def456-ghijkl) - All subsequent runs: Leave this field empty (Gurobi will use the activated license)
**Recommended: Set to half the size of your smallest cell (disregarding outliers)
- Smaller objects will be filtered out
- Too low: oversegmentation (cells split incorrectly)
- Too high: missing small cells
Max Area (default: 1,000,000)
- Maximum cell area in pixels
- Recommended: Set to 1.25-1.5× your largest cell size
- Larger segments likely represent fused cells and will be split or removed
- Note: Less critical to tune than min_area
- If tracking is fragmented: Try lowering this (e.g., 100-150) to include smaller detections
- Note: Ultrack class default is 100, but the ensemble example uses 200 for better filtering Recommended**: Set to 1.5× the maximum expected cell movement between frames
- How to measure: Open your data in napari, manually track a fast-moving cell across 2 frames, measure displacement
- Too low: track fragmentation (cells can't link properly)
- Too high: incorrect long-distance connections between unrelated cells
- Note: Ultrack class default is 15.0,g
- Higher values = more computational cost but better handling of crowded scenes
Max Distance (default: 40.0, from ensemble example)
- Maximum distance (in pixels) between cells for linking across frames
- CRITICAL FOR FRAGMENTATION: If you see many short, disconnected tracks:
- Increase this value (e.g., 50-80) basAll values must be ≤ 0 (negative = penalty). The solver minimizes the total cost, so more negative weights create stronger penalties.
IMPORTANT: Our defaults come from ultrack's multi-color ensemble example, which prioritizes continuous tracks. However, weights are highly dataset-specific - you may need to adjust them based on your results (see troubleshooting below).
Key principle: Adjust disappear_weight first, then balance division_weight with appear_weight. Keep division_weight equal to or more negative than appear_weight to prevent false divisions.
Appear Weight (default: -0.1, from ensemble example)
- Penalizes new cell appearances (track starts)
- Range: -10.0 to 0.0, step: 0.001
- More negative → fewer new tracks (e.g., -0.5 for very restrictive)
- Less negative → allow more track starts (e.g., -0.01 for data with many appearing cells)
- Too negative: Missing cells that should be tracked
- Too weak: Many false track starts
Disappear Weight (default: -2.0, from ensemble example)
- Penalizes cell disappearances (track ends)
- Range: -10.0 to 0.0, step: 0.1
- More negative → tracks strongly prefer to continue (e.g., -5.0 for maximum continuity)
- Less negative → allow tracks to end more easily (e.g., -0.1 for data with cells leaving field)
- Too negative: Missing cells, incorrect long tracks
- Too weak: Fragmented tracks (many short tracks instead of continuous)
- Tune this first when adjusting weights
Division Weight (default: -0.01, from ensemble example)
- Penalizes cell divisions
- Range: -10.0 to 0.0, step: 0.001
- More negative → fewer divisions detected (e.g., -0.1 if divisions unlikely)
- Less negative → allow more divisions (e.g., -0.001 for rapidly dividing cells)
- Keep equal to or more negative than
appear_weightto prevent false divisions - Too negative: Missing real divisions
- Too weak: Many false divisionsr!), which causes severe fragmentation
Division Weight (default: -0.01, from ensemble example)
- Penalize cell divisions
- Range: -10.0 to 0.0, step: 0.001
- More negative = fewer divisions detected (e.g., -0.1 if divisions unlikely)
- Less negative = allow more divisions (e.g., -0.001 for rapidly dividing cells)
- Note: Ultrack class default is -0.001 (10× weaker)
Enable GPU (default: ON)
- Uses PyTorch for GPU-accelerated processing
- Supports NVIDIA GPUs including Blackwell architecture (sm_120)
- Turn OFF for CPU-only mode (uses NumPy/scipy)
- GPU mode is typically 5-10× faster for large datasets
Note: Window size is automatically set to process the entire timelapse for best tracking quality. For very large datasets, ultrack uses out-of-memory zarr arrays to manage RAM efficiently.
Ultrack tracking produces two output files:
-
_ultrack_tracked.tif: Tracked label image- Each cell has a unique ID that persists across time
- Cell divisions create new IDs
-
_tracks.csv: Track data in CSV format- Columns:
track_id,t,z(if 3D),y,x, and other properties - Can be imported into analysis software
- Columns:
Understand Your Data First
Before tuning parameters, understand your data:
-
Measure cell movement:
- Open raw data in napari
- Track fastest-moving cell across 2 frames
- Measure displacement → set
max_distanceto 1.5× this value
-
Estimate cell sizes:
- Find smallest cell → set
min_areato half its size - Find largest cell → set
max_areato 1.5× its size
- Find smallest cell → set
-
Check segmentation quality:
- Are most cells detected in most frames?
- Are cells properly separated (not fused)?
- Good segmentation → good tracking
Our defaults work well for typical data, but you may need to adjust based on specific issues:
See the Troubleshooting section below for specific guidance on:
- Fragmented tracks (short, disconnected)
- Missing cells
- Too many/few divisions
- Incorrect connections
General tuning strategy:
- Fix hard constraints first (
max_distance,min_area,max_area) - Then adjust weights starting with
disappear_weight - Balance
division_weightwithappear_weight(keep division ≥ appear in negativity) For fast-moving cells (movement > 40 pixels/frame):
- Increase
max_distance: 60-100 (measure actual displacement!) max_neighbors: 8-10
For rapidly dividing cells:
division_weight: -0.001 (less negative = allow more divisions)max_neighbors: 8-10
For sparse data (few cells, clear boundaries):
appear_weight: -0.01 (less negative = allow new tracks)disappear_weight: -0.5 (less negative = allow track ends)max_distance: Can be larger (50-60) since less crowding
For large datasets:
- Extract a small subset (e.g., 10 frames)
- Tune parameters on the subset
- Apply to full dataset once satisfied
Input files:
- embryo_t001.tif (raw image, frame 1)
- embryo_t002.tif (raw image, frame 2)
- ...
- embryo_t100.tif (raw image, frame 100)
Step 1: Run Cellpose Segmentation
Output:
- embryo_t001_cp_labels.tif
- embryo_t002_cp_labels.tif
- ...
Step 2: Run ConvPaint Prediction
Output:
- embryo_t001_convpaint_labels.tif
- embryo_t002_convpaint_labels.tif
- ...
Step 3: Run Ultrack Tracking
Parameters:
- label_suffixes: _cp_labels.tif,_convpaint_labels.tif
- min_area: 150
- max_distance: 30
- (other parameters: use defaults)
Output:
- embryo_t001_ultrack_tracked.tif
- embryo_t001_tracks.csv
Input: 3D timelapse (TZYX)
- cells3d.tif (shape: 50, 30, 512, 512)
Step 1: Segment with multiple methods
- Run Cellpose 3D: cells3d_cp_labels.tif
- Run watershed-based: cells3d_watershed_labels.tif
Step 2: Run Ultrack Tracking (FIRST TIME with Gurobi)
Parameters:
- label_suffixes: _cp_labels.tif,_watershed_labels.tif
- gurobi_license: YOUR_LICENSE_KEY (enter your actual key first time only)
- min_area: 500 (3D cells are larger)
- max_distance: 25
- window_size: 10 (smaller for 3D to save memory)
Step 3: Run Ultrack Tracking (SUBSEQUENT RUNS)
Parameters:
- label_suffixes: _cp_labels.tif,_watershed_labels.tif
- gurobi_license: (leave empty - already activated)
- min_area: 500
- max_distance: 25
- window_size: 10
Output:
- cells3d_ultrack_tracked.tif
- cells3d_tracks.csv
Problem: The tracking script fails with missing module errors (zarr, torch, tifffile, etc.)
Cause: You're using an older ultrack environment that was created before these dependencies were added.
Solution: The system automatically detects and installs missing packages. If you see this error:
-
First run: The system will automatically install missing packages
⚠ Found X missing package(s) in 'ultrack' environment Installing missing packages... Installing zarr... ✓ Installed zarr -
If auto-install fails: Manually install the missing package
conda run -n ultrack pip install zarr>=3.0.0 conda run -n ultrack pip install torch torchvision conda run -n ultrack pip install tifffile -
Nuclear option: Recreate the environment
conda env remove -n ultrack # Then run tracking again - environment will be recreated with all packages
- Check that your label files ha, fragmented tracks
This is the most common issue. Try these fixes in order:
-
Increase
max_distance(MOST IMPORTANT):- Measure how far cells move between frames in napari
- Set to 2-3× the maximum displacement
- Example: If cells move 15-20px between frames, use
max_distance: 40-60
-
Increase penalty weights:
appear_weight: -0.01 to -0.5 (penalize new tracks)disappear_weight: -0.01 to -0.5 (penalize track ends)
-
Check segmentation quality:
- Are cells consistently detected across frames?
- Large gaps in detection → fragmentation
- Use ensemble with 2-3 segmentation methods for robustness
-
Lower
min_areaif cells are small:- Try 50-100 instead of default 100
- Ensures small cells aren't filtered out
- Ensure conda or mamba is installed
- Check your internet connection
- Try manually:
conda create -n ultrack python=3.11
- Increase
disappear_weight(make more negative, e.g., -0.5) - Increase
max_distance - Check if segmentation is consistent across frames
- Decrease
window_size(e.g., 10 or 5) - Process fewer frames at once
- Use a machine with more RAM
- Verify you have an internet connection during activation
- Check that your license key is correct
- Ensure you're on the network specified in your license
If you use ultrack in your research, please cite:
@inproceedings{bragantini2024ucmtracking,
title={Large-scale multi-hypotheses cell tracking using ultrametric contours maps},
author={Bragantini, Jordão and Lange, Merlin and Royer, Loïc},
booktitle={European Conference on Computer Vision},
pages={36--54},
year={2024},
organization={Springer}
}