From 2c47328f4b9775ea4195ab20cfd1550891487ec4 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 07:47:51 +0000 Subject: [PATCH 1/2] Roadmap: quick quality checks from whole-FOV embeddings and masks Adds docs/roadmap.md with two planned post-v0.4.0 checks (owner, 2026-11-02): outlier FOVs from MorphoEmbed whole-FOV embeddings, and a quick mask check from MorphoObjects per-object measurements. Both only flag, stay fast, compare within condition and biological repeat, and keep the algorithms in their owner bricks (no circular dependency on preprocessing). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc --- README.md | 2 +- docs/roadmap.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 docs/roadmap.md diff --git a/README.md b/README.md index 0206de11..1feaa23e 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ ruff format . pytest ``` -Coding conventions are described in [docs/development.md](docs/development.md). +Coding conventions are described in [docs/development.md](docs/development.md). Planned work after v0.4.0 is in [docs/roadmap.md](docs/roadmap.md). ## License diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 00000000..5bdb8fcc --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,97 @@ +# Preprocessing roadmap + +Planned work after v0.4.0. The v0.4.0 work itself (PP-0 to PP-13) is in +[plan.md](plan.md) §10 and in the frozen design (`preprocessing-design-v0.4.md` on +`CellMigrationLab/MorphoFeature`, branch `claude/restart-doc`). + +## Quick quality checks before analysis (owner, 2026-11-02) + +**Goal:** preprocessing stays a *quick* step, but it points the user to fields of view (FOVs) +worth a look before any analysis. Two checks are planned: +- outlier images, from whole-FOV embeddings; +- possibly wrong masks, from quick per-object measurements. + +Both only **flag**. The user looks at the flagged FOVs and decides. Nothing is excluded, +corrected or re-annotated automatically. + +### Q1. Outlier FOVs from whole-FOV embeddings (MorphoEmbed) + +- **What it does:** + - embeds each FOV as a whole, with no patching, through MorphoEmbed; + - flags FOVs whose embedding lies far from the other FOVs of the same condition and + biological repeat. Typical causes are out-of-focus fields, debris, bubbles, empty fields, + or other acquisition settings. +- **What it complements:** the intensity checks, which already flag images whose median or + high percentile lies far from their group. The embedding check catches what intensities + miss, such as texture, focus and content. + +### Q2. Quick mask check (MorphoObjects) + +- **What it measures:** a small, fast set of per-object measurements through MorphoObjects, + such as area, solidity, eccentricity, the share of objects touching the border, the + object count per FOV, and objects per parent (nuclei per cell). They are summarised per FOV + and mask type. +- **What it flags:** FOVs whose masks look unlike the others of the same condition and + biological repeat (out of distribution), for example: + - many tiny or merged objects; + - holes; + - over- or under-segmentation; + - cells without a nucleus or with several nuclei. +- **What the user does:** checks the annotation quality of those FOVs. +- **What it complements:** the `masks` step, which already counts objects and checks + containment between mask types; this extends it with shape statistics and outliers. + +### Rules for both + +- **Fast by design.** A time budget per FOV is set and benchmarked on the real datasets + (fiberfeatures `experiment_001`, MorphoRelate HPMEC) before release: + - Q1: one embedding per FOV from a downscaled whole field; CPU must be usable, and GPU is + optional and explicit; + - Q2: only cheap region properties, with no texture features. +- **Optional.** These are extras; `check` and `run` never need them. +- **Same rules as every brick:** + - no guessed axes or channels; + - no implicit model download, model swap, or CPU/GPU fallback; the model and its weights + are explicit and recorded; + - the channels used are stated; + - every FOV that could not be scored is reported, never treated as normal. +- **Comparisons only within a group.** A FOV is compared with the FOVs of its own condition + and biological repeat, as in the intensity checks. That way a real difference between + conditions is not flagged as an error. A group too small to compare (below the + intensity checks' minimum of 5 images) is reported as "not checked", not as passed. +- **Outlier statistic.** Robust deviations from the group median, reusing the intensity + checks' statistic and thresholds where they fit (no second copy, §9). For embeddings, a + robust distance in the embedding space; which one is decided with a benchmark. +- **Output.** The flags go to the run's report and to a QC table in the output folder, with + the model, its weights' identity, the measurement set, thresholds and versions, so a rerun + can tell whether they are still valid. + +### Where the code lives (open question for the owner) + +MorphoEmbed and MorphoObjects depend on preprocessing, so preprocessing cannot import them; +that would be a circular dependency. Each check's algorithm belongs to its own brick (§9 +ownership). + +The proposal: +- **The bricks compute:** + - MorphoEmbed offers a whole-FOV embedding mode for a preprocessing run; + - MorphoObjects offers the quick per-object set; + - both read through `RunInputs`. +- **Preprocessing owns the outlier statistic** (shared with the intensity checks) and the + QC table's format. +- **Preprocessing only displays the flags:** the notebook and the report show them when the + table exists. +- **The notebook step runs only when the bricks are installed:** the preprocessing notebook + gets an optional step 5 that imports MorphoEmbed and MorphoObjects only when they are + installed, or MorphoFeature offers the same as a "quick QC" preset. + +**To decide:** +- where the step runs: an optional step in the preprocessing notebook, a MorphoFeature + preset, or both; +- the default model for Q1; +- the per-FOV time budget. + +### When + +After v0.4.0 and after the MorphoEmbed and MorphoObjects migrations to `RunInputs` (phase 1 +of the MorphoBricks sequence). In the phase 2 triage, the owner places it in a bucket. From 3fc87f3ccf3ea66859a4f5df9bb6ad876cbeea91 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 07:48:45 +0000 Subject: [PATCH 2/2] Roadmap: quick checks run when their brick is installed, skips reported Owner decision (2026-11-02): the embedding check runs when MorphoEmbed is installed and the mask check when MorphoObjects is installed; otherwise they are skipped. The bricks register their checks through an entry point, so preprocessing never imports them; a skipped or failed check is reported as not run, never as passed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc --- docs/roadmap.md | 66 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index 5bdb8fcc..1a615535 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -66,30 +66,50 @@ corrected or re-annotated automatically. the model, its weights' identity, the measurement set, thresholds and versions, so a rerun can tell whether they are still valid. -### Where the code lives (open question for the owner) - -MorphoEmbed and MorphoObjects depend on preprocessing, so preprocessing cannot import them; -that would be a circular dependency. Each check's algorithm belongs to its own brick (§9 -ownership). - -The proposal: -- **The bricks compute:** - - MorphoEmbed offers a whole-FOV embedding mode for a preprocessing run; - - MorphoObjects offers the quick per-object set; - - both read through `RunInputs`. -- **Preprocessing owns the outlier statistic** (shared with the intensity checks) and the - QC table's format. -- **Preprocessing only displays the flags:** the notebook and the report show them when the - table exists. -- **The notebook step runs only when the bricks are installed:** the preprocessing notebook - gets an optional step 5 that imports MorphoEmbed and MorphoObjects only when they are - installed, or MorphoFeature offers the same as a "quick QC" preset. - -**To decide:** -- where the step runs: an optional step in the preprocessing notebook, a MorphoFeature - preset, or both; +### Where the code lives (owner, 2026-11-02) + +**Decision:** +- each check runs when its brick is installed: Q1 when MorphoEmbed is installed, Q2 when + MorphoObjects is installed; +- a check whose brick is missing is skipped; +- neither brick is ever needed for `check` or `run`. + +**Design (to keep the dependency one-way):** +- **The bricks register their checks.** MorphoEmbed and MorphoObjects depend on preprocessing, + so preprocessing never imports them by name. Each brick declares its check through a Python + entry point, for example group `morphobricks_preprocessing.quick_checks` with names + `embedding_outliers` and `mask_outliers`. Preprocessing finds the installed ones with + `importlib.metadata.entry_points`. +- **No extra of preprocessing installs the bricks,** since that would be a circular + install. Users install the bricks they want. +- **The algorithms stay in the bricks:** + - MorphoEmbed: the whole-FOV embedding; + - MorphoObjects: the quick per-object set. + Both read the images and masks through `RunInputs`. +- **Preprocessing owns the rest:** + - the hook's interface (a versioned protocol: inputs, the result table, the provenance it + must return); + - the outlier statistic, shared with the intensity checks; + - the QC table's format; + - showing the flags in the report, the CLI and the notebook. +- **A skipped check is reported, never silent.** For example: "embedding check not run: + MorphoEmbed is not installed (`pip install …`)". A skipped check is never read as passed, + so the report keeps three outcomes apart: flagged, checked with nothing found, and not + run. +- **A hook that fails, or returns an incompatible protocol version, is reported as not run, + with the reason.** Preprocessing does not fall back to another method. +- **When the checks run:** + - in the notebook, after the run, as an optional step that lists which checks are + available; + - on the command line, through a `quick-checks` command (or `run --quick-checks`), so + the default run stays as fast as today. +- **Model and device for Q1 come from MorphoEmbed's own explicit settings.** Its weights must + already be present; a missing weight file is "not run", never a download. + +**Still to decide:** - the default model for Q1; -- the per-FOV time budget. +- the per-FOV time budget; +- whether MorphoFeature also offers the same checks as a "quick QC" preset. ### When