Skip to content

About

Segmenting and tracking cells in 2D darkfield time-lapse microscopy movies acquired on a patterned hydrogel background

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Cell Track

This repository contains a reproducible Nextflow pipeline and preserved exploratory notebooks for segmenting and tracking cells in 2D darkfield time-lapse microscopy movies acquired on a patterned hydrogel background.

The central difficulty is that cell signal is mixed with a strong structured background pattern that can drift slightly over time. The pipeline therefore combines illumination correction, pattern alignment, low-rank/sparse decomposition, foundation-model segmentation, and global tracking.

Pipeline summary

The production workflow is orchestrated by main.nf and implemented as shared Python modules under src/cell_track/. The original exploratory workflow remains available in two notebooks:

  • basicpy.ipynb — BaSiCPy illumination correction.
  • main.ipynb — ECC alignment, robust PCA background removal, Cellpose-SAM segmentation, and Ultrack tracking.

Conceptually:

raw time-lapse TIFF
    ↓
BaSiCPy illumination correction
    ↓
ECC alignment of the hydrogel pattern
    ↓
Robust PCA: low-rank pattern + sparse cell signal
    ↓
Cellpose-SAM segmentation
    ↓
Ultrack global tracking
    ↓
tracks_df.csv + tracked_labels.tif

Repository layout

main.nf                       Nextflow entry point
nextflow.config               defaults, resources, and execution profiles
modules/local/                one Nextflow process per pipeline stage
src/cell_track/               shared Python implementation
src/cell_track/cli/           command-line adapters used by Nextflow
envs/                         runner and stage-specific Conda environments
params/example.yml            example pipeline parameters
tests/                        deterministic unit and integration tests
basicpy.ipynb                 preserved BaSiCPy exploration notebook
main.ipynb                    preserved segmentation/tracking notebook

Quick start with Nextflow

Requirements

  • Apple Silicon macOS or x86-64 Linux.
  • Miniforge (recommended) or another compatible Conda installation.
  • At least 16 GB of RAM is recommended for the current resource settings.

The provided runner environment installs the tested Java and Nextflow versions, so they do not need to be installed separately. From the repository root, create it once:

conda env create -f envs/runner.yml
conda activate cell-track-runner

If envs/runner.yml changes later, update the environment with:

conda env update \
  --name cell-track-runner \
  --file envs/runner.yml \
  --prune

Experienced users may instead use an existing compatible installation of Java 17+ and Nextflow 24.10+ together with Conda.

Run one movie

From the repository root:

nextflow run main.nf \
  --input 'images/stacked.tif' \
  --outdir results \
  -profile standard \
  -resume

The standard profile creates the stage-specific environments from envs/ and caches them under an OS/architecture-specific subdirectory of .conda/. This first environment setup can take time; later runs reuse the cache. The runner environment only supplies Java and Nextflow and remains separate from the scientific environments.

To place the stage-environment cache somewhere else, set NXF_CONDA_CACHEDIR before starting Nextflow:

export NXF_CONDA_CACHEDIR="$HOME/.cache/cell-track/conda"

You can also use the example parameter file:

nextflow run main.nf \
  -params-file params/example.yml \
  -profile standard \
  -resume

Run multiple movies

Use a glob as the input:

nextflow run main.nf \
  --input 'data/*.tif' \
  --outdir results \
  -profile standard \
  -resume

Each TIFF basename becomes its sample ID. Input files must therefore have unique basenames after removing .tif or .tiff.

Resume and selective reruns

Nextflow caches each stage. Always use -resume when continuing or repeating a run:

nextflow run main.nf -params-file params/example.yml -profile standard -resume

Changing an Ultrack parameter reruns Ultrack and QC but reuses BaSiCPy, ECC/RPCA, and Cellpose. Changing a Cellpose parameter reruns Cellpose and downstream stages. Do not delete work/ if you want to retain resumability.

Changing only pixel_size_um, frame_interval_min, or qc_frames reruns QC without rerunning preprocessing, segmentation, or tracking, provided the upstream inputs and cached work files are unchanged.

Platform and compute notes

The current environment recipes are intended for Apple Silicon macOS and x86-64 Linux. Intel macOS and ARM64 Linux are not currently tested because the pinned PyTorch and Higra binary support differs on those platforms.

cellpose_device: auto uses Apple MPS when it is available, CUDA on a compatible Linux setup, and otherwise CPU. You may request a device explicitly with --cellpose_device mps, cuda, or cpu.

The default Ultrack allocation is four CPUs and four workers. The Nextflow process also caps the requested worker count at task.cpus, preventing Ultrack from starting more workers than the task was allocated. Use an additional Nextflow config file if a larger workstation should allocate more CPUs.

Results

Results are organized by sample:

results/
├── pipeline_info/
│   ├── parameters.json
│   ├── execution_report.html
│   ├── execution_timeline.html
│   ├── execution_trace.txt
│   └── workflow_dag.html
└── <sample>/
    ├── preprocessing/
    │   ├── basicpy_diagnostics/
    │   └── ecc_rpca_diagnostics/
    ├── segmentation/
    │   ├── cellpose_labels.tif
    │   ├── cell_counts.csv
    │   └── cellpose_metadata.json
    ├── tracking/
    │   ├── tracks_df.csv
    │   ├── tracked_labels.tif
    │   ├── cell_areas.csv
    │   └── tracking_metadata.json
    └── qc/
        ├── cells_per_frame.png
        ├── segmentation_overlays.png
        ├── track_durations.png
        ├── tracking_overlays.png
        ├── track_metrics.csv
        └── summary.json

Large corrected TIFF intermediates are retained in Nextflow's work/ directory for -resume but are only copied to results/ when:

--save_intermediates true

Other optional outputs are controlled by:

--save_aligned_stacks true
--save_normalized_stack true
--save_ultrack_database true

When tracking databases are requested, one database is saved for each contiguous non-empty time segment under tracking/ultrack_databases/.

Per-track movement metrics

QC always writes track_metrics.csv, with one row per track_id (a track segment, not necessarily a cell followed through the entire movie). The table has a stable set of columns:

Columns Meaning
track_id, parent_track_id Track and parent segment IDs; parent IDs are preserved from the input (-1 means no parent, blank means not supplied).
n_positions, first_frame, last_frame Number of observations and zero-based first/last frame indices.
duration_frames Elapsed frame intervals: last_frame - first_frame, not the number of observations.
total_distance_px Sum of Euclidean distances between successive observed centroids, sorted by time within each track.
net_displacement_px Euclidean distance between the first and last observed positions.
mean_speed_px_per_frame Total distance divided by elapsed frame intervals.
max_step_distance_px Largest distance between successive observed positions; includes steps spanning gaps.
has_gaps, sufficient_observations Whether any successive observations are more than one frame apart, and whether at least two positions exist.
duration_min Elapsed duration in minutes; requires frame_interval_min.
total_distance_um, net_displacement_um, max_step_distance_um Corresponding distances in micrometers; require pixel_size_um.
mean_speed_um_per_min Mean speed in micrometers/minute; requires both calibration parameters.

Both calibration parameters default to null; unavailable physical values are blank, never calculated using an assumed scale. pixel_size_um must describe the processed image resolution, including any earlier resizing, and assumes square pixels. frame_interval_min assumes uniform acquisition timing. Supplied values must be finite and greater than zero. These parameters apply to every sample in the run; use separate runs for movies with different calibrations.

Parent and daughter segments are measured separately. Missing frames are bridged by a straight-line step between observations and flagged by has_gaps; movement during the gap is unknown. Tracks containing only one position have blank movement values rather than zero. Empty tracking results produce a header-only CSV. Duplicate track/frame pairs, non-finite coordinates, and invalid frame indices are rejected.

The calculation uses the exported tracking coordinates without smoothing or additional drift correction. Distances are observed 2D centroid-path estimates, not guaranteed true cell travel: inspect identity switches, segmentation changes, residual drift, and observation duration before comparing cells. The existing QC summary.json records calibration and calculation policies under track_metrics and lists the CSV under outputs.

Parameters

Defaults are defined in nextflow.config, and a complete editable example is provided in params/example.yml. Important groups are:

  • basicpy_* — frame registration, darkfield estimation, and autotuning.
  • ecc_* — motion model and ECC convergence.
  • rpca_* — sparse penalty, tolerance, and maximum iterations.
  • cellpose_* — model, compute device, diameter, thresholds, and batch size.
  • ultrack_* — contour smoothing, area filters, linking distance, solver weights, gap, and time limit.
  • qc_frames — selected frames for static overlays; accepts a YAML list or comma-separated CLI values.
  • pixel_size_um — optional micrometers per processed image pixel for QC distance conversion.
  • frame_interval_min — optional minutes between consecutive frames for QC duration and speed conversion.

For example:

nextflow run main.nf \
  --input 'images/stacked.tif' \
  --cellpose_device mps \
  --cellpose_flow_threshold 0.4 \
  --ultrack_max_distance 80 \
  --qc_frames 0,22,43 \
  -profile standard \
  -resume

Testing

The project uses Python's built-in unittest runner. Developers can create the named stage environments directly from the same files used by Nextflow:

conda env create -f envs/basicpy.yml
conda env create -f envs/analysis.yml
conda env create -f envs/cellpose.yml
conda env create -f envs/ultrack.yml

Run the BaSiCPy tests with:

PYTHONPATH=src conda run -n cell-track-basicpy \
  python -m unittest -v tests.test_common tests.test_basicpy tests.test_cli

Run the ECC/RPCA and QC tests with:

PYTHONPATH=src conda run -n cell-track-analysis \
  python -m unittest -v \
  tests.test_common \
  tests.test_ecc_rpca \
  tests.test_qc \
  tests.test_cli

Run the Cellpose adapter tests with:

PYTHONPATH=src conda run -n cell-track-cellpose \
  python -m unittest -v tests.test_common tests.test_segmentation tests.test_cli

Run the Ultrack tests with:

PYTHONPATH=src conda run -n cell-track-ultrack \
  python -m unittest -v tests.test_common tests.test_tracking tests.test_cli

Validate the workflow without running the analysis:

nextflow run main.nf \
  --input 'images/stacked.tif' \
  -profile standard \
  -preview

nextflow run main.nf \
  --input 'images/stacked.tif' \
  -profile standard \
  -stub-run

Method overview

Illumination correction with BaSiCPy

The first preprocessing stage uses BaSiCPy 1 to correct smooth illumination artifacts such as shading, vignetting, lamp drift, and frame-to-frame baseline variation. This is run in a separate basicpy environment because BaSiCPy dependencies are easier to isolate from the main ultrack environment.

BaSiCPy reduces low-frequency illumination effects, but it is not intended to remove the sharp, spatially structured hydrogel pattern. That remaining structured background is handled by the ECC + robust PCA stages.

ECC alignment of the hydrogel pattern

Robust PCA works best when the background is spatially consistent across frames. In this data, the hydrogel pattern can translate or rotate slightly over time, so each BaSiCPy-corrected frame is aligned to a temporal-median template using Enhanced Correlation Coefficient (ECC) image registration 2.

The current notebook uses a Euclidean motion model:

ECC_MOTION = cv2.MOTION_EUCLIDEAN

This allows translation and rotation. The estimated transforms align the movie before robust PCA, and the extracted sparse cell signal is then transformed back to the original movie coordinates.

Robust PCA for pattern/cell separation 3, 4

After alignment, the movie is reshaped into a matrix:

$$ M ∈ R^{pixels × frames} $$

Robust PCA models the movie as:

$$ M = L + S $$

where:

  • L is a low-rank component representing the recurring hydrogel/background pattern.
  • S is a sparse component representing transient foreground signal, primarily cells.

This decomposition is appropriate here because the aligned hydrogel pattern is present in every frame and therefore highly correlated over time, whereas cells occupy a relatively small fraction of pixels and change position/morphology across frames.

The implementation uses an inexact augmented Lagrange multiplier approach. The main tuning parameter is RPCA_LAMBDA_MULTIPLIER, which controls the penalty on the sparse component. Larger values can suppress residual pattern more strongly, but may also remove faint cell signal if set too high.

Cellpose-SAM segmentation

The background-subtracted sparse component is normalized frame-by-frame and segmented with Cellpose-SAM 5 through the Cellpose v4 API. The default model is cpsam_v2, with cpsam as a fallback.

Cellpose-SAM is a good fit for this data because the cells can undergo large morphology changes, from rounded to spread or star-like shapes. The pipeline does not rely on a star-convex or fixed-shape assumption.

The segmentation output is saved as: outputs/cellpose_labels.tif

Large full-stack napari label display is avoided by default because it can freeze the VS Code/Jupyter Qt event loop on macOS.

Ultrack tracking

Cellpose labels are independent in each frame; label IDs are not temporally consistent. Ultrack 6, 7 converts the per-frame labels into foreground and boundary maps, builds candidate segmentation hypotheses and frame-to-frame links, and solves a global integer linear program to recover consistent tracks.

The main tracking outputs are:

outputs/tracks_df.csv
outputs/tracked_labels.tif
  • tracks_df.csv stores track IDs, time points, and centroid coordinates.
  • tracked_labels.tif stores label images with temporally consistent track IDs.

If Gurobi is unavailable, Ultrack falls back to the CBC solver. CBC works, but exact optimization can be slow; exploratory runs may benefit from a nonzero solution gap, a time limit, or temporal windowing.

Generated outputs

Common generated files include:

images/*_basicpy_timelapse.tif
images/*_basicpy_flatfield_only.tif
images/basicpy_diagnostics/
outputs/cellpose_labels.tif
outputs/tracks_df.csv
outputs/tracked_labels.tif
data.db
metadata.toml

These files can be large and are usually treated as generated artifacts rather than source files.

References

  1. Peng, T., Thorn, K., Schroeder, T., Wang, L., Theis, F. J., Marr, C., & Navab, N. (2017). A BaSiC tool for background and shading correction of optical microscopy images. Nature Communications, 8, 14836. https://doi.org/10.1038/ncomms14836

  2. Evangelidis, G. D., & Psarakis, E. Z. (2008). Parametric image alignment using enhanced correlation coefficient maximization. IEEE Transactions on Pattern Analysis and Machine Intelligence, 30(10), 1858–1865. https://doi.org/10.1109/TPAMI.2008.113

  3. Candès, E. J., Li, X., Ma, Y., & Wright, J. (2011). Robust principal component analysis? Journal of the ACM, 58(3), 1–37. https://doi.org/10.1145/1970392.1970395

  4. Lin, Z., Chen, M., & Ma, Y. (2010). The augmented Lagrange multiplier method for exact recovery of corrupted low-rank matrices. arXiv:1009.5055. https://arxiv.org/abs/1009.5055

  5. Pachitariu, M., Rariden, M., & Stringer, C. (2025). Cellpose-SAM: superhuman generalization for cellular segmentation. bioRxiv (Cold Spring Harbor Laboratory). https://doi.org/10.1101/2025.04.28.651001

  6. Bragantini, J., Lange, M., & Royer, L. (2024). Large-Scale multi-hypotheses cell tracking using ultrametric contours maps. In Lecture notes in computer science (pp. 36–54). https://doi.org/10.1007/978-3-031-72986-7_3

  7. Bragantini, J., Theodoro, I., Zhao, X. et al. Ultrack: pushing the limits of cell tracking across biological scales. Nat Methods 22, 2423–2436 (2025). https://doi.org/10.1038/s41592-025-02778-0

About

Segmenting and tracking cells in 2D darkfield time-lapse microscopy movies acquired on a patterned hydrogel background

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages