Skip to content

Commit 96ba900

Browse files
Brain extraction overhaul: SynthStrip primary + BET hardening + posterior-fossa QC (#111)
* Brain extraction overhaul: SynthStrip primary + BET hardening + posterior-fossa QC Bring brain extraction in line with 2020-2025 best practice, prioritizing brainstem/posterior-fossa preservation. The previous primary path was a template-free Otsu heuristic with a bare `bet -m -f 0.5` fallback and no anatomical prior - the worst choice for a brainstem/pons study (BET clips the cerebellum/brainstem). Changes: - Add SynthStrip (FreeSurfer mri_synthstrip) as the PRIMARY method. Contrast- agnostic, works directly on T1/FLAIR/SWI/DWI with no template mismatch. - New config BRAIN_EXTRACTION_METHOD (synthstrip|ants|bet, default synthstrip) with an ordered, graceful fallback chain (synthstrip -> ants -> bet); missing or failing tools degrade to the next available method, never hard-crash. - Harden the BET fallback: robustfov neck removal for large-FOV sagittal 3D inputs, `-R` robust centre estimation + `-c` centre-of-gravity when available, and modality-specific `-f` (BET_F_T1=0.3, BET_F_FLAIR=0.2). - Add a non-fatal posterior-fossa QC gate that warns when the brain mask looks like it clipped the cerebellum/brainstem (inferior-slab voxel fraction vs BRAIN_QC_INFERIOR_FRACTION). - Soften the ANTs Otsu-path morphological open from radius 4 to a config-driven BRAIN_MASK_MORPH_RADIUS (default 1) to avoid severing the brainstem->cord taper / rounding off the pons. The perform_brain_extraction() signature and output naming (<prefix>BrainExtractionBrain.nii.gz / <prefix>BrainExtractionMask.nii.gz) are unchanged, so preprocess.sh and pipeline.sh stage 3 are unaffected. Follow-ups (out of scope): mask propagation (extract once on T1, warp mask to FLAIR); the analysis.sh antsBrainExtraction path uses an MNI152-T1 binary mask on FLAIR (a misconfiguration worth fixing separately). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Generalize robustfov to a shared pre-extraction FOV-normalization step robustfov neck/FOV removal previously only ran inside the BET fallback, so with SynthStrip as the primary method it almost never fired - losing its benefit exactly on the large-FOV sagittal 3D inputs (T1_MPRAGE_SAG / T2_SPACE_FLAIR_Sag) it was meant to help. Make robustfov a shared, optional pre-extraction step that benefits ALL methods (synthstrip/ants/bet) without changing the native geometry of the final outputs: - Add should_run_fov_crop() (gated by BRAIN_EXTRACTION_ROBUSTFOV plus an optional BRAIN_EXTRACTION_ROBUSTFOV_MIN_Z_MM superior-inferior FOV heuristic), compute_fov_cropped_for_extraction() (runs robustfov, emits cropped image + ROI->full affine), and map_mask_to_original_grid() (maps the cropped-space mask back onto the original grid and rebuilds the brain in native space). - perform_brain_extraction() now optionally crops, runs the chosen method on the cropped image, then maps the mask back to the ORIGINAL native space and geometry. If mapping fails it re-extracts on the original image. Signature and output naming are unchanged. - The mask is resampled with the ROI->full affine DIRECTLY (robustfov's -m is "roi to full fov"); empirically this preserves the mask voxel count exactly while the inverse shifts it ~1 voxel and drops voxels. - Factor the synthstrip/ants/bet dispatch into a single run_extraction_chain() used by both the cropped and original-image paths (no duplicated switch). - Add verify_mask_alignment() (dim + non-empty sanity check) after mapping. - Remove the now-redundant inline robustfov from brain_extraction_bet() so we never double-crop; BET keeps its -R + centre-of-gravity behavior. - New config vars documented in config/default_config.sh near the other extraction settings. robustfov-absent path degrades gracefully (non-fatal skip, extract on original). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 675c26a commit 96ba900

3 files changed

Lines changed: 627 additions & 98 deletions

File tree

config/default_config.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,57 @@ export EXTRACTION_TEMPLATE="$EXTRACTION_TEMPLATE_1MM"
351351
export PROBABILITY_MASK="$PROBABILITY_MASK_1MM"
352352
export REGISTRATION_MASK="$REGISTRATION_MASK_1MM"
353353

354+
# ------------------------------------------------------------------------------
355+
# Brain extraction method & parameters
356+
# ------------------------------------------------------------------------------
357+
# Preferred brain extraction method. The pipeline tries this method first and
358+
# falls back gracefully to the next available method if the tool is missing or
359+
# fails. Fallback order is always: synthstrip -> ants -> bet.
360+
# synthstrip - FreeSurfer mri_synthstrip (contrast-agnostic deep-learning
361+
# skull-strip; current best practice for T1/FLAIR/SWI/DWI and the
362+
# safest choice for brainstem/cerebellum preservation)
363+
# ants - template-free N4 -> Otsu -> largest-component -> morphology path
364+
# bet - FSL BET with robustfov neck removal + modality-specific -f
365+
export BRAIN_EXTRACTION_METHOD="synthstrip"
366+
367+
# Radius (in voxels) for the morphological open (dilate then erode) in the ANTs
368+
# Otsu fallback path. The legacy value of 4 is aggressive at 1mm and can sever
369+
# the brainstem->cord taper or round off the pons; 1-2 is gentler and preserves
370+
# the posterior fossa.
371+
export BRAIN_MASK_MORPH_RADIUS=1
372+
373+
# Modality-specific BET fractional intensity thresholds (-f). Lower values keep
374+
# more brain (important for FLAIR/T2 where BET tends to over-strip). T1 uses a
375+
# slightly higher value than the bare 0.5 default which clipped the cerebellum.
376+
export BET_F_T1=0.3
377+
export BET_F_FLAIR=0.2
378+
379+
# Posterior-fossa QC gate: minimum fraction of brain-mask voxels expected to lie
380+
# in the inferior portion of the volume (cerebellum/brainstem region). If the
381+
# observed fraction falls below this, the mask is flagged as possibly clipped.
382+
# Even SynthStrip drops the cerebellum in ~1/3 of T2 cases, so this is a warning
383+
# (non-fatal) sanity check, not a hard failure.
384+
export BRAIN_QC_INFERIOR_FRACTION=0.06
385+
386+
# Shared robustfov FOV-normalization (neck/large-FOV removal) applied as a
387+
# pre-extraction step for ALL methods (synthstrip/ants/bet), not just the BET
388+
# fallback. On large-FOV sagittal 3D inputs (T1_MPRAGE_SAG, T2_SPACE_FLAIR_Sag)
389+
# the neck and shoulders drag skull-strip centres of mass too low; cropping the
390+
# FOV first improves extraction and downstream registration. The brain mask is
391+
# extracted on the cropped image, then mapped BACK to the original full grid via
392+
# the inverse of robustfov's ROI->full affine, so the final brain/mask outputs
393+
# stay in the ORIGINAL native space and geometry (nothing downstream shifts).
394+
# Requires FSL robustfov; if unavailable, the pipeline logs a non-fatal skip and
395+
# extracts on the original image (legacy behaviour).
396+
export BRAIN_EXTRACTION_ROBUSTFOV=true
397+
398+
# Heuristic gate for the robustfov pre-step. When >0, FOV cropping only triggers
399+
# if the superior-inferior (Z) extent in mm (dim3 * pixdim3) exceeds this value,
400+
# which targets the large-FOV sagittal slabs while leaving already-tight axial
401+
# acquisitions untouched. Set to 0 to apply the crop unconditionally whenever
402+
# BRAIN_EXTRACTION_ROBUSTFOV is enabled and robustfov is available.
403+
export BRAIN_EXTRACTION_ROBUSTFOV_MIN_Z_MM=180
404+
354405
# Supported modalities for registration to T1
355406
export SUPPORTED_MODALITIES=("FLAIR" "SWI" "DWI" "TLE" "COR")
356407

src/modules/brain_extraction.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,9 @@ run_parallel_brain_extraction() {
844844
export -f validate_nifti validate_file
845845
export -f get_output_path get_module_dir create_module_dir
846846
export -f log_diagnostic execute_with_logging perform_brain_extraction execute_ants_command
847-
847+
export -f synthstrip_available brain_extraction_synthstrip brain_extraction_ants
848+
export -f brain_extraction_bet qc_posterior_fossa_coverage safe_fslmaths
849+
848850
# Run in parallel using the common function
849851
run_parallel "extract_brain" "$pattern" "$input_dir" "$jobs" "$max_depth"
850852
local status=$?

0 commit comments

Comments
 (0)