Skip to content

Add supervised WMH detection module (FSL BIANCA)#116

Merged
davidj-brewster merged 2 commits into
mainfrom
feat/wmh-bianca-supervised-module
Jun 15, 2026
Merged

Add supervised WMH detection module (FSL BIANCA)#116
davidj-brewster merged 2 commits into
mainfrom
feat/wmh-bianca-supervised-module

Conversation

@davidj-brewster

Copy link
Copy Markdown
Contributor

Summary

Adds a self-contained, sourceable module src/modules/wmh_bianca.sh implementing supervised white-matter-hyperintensity (WMH) detection via FSL BIANCA, plus a documented, default-OFF config block in config/default_config.sh.

The literature (Griffanti et al., NeuroImage 2016) shows supervised tools (BIANCA, LST) outperform unsupervised intensity thresholding for small-lesion sensitivity — exactly the regime relevant to brainstem/pons WMH. This is the FSL BIANCA unit of a parallel best-practices upgrade.

This module is not yet wired into the pipeline — it is intentionally kept conflict-free for a follow-up integration unit.

Dependency

  • FSL BIANCA (bianca, make_bianca_mask, and cluster/flirt for post-processing). All detected at runtime; absence is a graceful, non-fatal skip (never crashes the pipeline).

Training-data requirement (important)

BIANCA is a k-NN supervised classifier. It requires either:

  • a training masterfile of subjects that each have a FLAIR (+optionally T1) and a manually-labelled lesion mask (BIANCA_TRAINING_MASTERFILE), or
  • a pre-trained classifier to load (BIANCA_LOAD_CLASSIFIER, produced by a prior --saveclassifierdata run).

With neither configured (the common case on a fresh deployment), the module logs a clear warning explaining the requirement and skips gracefully. This is expected and documented prominently in both the module header and the config comments.

What run_bianca_wmh() does

  1. Detects the BIANCA toolset; non-fatal skip if missing.
  2. Derives a brain mask from the (brain-extracted) FLAIR; auto-locates a FLAIR→MNI .mat for spatial features if not supplied.
  3. Builds a BIANCA masterfile with FLAIR (+T1) intensity features, brain-mask feature, MNI spatial features, and runs bianca with tunable --featuresubset, --spatialweight, --patchsizes, --matfeaturenum, --trainingnums, and --saveclassifierdata/--loadclassifierdata.
  4. When training, appends the query row to the training masterfile with a placeholder at the label column so column layouts align (BIANCA applies one global column layout to all rows), shifts auto-derived feature indices past the label column, and trains only on the real training rows — never the query.
  5. Thresholds the probability map at BIANCA_THRESHOLD (default 0.9) → binary WMH mask; optional BIANCA_MIN_CLUSTER_SIZE post-processing; reports cluster count + total volume.
  6. Brainstem focus: intersects the whole-brain WMH mask with the pipeline's brainstem mask (*brainstem*mask*.nii.gz) and reports brainstem-restricted WMH separately, using safe_fslmaths throughout.

Config (default_config.sh, all default-safe)

WMH_BIANCA_ENABLED=false, BIANCA_TRAINING_MASTERFILE, BIANCA_TRAINING_DIR, BIANCA_LOAD_CLASSIFIER, BIANCA_SAVE_CLASSIFIER, BIANCA_THRESHOLD=0.9, BIANCA_PATCHSIZES, BIANCA_SPATIALWEIGHT, BIANCA_PATCH3D, BIANCA_TRAININGPTS, BIANCA_NONLESPTS, BIANCA_SELECTPTS, BIANCA_MIN_CLUSTER_SIZE, plus column-layout overrides (BIANCA_LABEL_FEATURENUM, BIANCA_BRAINMASK_FEATURENUM, BIANCA_FEATURESUBSET, BIANCA_MATFEATURENUM, BIANCA_TRAININGNUMS).

Integration hook (for the coordinator to wire later)

Add this one line to the analysis stage (after the brainstem mask + standard-space FLAIR/T1 exist), guarded so a non-fatal skip never aborts the stage:

run_bianca_wmh "$flair_std" "${RESULTS_DIR}/wmh_bianca/${subject}" "$t1_std" "$flair_to_mni_mat" || true

(and source src/modules/wmh_bianca.sh alongside the other module sources.)

Verification

  • bash -n and shellcheck --severity=error clean across the whole repo.
  • Unit suites pass: test_environment_unit.sh (100), test_pipeline_control_unit.sh (98), test_import_unit.sh (29); pytest 26 passed.
  • bash src/pipeline.sh --help | grep -q "Usage:" passes.
  • Module-load checks under strict set -e -u -o pipefail: run_bianca_wmh defined, double-sourcing is a no-op, and the absent-tool / no-training / missing-input / empty-training paths all log a graceful skip and return non-zero without crashing the shell. Masterfile column alignment (placeholder insertion, shifted feature indices, trainingnums without trailing comma) verified end-to-end with mock training data.

Real end-to-end BIANCA execution needs training data + FSL + MRI and is out of scope for CI.

🤖 Generated with Claude Code

davidj-brewster and others added 2 commits June 15, 2026 03:48
Add a self-contained, sourceable module src/modules/wmh_bianca.sh implementing
supervised white-matter-hyperintensity detection via FSL BIANCA, plus a
documented, default-OFF config block. The literature (Griffanti et al. 2016)
shows supervised tools (BIANCA, LST) outperform unsupervised intensity
thresholding for small-lesion sensitivity, which matters for brainstem/pons WMH.

Module (entry function run_bianca_wmh):
- Detects bianca + make_bianca_mask; graceful non-fatal skip if absent.
- Builds a query masterfile (FLAIR [+T1], brain mask, FLAIR->MNI .mat for
  spatial features) and runs bianca with tunable featuresubset / spatialweight /
  patchsizes / matfeaturenum / trainingnums / save+load classifier data.
- Supports either training from a manual-mask masterfile or loading a
  pre-trained classifier; graceful skip (with clear guidance) when neither is
  configured (expected on a fresh deployment).
- When training, aligns the appended query row to the training column layout by
  inserting a placeholder at the label column and shifting auto-derived feature
  indices accordingly; trains only on real training rows (never the query).
- Thresholds the probability map at BIANCA_THRESHOLD (default 0.9), optional
  min-cluster-size post-processing, reports cluster count + volume.
- Intersects the WMH mask with the pipeline's brainstem mask and reports
  brainstem-restricted WMH separately, using safe_fslmaths throughout.

Config: WMH_BIANCA_ENABLED=false plus BIANCA_TRAINING_MASTERFILE,
BIANCA_TRAINING_DIR, BIANCA_LOAD/SAVE_CLASSIFIER, BIANCA_THRESHOLD,
BIANCA_PATCHSIZES, BIANCA_SPATIALWEIGHT, and column-layout/feature options.

Hardened against the pipeline's `set -e -u -o pipefail`: guarded grep/find/pipe
substitutions, numeric validation of threshold/min-cluster, space-in-path
detection (BIANCA masterfiles cannot quote), and CWD-independent config sourcing.

Not wired into the pipeline yet (left to a follow-up integration unit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts:
#	config/default_config.sh
@davidj-brewster davidj-brewster merged commit ca4329e into main Jun 15, 2026
8 checks passed
davidj-brewster added a commit that referenced this pull request Jun 15, 2026
Add a self-contained, sourceable module src/modules/wmh_bianca.sh implementing
supervised white-matter-hyperintensity detection via FSL BIANCA, plus a
documented, default-OFF config block. The literature (Griffanti et al. 2016)
shows supervised tools (BIANCA, LST) outperform unsupervised intensity
thresholding for small-lesion sensitivity, which matters for brainstem/pons WMH.

Module (entry function run_bianca_wmh):
- Detects bianca + make_bianca_mask; graceful non-fatal skip if absent.
- Builds a query masterfile (FLAIR [+T1], brain mask, FLAIR->MNI .mat for
  spatial features) and runs bianca with tunable featuresubset / spatialweight /
  patchsizes / matfeaturenum / trainingnums / save+load classifier data.
- Supports either training from a manual-mask masterfile or loading a
  pre-trained classifier; graceful skip (with clear guidance) when neither is
  configured (expected on a fresh deployment).
- When training, aligns the appended query row to the training column layout by
  inserting a placeholder at the label column and shifting auto-derived feature
  indices accordingly; trains only on real training rows (never the query).
- Thresholds the probability map at BIANCA_THRESHOLD (default 0.9), optional
  min-cluster-size post-processing, reports cluster count + volume.
- Intersects the WMH mask with the pipeline's brainstem mask and reports
  brainstem-restricted WMH separately, using safe_fslmaths throughout.

Config: WMH_BIANCA_ENABLED=false plus BIANCA_TRAINING_MASTERFILE,
BIANCA_TRAINING_DIR, BIANCA_LOAD/SAVE_CLASSIFIER, BIANCA_THRESHOLD,
BIANCA_PATCHSIZES, BIANCA_SPATIALWEIGHT, and column-layout/feature options.

Hardened against the pipeline's `set -e -u -o pipefail`: guarded grep/find/pipe
substitutions, numeric validation of threshold/min-cluster, space-in-path
detection (BIANCA masterfiles cannot quote), and CWD-independent config sourcing.

Not wired into the pipeline yet (left to a follow-up integration unit).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@davidj-brewster davidj-brewster deleted the feat/wmh-bianca-supervised-module branch June 15, 2026 18:06
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.

1 participant