Cell segmentation and feature extraction on a Slurm HPC cluster (or any GPU machine) using Cellpose.
- Segmentation modes: nuclei-only, cells-only, or dual (both)
- Secondary objects: detect objects inside cells (pathogens, organelles) by thresholding or Cellpose
- Feature extraction: CellProfiler-equivalent morphological and intensity features, plus your own custom features
- Brieflow inside: runs brieflow's phenotype code (vendored unchanged), so masks and features match brieflow's for the same parameters
- File formats: TIFF, Nikon ND2, DeltaVision (.dv)
- Cellpose 3 & 4: Supports both versions with automatic model selection
GoudaCell is a single-shot tool — run it once on your images to produce segmentation masks and features, then use the outputs in your downstream analysis. One of the Cheeseman lab's single-purpose GPU tools (see also: emmentalembed for protein embeddings).
Segmentation masks (TIFF label images):
- Morphological profiling — extract per-cell features and cluster phenotypes (Bray et al. 2016, Nature Protocols)
- Perturbation scoring — compare feature distributions between control and perturbed cells (Celik et al. 2024, eLife)
- Single-cell tracking — link masks across timepoints for live-cell analysis
- Quality control — filter segmented objects by size, shape, or intensity
Extracted features (CSV, ~100+ features per cell):
- Dimensionality reduction — PCA/UMAP on feature space for phenotype discovery
- Classification — train models to distinguish cell states or drug responses
- Correlation analysis — link morphological features to genetic perturbations
Upgrading from 0.3? 0.4.0 runs brieflow's phenotype code, so masks and feature tables change for existing configs. See CHANGELOG.md.
# Clone the repository on your cluster
git clone https://github.com/cheeseman-lab/goudacell.git
cd goudacell
# Create the environment
conda create -n goudacell -c conda-forge python=3.11 uv pip -y
conda activate goudacell
# Install goudacell (choose ONE):
uv pip install -e ".[cellpose3]" # For most cells (rounded shapes)
uv pip install -e ".[cellpose4]" # For complex cell shapes
# Both extras pin torch to the cu126 wheel (CUDA 12.6; needs NVIDIA driver >= 560).
# Check the GPU is usable with: goudacell version (or the notebook's GPU banner)
# Register as a Jupyter kernel
python -m ipykernel install --user --name goudacell --display-name "goudacell"# Start Jupyter on a GPU node (run from goudacell directory)
cd /path/to/goudacell
export SBATCH_PARTITION=<gpu-partition> # your cluster's GPU partition (sinfo -o "%P %G")
sbatch scripts/jupyter_gpu.sh
# Check the output file for the URL
cat out/logs/goudacell_jupyter-*.outThe SLURM scripts request one GPU (--gres=gpu:1) but no partition: set it with
SBATCH_PARTITION as above or sbatch --partition=<gpu-partition> .... They activate the
goudacell conda env; set GOUDACELL_ENV to use another env name.
Open the notebook at notebooks/segmentation.ipynb and:
- Set your image directory and file pattern
- Choose segmentation mode:
"nuclei","cells", or"dual" - Adjust parameters (diameter, thresholds) using the sweep cells
- Run feature extraction (optional)
- Generate batch config when happy with results
# Use the config the notebook wrote to configs/ (run from the repo root)
sbatch scripts/run_segmentation.sh configs/segmentation_config.yamlgoudacell segment keeps going when one file fails and ends with a summary of the failed
files. It exits 1 only when no file succeeded; when some files fail it keeps the outputs of the
others and exits 0, so check the summary at the end of the log.
Generated artifacts are kept out of the source tree:
| Folder | Contents |
|---|---|
data/ |
Your input images |
configs/ |
Configs written by the notebook (<name>.yaml, next to your data folder) |
masks/<name>/ |
Masks from batch runs of the notebook's config <name> (next to your data folder) |
features/<name>/ |
Feature tables from those runs |
out/logs/ |
SLURM .out logs |
Configs carry absolute input/output paths, so a config works no matter where it
lives or where you launch from. Run sbatch from the repo root so out/logs/
exists for the job logs.
| Mode | Output | Use case |
|---|---|---|
nuclei |
*_nuclei_mask.tif |
Nuclear segmentation only |
cells |
*_mask.tif |
Cell segmentation only |
dual |
*_nuclei_mask.tif + *_cell_mask.tif |
Both nuclei and cells |
Extract CellProfiler-equivalent features from segmented images (~100+ features per compartment):
- Intensity: mean, std, min, max, median, quartiles, edge intensities
- Shape: area, perimeter, solidity, eccentricity, Zernike/Hu moments
- Texture: Haralick (13), PFTAS (54)
- Distribution: radial intensity distribution
- Correlation: channel correlation, colocalization metrics
- Neighbors: counts, distances, angles
- Foci: count and area per channel (optional,
feature_extraction.foci_channel) - Custom: your own per-cell measurements (
ui.set_custom_features([...])in the notebook)
With secondary-object detection on (dual mode), each image also gets a
*_second_obj_mask.tif, a per-object *_second_obj_features.csv, and per-cell object
counts/areas merged into the main feature table.
feature_extraction.method: cellprofiler measures each image's masks with a real
CellProfiler pipeline, run headless, instead of the built-in extractor.
CellProfiler 4.2 needs Python 3.9 and numpy<2, and goudacell needs Python ≥3.10 and
numpy≥2, so the two can't share an env. goudacell never imports CellProfiler: it runs the
cellprofiler command from a separate env as a subprocess. You keep working (notebook
kernel, CLI) in the goudacell env, and only need the CellProfiler env to exist.
From the repo root:
bash scripts/setup_cellprofiler_env.shThis creates the conda env goudacell_cp from envs/cellprofiler.yml (CellProfiler
4.2.8.1, Python 3.9 and Java, from conda-forge and bioconda) and checks it. If the env
already exists, the script only checks it. The solve is heavy, so on a shared cluster run
the script on a compute node. It takes a few minutes with the libmamba solver. If you'd
rather run conda yourself, this is the equivalent command:
conda env create --solver=libmamba -f envs/cellprofiler.ymlconda ≥23.10 uses libmamba by default. On an older conda, install the solver into base
with conda install -n base -c conda-forge conda-libmamba-solver. If you can't install
it, drop --solver=libmamba: the classic solver still works but can take a very long time.
conda run -n goudacell_cp cellprofiler --version # prints 4.2.8.1 (after some warnings)Select the cellprofiler method in the notebook, or in the config:
feature_extraction:
enabled: true
method: cellprofilerNothing else is needed. goudacell looks for CellProfiler in this order:
cellprofiler_cmdin the config (the notebook's "CP command" field), if set;- the
GOUDACELL_CELLPROFILERenvironment variable; - a
cellprofilercommand on your PATH; - the
goudacell_cpconda env, found through conda without activating it.
Before running, goudacell checks the command with cellprofiler --version. It must be
CellProfiler 4.2.x; if not, the notebook and the CLI stop with an error that says which
command was found and what to do. To use a CellProfiler installed some other way (another
env name, a module, a container wrapper), point goudacell at its executable:
export GOUDACELL_CELLPROFILER=/path/to/cellprofiler-env/bin/cellprofileror set cellprofiler_cmd: /path/to/cellprofiler-env/bin/cellprofiler in the config.
Without a pipeline_file, goudacell runs its default pipeline
(src/goudacell/data/goudacell_default.cppipe, filled in for your channels and masks).
It runs these modules:
- MeasureObjectIntensity
- MeasureObjectSizeShape (with Zernike)
- MeasureTexture (scale 3)
- MeasureColocalization (within objects, all channel pairs)
- MeasureObjectNeighbors (adjacent nuclei and cells)
- ExportToSpreadsheet
The Texture, Correlation and Neighbors switches turn their modules off. To substitute your
own pipeline, set pipeline_file (the notebook's "CP pipeline" field) to a .cppipe. As a
starting point, goudacell.features_cellprofiler.default_pipeline(["DAPI", "GFP"]) returns
the default's text for your channels; save it as a .cppipe and open it in the CellProfiler
GUI.
For each image, goudacell writes one input folder:
- every channel as
<channel name>.tif(thechannel_names); - the masks as
nuclei_mask.tif,cell_mask.tifandcytoplasm_mask.tif.
It then runs cellprofiler -c -r -p <pipeline> -i <input> -o <output>. A pipeline of your
own must follow the same layout:
- In NamesAndTypes, assign each channel file as a grayscale image, and the masks as
Objects named
Nuclei,CellsandCytoplasm. - Add the Measure modules you want.
- End with ExportToSpreadsheet (CSV, one file per object).
goudacell joins those three object tables on the mask label. The columns are
nucleus_/cell_/cytoplasm_ plus CellProfiler's names (e.g.
cell_Intensity_MeanIntensity_GFP), with intensities scaled to 0–1. CellProfiler gets
cellprofiler_timeout seconds per image (default 3600; null for no limit) before it is
killed and the image fails with an error naming that setting; raise it for large tiles or
heavy pipelines. A pipeline that loads a
mask the mode doesn't produce (e.g. Cells in nuclei mode) finds no image set and fails
with the list of staged files. pytest tests/test_cellprofiler_backend.py runs a minimal
pipeline and the default one with the CellProfiler it finds, and skips those tests when it
finds none.
- "this notebook runs in the
goudacellenv…": the notebook kernel is the CellProfiler env. Switch the kernel togoudacell. - Solver slow or hanging: use libmamba (see step 1); the classic solver can run for a very long time on this recipe.
- SSL/certificate errors while solving or downloading: this is usually a proxy or an
outdated CA bundle. Try
conda update -n base ca-certificates certifi, or point conda at your institution's CA bundle withconda config --set ssl_verify /path/to/ca-bundle.crt. If a separately installedmambafails this way, useconda ... --solver=libmambainstead. - Java not found / "JVM" errors when CellProfiler reads images: the env needs its own
Java. Run
conda install -n goudacell_cp -c conda-forge openjdk. - Wrong CellProfiler version: goudacell supports 4.2.x. Check which command it found
(the error names it), unset or fix
GOUDACELL_CELLPROFILER/cellprofiler_cmd, or rebuild the env withconda env remove -n goudacell_cpand rerun the setup script. - Warnings on
cellprofiler --version(pkg_resources, SciPy/NumPy version) are harmless.
| Version | Install with | Use for |
|---|---|---|
| Cellpose 3 | .[cellpose3] |
Round cells (most common) |
| Cellpose 4 | .[cellpose4] |
Irregular/complex shapes |
Either version also accepts a path to a custom trained model in place of a model name.
- TIFF (
.tif,.tiff) - Nikon ND2 (
.nd2) - DeltaVision (
.dv)
MIT; see LICENSE. src/goudacell/brieflow/ is vendored from
brieflow (MIT) and keeps brieflow's own
LICENSE, which scripts/sync_brieflow.py copies with the modules.