A collection of QuPath Groovy scripts used for daily image analysis tasks, including measurement extraction, cell detection, annotation export, and spatial analysis.
Scripts for calculating or cleaning object measurements.
add_circularity_and_solidity.groovyadd_imagej_shape_measurements.groovyadd_intensity_measurements.groovyadd_shape_measurements.groovyclean_measurement_list.groovy
Scripts for comparing segmentation results or evaluating model performance.
segmentation_metrics.groovy
Scripts for generating and analyzing cell objects.
create_cells_from_annotation_hierarchy.groovy
Scripts for classifying objects based on morphology or other measurements.
classify_detections_shape_vs_round.groovy
Python toolkit for fine-tuning CellPose-SAM on custom annotated data. Unlike the Groovy scripts, this is used outside QuPath in a terminal or Jupyter notebook.
Copy the training_template/ folder to your experiment project directory, then follow the workflow in the notebook, or see training_template/README.md for a step-by-step CLI-only walkthrough (no notebook required):
- Export annotated pairs from QuPath using
export_annotations/cellpose_training/ - Place exported
_img.tif/_mask.tifpairs indata/(flat or one subfolder per dataset) - Split the data using the Split data cell in the notebook, or run
python split_data.py data/from a terminal - Train via notebook (
train_cpsam.ipynb) or CLI (python train_cpsam.py --model_name <name>) - The trained model is saved to
models/<model_name>inside your copied folder
Requires the cellpose-sam conda environment.
Python helper for training InstanSeg on data exported from QuPath, used outside QuPath like cpsam_training/.
-
pack_instanseg_dataset.py: packs the pairs fromexport_annotations/instanseg_training/into InstanSeg's<name>_dataset.pth.- It reads the channel names and pixel size from each OME-TIFF and relabels the masks.
- It splits Train/Validation/Test by source image. Use
--split-csvfor your own split, e.g. by patient. - Train with
-d_p <export folder> -data <name> -source "[<name>]".
-
training_template/split_data.py— creates reproducible train/test/eval splits; auto-detects flat or multi-dataset layout -
training_template/train_cpsam.ipynb— step-by-step notebook with inline loss plot -
training_template/train_cpsam.py— CLI equivalent; saves loss curve as PNG and CSV
Scripts for cell detection using external models and extensions (e.g., StarDist, Cellpose, ImageJ).
cpsam_detection_live_cell_imaging.groovy— Requires QuPath 0.5.0 + qupath-extension-cellpose 0.9.3. In QuPath 0.7.0, the extension does not correctly use the timepoint from the annotation ROI when exporting image tiles, causing all frames to be detected using frame 0 data. This is a known regression; do not run this script in QuPath 0.7.0 until a fix is confirmed.instanseg_detection.groovy: InstanSeg detection with a custom or downloaded model folder (rdf.yaml + instanseg.pt).- Input channels are given by name or index, and the output channel is selectable (e.g. cells only from a nuclei+cells model).
- It runs in the region annotations of a class, or in the selected annotations, or on the whole image.
- Requires qupath-extension-instanseg 0.1.6 (tested in QuPath 0.7.0).
imagej_threshold_detection_on_annotations.groovy— creates threshold-based annotation objects using an ImageJ threshold method, keeping only regions overlapping with target annotationsstardist_fluorescence_cell_detection.groovystardist_fluorescence_cell_detection_with_preprocessing.groovystardist_fluorescence_cell_detection_zstack.groovystardist_fluorescence_detection_on_annotations.groovy
Scripts for exporting annotations, masks, or training labels.
- cellpose_training/
export_labels_for_cellpose.groovyexport_labels_for_cellpose_all_zslices_and_timepoints.groovyexport_labels_for_cellpose_current_zslice_and_timepoint.groovyexport_labels_for_cellpose_training_regions.groovy— exports one image/mask pair per "Training"-classified region annotation, instance-labeling only the objects inside each region (2D only)
- instanseg_training/
export_labels_for_instanseg_training_regions.groovy: the InstanSeg version of the Cellpose training-regions export.- Writes the image as OME-TIFF, so the channel names and pixel size are kept.
- Channels are chosen by name.
- Labels can come from annotations or detections of one or more classes.
- Large regions can be cut into tiles that lie fully inside them.
- Pack the output with
instanseg_training/pack_instanseg_dataset.py.
- geojson/
export_geojson.groovy
- individualized_annotations/
export_binary_mask_bounding_boxes.groovyexport_binary_mask_multichannel.groovy
- semantic_training/
export_semantic_labels_regions.groovy— multi-class label export per unclassified-annotation region, single planeexport_semantic_labels_zstack.groovy— single-class label export across the whole image (all z-slices/timepoints), with an optional border/boundary label to separate touching instances downstream
Scripts for importing external data (e.g. model predictions) as annotations.
import_predicted_labels_as_annotations.groovy— imports a prediction/label image as annotations for curation; per-class threshold-based ROI extraction via ImageJ, auto-detects XY downsample mismatches, and skips images that already have curated annotations of the target class(es)
Scripts for renaming or reformatting project entries.
rename_project_images.groovy— renames project entries by combining the parent folder name and filename, stripping the file extension and a configurable suffix
Scripts for removing objects that fail a measurement-based or spatial criterion.
filter_detections_by_measurement.groovy— removes detections whose value for a given measurement (e.g. Circularity) falls outside a configurable thresholdremove_annotations_at_image_boundaries.groovy— removes objects whose ROIs touch or are within a set distance of an annotation boundaryremove_detections_at_image_boundaries.groovy— detection-native counterpart to the above; removes detections touching or within a set distance of the image border, without needing an annotation<->detection conversion
Scripts for analyzing skeletonized structures via ImageJ.
analyze_skeleton.groovy
Scripts for computing distances, relationships, or reference-based measurements.
add_centroid_relative_to_parent_rectangle.groovy— adds each detection's centroid (calibrated) using its rectangle parent's top-left corner as the origin; detections with a non-rectangle parent or no parent are skippedadd_reference_centroid_xy.groovydistance_to_nearest_objects.groovyis_in_object.groovyperipheral_overlap_with_class.groovy— for each detection, measures the % of a band along its boundary (configurable inner/outer width, core excluded) covered by objects of a given class, e.g. objects created from a thresholder
General-purpose helper scripts for managing channels, annotations, or calibration.
annotations_to_detections.groovychange_channel_names.groovychange_channel_names_nchannel_variable.groovy— sets channel names for images with either 3 or 4 channelsdetections_to_annotations.groovyexpand_or_erode_annotations.groovy— replaces annotations with a dilated (positive) or eroded (negative) version, keeping the original classification and parent nesting; by default respects the parent annotation's boundary (or image bounds, if none) so erosion doesn't recede from it and dilation doesn't cross itfill_annotations.groovyprepend_folder_to_entry_name.groovy— prepends the parent folder name to each project entry nameremove_annotations.groovyremove_detections.groovyset_pixel_calibration.groovyset_project_classes.groovy— sets the available classification classes for the projectsquare_annotation_from_point.groovy— converts point annotations into square annotations centered on each point, keeping the original classification (size in pixels, unaffected by calibration)
These scripts can be run directly within QuPath's Script Editor:
- Open QuPath →
Automate → Show script editor - Load the desired
.groovyfile. - Adjust the parameters in the configuration block at the top of the script.
- Run (
Ctrl/Cmd + R) orRun for project.
All scripts expose their parameters in a clearly marked block at the top:
// ── Configuration ────────────────────────────────────────────────────────────
def targetClassName = "YOUR_CLASS_NAME" // class name, null (all), or "" (unclassified)
// ─────────────────────────────────────────────────────────────────────────────For scripts that filter by annotation class, targetClassName accepts three forms:
| Value | Behaviour |
|---|---|
"ClassName" |
objects of that class only |
null |
all objects, regardless of class |
"" |
unclassified objects only |
Detection scripts (StarDist, Cellpose) follow their own parameter convention and are not covered by this pattern.
These scripts build upon the QuPath scripting API and community examples.