BOA-MR (Body and Organ Analysis — Magnetic Resonance) is the MRI extension of the open-source BOA CT framework. It runs end-to-end from a T2-weighted MR volume: nnU-Net segmentation (body regions and body parts), VAT/IMAT intensity thresholding, mask refinement, volumetric biomarkers, and an optional verification PDF aligned with BOA CT.
Underlying T2-weighted MR image from the EAY131 collection on The Cancer Imaging Archive (TCIA), licensed under CC BY 4.0.
The pipeline is designed for research and quality-assurance workflows in radiology and metabolic imaging.
Methodological background: Moving Beyond CT Body Composition Analysis — style-transfer–assisted domain adaptation of CT-trained BOA models to T2-weighted MRI (Investigative Radiology, 2025).
Regulatory note: BOA-MR outputs are intended for research and segmentation QA. Generated reports carry a Not for clinical use disclaimer and must not be used as standalone diagnostic documents.
image.nii.gz
→ [1] nnU-Net inference body-regions-mr.nii.gz, body-parts-mr.nii.gz
→ [2] VAT/IMAT thresholding tissues-mr.nii.gz
→ [3] Post-processing mask refinement (body-map-mr.nii.gz, …)
→ [4] Volumetry measurements.json
→ [5] Verification PDF boa-mr-report.pdf (optional)
Steps [1–2] are skipped when you pass --skip-inference and supply pre-computed segmentations.
| Component | Full pipeline (image.nii.gz only) |
Post-processing only (--skip-inference) |
|---|---|---|
| Python | ≥ 3.10 + uv | Same |
| Model weights | Auto-downloaded on first inference run (~900 MB, SHA256-verified) or manual BOA-MR-vX.Y.Z-weights.zip from Releases |
Not needed if segmentations supplied |
| GPU | Recommended (CUDA) for nnU-Net inference | Not required |
| nnU-Net v2 CLI | nnUNetv2_predict on PATH (via nnunetv2 package) |
Not required |
| PDF libraries | Cairo/Pango (or use Docker / --no-report) |
Same |
Muscle volumes in measurements.json are derived from the body-regions nnU-Net mask (label 2), not per-muscle segmentation.
Full pipeline — only the MR volume is required:
case/
└── image.nii.gz # T2-weighted MR reference
BOA-MR runs nnU-Net inference and tissue thresholding automatically, then post-processing and reporting.
Pre-segmented re-runs — provide all four NIfTIs and use --skip-inference:
case/
├── image.nii.gz
├── body-regions-mr.nii.gz
├── body-parts-mr.nii.gz
└── tissues-mr.nii.gz
After a successful run you should see (among others):
case/
├── measurements.json # primary result
├── boa-mr-report.pdf # unless --no-report
├── body-map-mr.nii.gz # post-processed outputs
└── …
Requirements: Python ≥ 3.10, uv
One-time setup
git clone https://github.com/UMEssen/BOA-MR.git
cd BOA-MR
uv syncOn the first full-pipeline run, BOA-MR automatically downloads BOA-MR-v0.1.0-weights.zip from GitHub Releases and verifies its SHA256 checksum.
Manual weight install (optional):
uv run boa-mr-fetch-weights
# or: ./scripts/fetch_weights.shOr download BOA-MR-v0.1.0-weights.zip from Releases and extract body_regions/ and body_parts/ into src/inference/weights/.
Note: GitHub’s auto-generated Source code (zip) does not contain model weights.
PDF on macOS/Linux: WeasyPrint needs system libraries. If PDF generation fails, install:
# Debian / Ubuntu
sudo apt install libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf-2.0-0
# macOS (Homebrew)
brew install cairo pango gdk-pixbuf libffiOr skip the PDF with --no-report (see below).
From a case folder or directly from the MR volume:
uv run boa-mr /path/to/case
uv run boa-mr /path/to/case/image.nii.gz# Separate output directory (inputs stay untouched)
uv run boa-mr /path/to/case --output-dir /path/to/out
# Skip PDF — postprocessing + measurements only (faster, no Chrome/Kaleido needed)
uv run boa-mr /path/to/case --no-report
# Skip nnU-Net when segmentations already exist
uv run boa-mr /path/to/case --skip-inference
# CPU inference (slow; GPU recommended)
uv run boa-mr /path/to/case --device cpu
# Force full rebuild (ignore cache)
uv run boa-mr /path/to/case --force
# Combine flags
uv run boa-mr /path/to/case --output-dir /path/to/out --forceuv run boa-mr-measure /path/to/casePrivacy: The verification PDF does not include patient-identifiable data.
The default image is CPU-based and bundles WeasyPrint/Cairo/Pango for PDF generation. It does not include CUDA or nnU-Net GPU inference.
| Use case | Docker command |
|---|---|
| Pre-segmented case (recommended today) | docker run … /data/case --skip-inference |
Full pipeline from image.nii.gz only |
Run locally with uv + GPU (see Option A) |
One-time build
Place nnU-Net weights under src/inference/weights/ before building if you need full inference in the image (see Releases or ./scripts/fetch_weights.sh). Post-processing-only Docker builds do not require weights.
cd boa-mr
docker build -t boa-mr:latest .Mount your case folder and pass its in-container path as the argument:
docker run --rm \
-v /absolute/path/to/case:/data/case \
boa-mr:latest \
/data/case --skip-inferenceProvide all four NIfTIs in the case folder (see Before you start).
# Separate output volume (pre-segmented case)
docker run --rm \
-v /absolute/path/to/case:/data/case \
-v /absolute/path/to/out:/data/out \
boa-mr:latest \
/data/case --output-dir /data/out --skip-inference
# Skip PDF
docker run --rm \
-v /absolute/path/to/case:/data/case \
boa-mr:latest \
/data/case --skip-inference --no-report
# Force rebuild
docker run --rm \
-v /absolute/path/to/case:/data/case \
boa-mr:latest \
/data/case --skip-inference --forcedocker run --rm boa-mr:latest --helpPaths: Always use absolute paths in
-vmounts. Inside the container, the case path must match the mount target (e.g./data/case).
Use these commands to verify your installation before processing study data.
cd boa-mr
uv run python -m unittest tests.test_pipeline -vRuns label-map checks, CSV export, and report builder smoke tests — no NIfTIs needed.
Point to a directory that contains image.nii.gz and the four segmentation NIfTIs:
export BOA_MR_EXAMPLE_DIR=/path/to/case-with-segmentations
uv run python -m unittest tests.test_pipeline.TestPipelineE2E -vThis runs the full CLI twice (with --skip-inference): once without PDF, once with PDF generation. Expect measurements.json and boa-mr-report.pdf (> 10 KB).
If you have AI segmentations but want a clean output folder:
CASE=/path/to/your/case
TMP=$(mktemp -d)
cp "$CASE/image.nii.gz" "$CASE/tissues-mr.nii.gz" "$TMP/"
cp "$CASE/body-regions-mr.nii.gz" "$CASE/body-parts-mr.nii.gz" "$TMP/"
cd /path/to/boa-mr
uv run boa-mr "$TMP" --skip-inference --force
# Check outputs
ls -lh "$TMP/measurements.json" "$TMP/boa-mr-report.pdf"docker build -t boa-mr:latest .
docker run --rm \
-v /absolute/path/to/case:/data/case \
boa-mr:latest \
/data/case --skip-inference --force| Check | Pass criterion |
|---|---|
| Exit code | 0; terminal prints Pipeline completed successfully |
| Measurements | measurements.json exists, non-empty |
boa-mr-report.pdf exists and is > 10 KB (unless --no-report) |
|
| Cache | Second run without --force skips unchanged stages |
| Mode | Files |
|---|---|
| Full pipeline | image.nii.gz only |
Skip inference (--skip-inference) |
image.nii.gz, body-regions-mr.nii.gz, body-parts-mr.nii.gz, tissues-mr.nii.gz |
| File | Content |
|---|---|
image.nii.gz |
T2-weighted MR reference volume |
body-regions-mr.nii.gz |
nnU-Net body-region segmentation (SAT, muscle, cavities, bone, …) |
body-parts-mr.nii.gz |
nnU-Net anatomical partition map (arms, legs, torso, head) |
tissues-mr.nii.gz |
VAT/IMAT map from intensity thresholding — requires visual QA |
| File | Description |
|---|---|
body-regions-mr.nii.gz |
Post-processed body regions |
body-parts-mr.nii.gz |
Post-processed body parts |
body-map-mr.nii.gz |
Body silhouette mask |
measurements.json |
Primary structured output — schema v2.0 |
boa-mr-report.pdf |
Optional verification document |
| Section | Contents |
|---|---|
body_region_kpis |
Regional volumes and derived indices: whole scan, abdominal cavity, thoracic cavity, torso, arms, legs |
body_region_per_slice_overview |
Slice-resolved muscle, SAT, VAT, IMAT, bone along the inferior–superior axis |
Representative volumetric fields:
| Field | Definition |
|---|---|
muscle_volume_ml |
Skeletal muscle volume (mL) |
sat_volume_ml |
Subcutaneous adipose tissue (mL) |
vat_volume_ml |
Visceral adipose tissue (mL) — threshold-derived; verify mask |
imat_volume_ml |
Intramuscular adipose tissue (mL) — threshold-derived; verify mask |
bone_volume_ml |
Osseous tissue volume (mL) |
total_fat_volume_ml |
SAT + VAT + IMAT (mL) |
Derived ratio indices (e.g. muscle–SAT index, VAT–SAT index, % body fat) are included where applicable at the regional level.
boa-mr-report.pdf implements a BOA CT–isomorphic verification layout (reference module), enabling direct visual and tabular comparison between CT and MR pipeline outputs.
| Property | Detail |
|---|---|
| Rendering | Jinja2 → WeasyPrint; Plotly tissue summary; OpenCV/matplotlib overlays |
| Theme | Dark institutional palette (#0A1628); hospital branding in page header |
| Disclaimer | Not for clinical use on every page |
| VAT/IMAT QA | Sections §1–§3 specifically support mandatory threshold-mask review |
See VAT & IMAT — mandatory verification below. The verification report exists in part to make thresholding errors visible — it does not validate them automatically.
| § | Section | Content |
|---|---|---|
| 1 | Tissue summary | Central coronal/sagittal MR overlay; slice-wise stacked volume bars (% TAT, absolute mL) |
| 2 | Equidistant axial slices | Five uniformly spaced axial levels with body-region and tissue overlays |
| 3 | Tissue heatmaps | Coronal and sagittal maximum-intensity projections per tissue class |
| 4 | Aggregated measurements | Regional statistics (Whole Scan, Abdominal Cavity, Thoracic Cavity, Torso) |
| 5 | Findings | Narrative summary derived from body_region_kpis |
| Parameter | BOA CT | BOA-MR |
|---|---|---|
| Intensity scaling | Hounsfield unit window | Robust percentile normalisation |
| Tissue classes | Bone, muscle, SAT, VAT, IMAT, PAT, EAT | Bone, muscle, SAT, VAT, IMAT |
| TotalSegmentator / BMD | Present | Omitted (MR body-composition scope) |
| Page theme | Light | Dark blue / white |
Body regions — body-regions-mr.nii.gz
| Label | Anatomical class |
|---|---|
| 1 | Subcutaneous adipose tissue (SAT) |
| 2 | Skeletal muscle |
| 3 | Abdominal cavity |
| 4 | Thoracic cavity |
| 5 | Bone |
| 6+ | Ancillary structures (glands, pericardium, mediastinum, brain, …) |
Body parts — body-parts-mr.nii.gz
| Label | Partition |
|---|---|
| 1 | Upper extremities |
| 2 | Lower extremities |
| 3 | Head |
| 4 | Torso |
Tissues — tissues-mr.nii.gz · intensity-thresholded
| Label | Compartment | Derivation |
|---|---|---|
| 1 | Visceral adipose tissue (VAT) | MR signal-intensity threshold |
| 2 | Intramuscular adipose tissue (IMAT) | MR signal-intensity threshold |
Both labels are not semantic class assignments — they reflect voxels exceeding sequence-specific intensity cut-offs. Threshold suitability varies across scanners, protocols, and subjects. Always verify visually before interpreting corresponding volumes in measurements.json.
Prior to volumetry, BOA-MR applies five deterministic refinement steps:
- Body map extraction — largest connected component of the body silhouette
- Extracorporeal suppression — zeroisation of voxels outside the body mask
- Inferior leg propagation — axial propagation of leg labels
- Cavity decontamination — removal of spurious cavity labels within the leg mask
- Per-label connected-component filtering — speckle suppression per region class
Source segmentations are overwritten in place during post-processing. Pass --backup-raw to copy the original AI NIfTIs into raw/ first.
Quick lookup for all CLI flags (local and Docker use the same interface):
boa-mr CASE_DIR [options]| Flag | Function |
|---|---|
--output-dir PATH |
Redirect outputs to alternate directory |
--no-report |
Suppress PDF generation |
--skip-inference |
Skip nnU-Net; require pre-segmented NIfTIs |
--device cuda / cpu |
Compute device for nnU-Net (default: cuda) |
--weights-dir PATH |
Override bundled model weights location |
--force |
Invalidate cache; rebuild all stages |
--write-debug-masks |
Emit developer QC NIfTIs during measurement |
--backup-raw |
Back up original AI segmentations to raw/ before post-processing |
boa-mr-measure /path/to/caseSee How to use it for full local and Docker examples.
| Platform | Modality | Repository | Function |
|---|---|---|---|
| BOA CT | Computed tomography | UMEssen/Body-and-Organ-Analysis | End-to-end CT segmentation, quantification, verification |
| BOA-MR | T2-weighted MRI | this repository | End-to-end MR segmentation, quantification, verification |
Shared conventions: flat-directory I/O, measurements.json schema, multi-section verification PDF.
When using BOA-MR in academic work, please cite:
Haubold J, Pollok OB, Holtkamp M, Salhöfer L, Schmidt CS, Bojahr C, Straus J, Schaarschmidt BM, Borys K, Kohnke J, Wen Y, Opitz M, Umutlu L, Forsting M, Friedrich CM, Nensa F, Hosch R. Moving Beyond CT Body Composition Analysis: Using Style Transfer for Bringing CT-Based Fully-Automated Body Composition Analysis to T2-Weighted MRI Sequences. Investigative Radiology. 2025;60(8):552-559. doi:10.1097/RLI.0000000000001162
PubMed: 39961134
BibTeX
@article{Haubold2025BOAMR,
title = {Moving Beyond {CT} Body Composition Analysis: Using Style Transfer for Bringing {CT}-Based Fully-Automated Body Composition Analysis to {T2}-Weighted {MRI} Sequences},
author = {Haubold, Johannes and Pollok, Olivia Barbara and Holtkamp, Mathias and Salh{\"o}fer, Luca and Schmidt, Cynthia Sabrina and Bojahr, Christian and Straus, Jannis and Schaarschmidt, Benedikt Michael and Borys, Katarzyna and Kohnke, Judith and Wen, Yutong and Opitz, Marcel and Umutlu, Lale and Forsting, Michael and Friedrich, Christoph M and Nensa, Felix and Hosch, Ren{\'e}},
journal = {Investigative Radiology},
year = {2025},
volume = {60},
number = {8},
pages = {552--559},
doi = {10.1097/RLI.0000000000001162},
pmid = {39961134}
}For the parent CT framework:
Haubold J, Baldini G, Parmar V, et al. BOA: A CT-Based Body and Organ Analysis Tool for Radiologists at the Point of Care. Investigative Radiology. 2023. GitHub →
| Symptom | Remediation |
|---|---|
Missing required segmentation |
Verify image.nii.gz (full run) or all four NIfTIs with --skip-inference |
nnUNetv2_predict not found |
Re-run uv sync |
Model weights not found / SHA256 mismatch |
Run uv run boa-mr-fetch-weights or ./scripts/fetch_weights.sh, or download BOA-MR-v0.1.0-weights.zip from Releases; pass --weights-dir or set BOA_MR_WEIGHTS_ROOT |
BOA_MR_SKIP_WEIGHTS_DOWNLOAD |
Set to 1 for offline use and provide weights manually |
| CUDA / GPU out of memory | Use --device cpu (slow), or reduce input size; ensure GPU drivers are installed |
| PDF generation fails locally | Use Docker with --skip-inference, install Cairo/Pango (see Option A), or add --no-report |
| WeasyPrint / Cairo error | Debian/Ubuntu: apt install libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf-2.0-0 |
| Plotly / Kaleido export error | Re-run uv sync (Kaleido ≥ 1.x required); Kaleido needs Chrome locally |
Docker: No such file for case path |
Use absolute paths in -v mounts; path inside container must match mount target |
| Slow re-runs | Outputs are cached; pass --force to rebuild everything |
| Stale outputs after re-segmentation | Pass --force or delete cached outputs (measurements.json, boa-mr-report.pdf) |
boa-mr/
├── src/inference/ # nnU-Net inference (weights ship in release zips)
│ └── weights/ # not in git — see weights/README.md
├── src/postprocessing/ # Segmentation refinement & primary CLI
├── src/boa_mr/
│ ├── metrics_compute.py # Volumetric KPI engine → measurements.json
│ ├── metrics_utils.py # Shared volume/mask helpers for metrics_compute
│ └── report/ # Body composition PDF (BOA CT–aligned)
│ ├── builder.py
│ ├── plots/
│ └── template/
├── scripts/ # Release packaging (maintainers)
├── logos/ # Institutional SVG assets
├── docker/
├── tests/
└── images/ # README figures (hero image, segmentation demo)
BOA_MR_DATA_ROOT overrides the container data root (default: /app).
Model weights are published separately from source code on GitHub Releases:
| Asset | Contents |
|---|---|
BOA-MR-v0.1.0-weights.zip |
nnU-Net checkpoints (body_regions/, body_parts/) |
SHA256SUMS |
Checksums for release assets |
| Source code (zip/tar.gz) | GitHub auto-archive — no weights |
Maintainers — build and publish manually:
./scripts/package_weights_release.sh
# Update src/inference/weights_manifest.json with the printed SHA256
gh release upload v0.1.0 dist/BOA-MR-v0.1.0-weights.zip dist/SHA256SUMS --clobberCritical: Visceral (VAT) and intramuscular (IMAT) adipose tissue are intensity-thresholded in the current pipeline. Unlike SAT, muscle, and bone — which are assigned by semantic segmentation in
body-regions-mr.nii.gz— VAT and IMAT labels intissues-mr.nii.gzdepend on MR signal-intensity cut-offs applied to the source sequence.
| Compartment | Derivation in current pipeline | Intensity dependence |
|---|---|---|
| SAT, muscle, bone | Semantic nnU-Net labels (body-regions-mr.nii.gz) |
Indirect (model training), not per-voxel thresholding |
| VAT, IMAT | Intensity thresholding (tissues-mr.nii.gz) |
Direct — per-examination signal levels |
MRI provides no standardised attenuation scale equivalent to CT Hounsfield units. Signal intensity varies with acquisition parameters (sequence type, TR/TE, fat suppression), field strength, coil configuration, and patient-specific factors. A fixed or learned intensity threshold that performs adequately on one protocol may under- or over-segment VAT/IMAT on another.
BOA-MR quantifies whatever mask is supplied — it does not recalibrate thresholds per study. Reported vat_volume_ml, imat_volume_ml, and all derived indices (VAT–SAT ratio, total fat, % body fat) therefore inherit any thresholding error present in the input tissues-mr.nii.gz.
VAT and IMAT must be visually verified on every case before volumes are interpreted or exported for analysis.
Use the verification PDF (boa-mr-report.pdf) — in particular:
| Report section | QA purpose |
|---|---|
| Equidistant axial slices (§2) | Inspect VAT/IMAT overlays at five axial levels; confirm anatomical plausibility |
| Tissue heatmaps (§3) | Review coronal/sagittal VAT and IMAT projections for spatial coherence |
| Tissue summary (§1) | Check slice-wise VAT/IMAT bars for discontinuities or implausible distributions |
Do not accept VAT/IMAT volumes from measurements.json without this review. When thresholding artefacts are identified, correct the upstream tissues-mr.nii.gz and re-run BOA-MR with --force.
BOA-MR is licensed under the Apache License, Version 2.0.
Developed at the SHIP-AI group, Institute for Artificial Intelligence in Medicine (IKIM), University Hospital Essen

