Skip to content

Add viscy-phenotyping package for image-based feature extraction#410

Open
Soorya19Pradeep wants to merge 2 commits intodynadtwfrom
dyna-computed_features
Open

Add viscy-phenotyping package for image-based feature extraction#410
Soorya19Pradeep wants to merge 2 commits intodynadtwfrom
dyna-computed_features

Conversation

@Soorya19Pradeep
Copy link
Copy Markdown
Contributor

Introduces a new sub-package with CLI commands for computing Spearman correlation features between DynaCLR PCs and computed image features:

  • compute-features: extracts per-cell morphology and texture features
  • write-header: initialises shared CSV before SLURM array jobs
  • list-fovs: enumerates FOVs in an OME-Zarr store
  • merge-features: concatenates per-FOV CSVs

Nuclear label channel is now resolved by name from the tracking zarr (nuclear_label_channel in features.yml) rather than relying on np.squeeze over the label array.

Soorya19Pradeep and others added 2 commits April 23, 2026 09:37
Introduces a new sub-package with CLI commands for computing Spearman
correlation features between DynaCLR PCs and computed image features:
- compute-features: extracts per-cell morphology and texture features
- write-header: initialises shared CSV before SLURM array jobs
- list-fovs: enumerates FOVs in an OME-Zarr store
- merge-features: concatenates per-FOV CSVs

Nuclear label channel is now resolved by name from the tracking zarr
(nuclear_label_channel in features.yml) rather than relying on
np.squeeze over the label array.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds four CellProfiler measurement groups computed per cell patch:
- cp_sizeshape_features: MeasureObjectSizeShape (78 features, mask-only, prefix cp_)
- cp_intensity_features: MeasureObjectIntensity (21 features, per channel)
- cp_texture_features:   MeasureTexture/Haralick (52 features, per channel)
- cp_granularity_features: MeasureGranularity (16 features, per channel)

Texture images are min-max normalised to [0, 1] before passing to
cp_measure to satisfy skimage.img_as_ubyte's float range requirement.

Total features per cell per channel increases from ~84 to ~241.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new viscy-phenotyping workspace package that computes per-cell, per-timepoint image-derived features (custom + CellProfiler-style via cp-measure) and provides a Click CLI to run feature extraction over OME-Zarr datasets / tracking outputs for downstream correlation with DynaCLR PCs.

Changes:

  • Introduces viscy-phenotyping Python package with feature modules and a single-cell feature orchestrator.
  • Adds a viscy-phenotyping CLI with commands to list FOVs, write CSV headers, compute per-FOV/all-FOV features, and merge per-FOV CSV outputs.
  • Adds unit tests and reference documentation (feature catalog + design notes) for the new package.

Reviewed changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
uv.lock Adds the new workspace member and locks new dependencies (cp-measure, centrosome, mahotas, etc.).
packages/viscy-phenotyping/tests/profiler_test.py Tests for individual feature modules plus the compute_cell_features orchestrator.
packages/viscy-phenotyping/tests/features_test.py Tests for extract_nuclear_morphology on 2D/3D label images.
packages/viscy-phenotyping/src/viscy_phenotyping/profiler.py Orchestrates per-cell feature computation across channels and feature groups.
packages/viscy-phenotyping/src/viscy_phenotyping/io.py Implements patch cropping utility used by the CLI pipeline.
packages/viscy-phenotyping/src/viscy_phenotyping/features.py Implements nuclear morphology extraction from label images (2D/3D).
packages/viscy-phenotyping/src/viscy_phenotyping/features_texture.py Implements intensity statistics + GLCM/LBP texture features.
packages/viscy-phenotyping/src/viscy_phenotyping/features_structure.py Implements edge density, connected-components, and skeleton-based structure features.
packages/viscy-phenotyping/src/viscy_phenotyping/features_shape.py Implements nuclear shape/circularity + Fourier shape descriptors.
packages/viscy-phenotyping/src/viscy_phenotyping/features_radial.py Implements radial distribution and concentric ring uniformity features.
packages/viscy-phenotyping/src/viscy_phenotyping/features_gradient.py Implements gradient/sharpness features and nucleus-vs-background contrast.
packages/viscy-phenotyping/src/viscy_phenotyping/features_density.py Implements spot/density + granularity spectrum features.
packages/viscy-phenotyping/src/viscy_phenotyping/features_cp_measure.py Wraps cp-measure feature groups (intensity/size-shape/texture/granularity).
packages/viscy-phenotyping/src/viscy_phenotyping/cli.py Adds Click CLI entrypoints for feature extraction workflows.
packages/viscy-phenotyping/src/viscy_phenotyping/__init__.py Exposes main library entrypoints (compute_cell_features, extract_nuclear_morphology).
packages/viscy-phenotyping/README.md Package README referenced by packaging metadata (currently empty).
packages/viscy-phenotyping/pyproject.toml Defines the new package, dependencies, and CLI entrypoint.
packages/viscy-phenotyping/FEATURES.md Feature reference documentation for outputs and naming conventions.
packages/viscy-phenotyping/DESIGN.md Design notes describing intended workflows (incl. SLURM parallelism pattern).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +66
prev_sum = baseline
for r in range(1, _N_GRANULARITY_SCALES + 1):
opened = opening(img_uint8, disk(r))
curr_sum = float(opened.sum())
out[f"granularity_{r}"] = float((prev_sum - curr_sum) / baseline)
prev_sum = curr_sum
csv_files = list((tracks_path / fov_name).glob("*.csv"))
if not csv_files:
_logger.warning("No tracking CSV found for %s — skipping.", fov_name)
return pd.DataFrame()
Comment on lines +26 to +29
yh, xh = patch_yx[0] // 2, patch_yx[1] // 2
yc = min(max(y, yh), H - yh)
xc = min(max(x, xh), W - xh)
return array[..., yc - yh : yc + yh, xc - xh : xc + xh]
[project]
name = "viscy-phenotyping"
description = "Image-based phenotyping via nuclear morphology for VisCy"
readme = "README.md"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants