Brain-age in ultra-low-field MRI: How well does it work?
The 2 matches
- [1] § Materials and Methods › Brain-age models ↔ src/synthba/synthba.py, lines 78–136 · score 0.58 · skull stripped, age predictions, SynthBA, pipeline, brain age, template
- [2] § Materials and Methods › Brain-age models › SynthBA ↔ src/synthba/skull_stripping.py, lines 18–140 · score 0.57 · SynthStrip, skull stripping, affine, SynthBA, brain, scan
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 225 lines · 8.9 KB · no license · 1 match
- import os
- import hashlib
- import re
- from typing import List, Optional, Union, Callable
- import pandas as pd
- import nibabel as nib
- import torch
- from torch.utils.data import DataLoader
- from monai import transforms
- from monai.data import Dataset
- from monai.networks.nets.densenet import DenseNet201
- from nibabel.nifti1 import Nifti1Image
- from nibabel.nifti2 import Nifti2Image
- from huggingface_hub import hf_hub_download
- from .registration import align
- from .skull_stripping import SkullStripping
- def _split_nii_name(filename: str) -> tuple:
- if filename.endswith('.nii.gz'):
- return filename[:-7], '.nii.gz'
- return os.path.splitext(filename)
- def _sanitize_path_component(component: str) -> str:
- component = re.sub(r'[^A-Za-z0-9._-]+', '_', component).strip('._-')
- return component or 'path'
- def _preprocessed_output_paths(input_list: List[str], preprocess_outdir: str) -> List[str]:
- """
- Build readable, unique output paths from the shortest distinguishing input suffix.
- For example, subject_a/visit_a/t1.nii.gz and subject_b/visit_a/t1.nii.gz
- become subject_a-visit_a-t1.nii.gz and subject_b-visit_a-t1.nii.gz.
- """
- if not input_list:
- return []
- path_parts = []
- for input_path in input_list:
- parts = [p for p in os.path.normpath(input_path).split(os.sep) if p]
- path_parts.append(parts or [os.path.basename(input_path)])
- max_depth = max(len(parts) for parts in path_parts)
- output_names = None
- for depth in range(1, max_depth + 1):
- candidate_names = []
- for parts in path_parts:
- suffix_parts = parts[-depth:]
- stem, suffix = _split_nii_name(suffix_parts[-1])
- name_parts = suffix_parts[:-1] + [stem]
- candidate_name = '-'.join(_sanitize_path_component(p) for p in name_parts) + suffix
- candidate_names.append(candidate_name)
- comparable_names = [name.lower() for name in candidate_names]
- if len(comparable_names) == len(set(comparable_names)):
- output_names = candidate_names
- break
- if output_names is None:
- output_names = []
- for index, (input_path, parts) in enumerate(zip(input_list, path_parts)):
- stem, suffix = _split_nii_name(parts[-1])
- digest = hashlib.sha1(f'{index}:{os.path.abspath(input_path)}'.encode()).hexdigest()[:8]
- output_names.append(f'{_sanitize_path_component(stem)}-{digest}{suffix}')
- return [os.path.join(preprocess_outdir, name) for name in output_names]
- class SynthBA:
- """
- Predict the brain age from MRI scans of any contrast and resolution using the SynthBA model.
- """
- def __init__(
- self,
- device: str,
- checkpoint: Optional[str] = None,
- model_type: str = 'g',
- skull_stripping: Optional[SkullStripping] = None,
- align_fn: Optional[Callable] = None,
- ):
- """
- Initialize the SynthBA brain age prediction model.
- Args:
- device (str): The device to run the model on (e.g., 'cuda' or 'cpu').
- checkpoint (Optional[str]): Path to a model checkpoint. If None, downloads from Hugging Face.
- model_type (str): Model variant to use ('u' or 'g').
- skull_stripping (Optional[SkullStripping]): Custom skull stripping method, if provided.
- align_fn (Optional[Callable]): Custom image alignment function, if provided.
- """
- if checkpoint is None and model_type not in ['u', 'g']:
- raise Exception('SynthBA `model_type` should be either `u` or `g`')
- self.device = device
- self.hf_fname = f'synthba-{model_type}.pth'
- if checkpoint is None:
- checkpoint = hf_hub_download(repo_id='lemuelpuglisi/synthba', filename=self.hf_fname)
- checkpoint = torch.load(checkpoint, map_location=device)
- self.model = DenseNet201(3, 1, 1, dropout_prob=0)
- self.model.load_state_dict(checkpoint)
- self.model = self.model.to(device).eval()
- # Preprocessing components
- self.skull_stripping = SkullStripping(self.device) if skull_stripping is None else skull_stripping
- self.align_fn = align if align_fn is None else align_fn
- # Download alignment templates for different MR weightings
- self.templates = {
- 't1': nib.load(hf_hub_download(repo_id='lemuelpuglisi/synthba', filename='MNI152_T1_1mm_Brain.nii.gz')),
- 't2': nib.load(hf_hub_download(repo_id='lemuelpuglisi/synthba', filename='MNI152_T2_1mm_Brain.nii.gz'))
- }
- # Image transformation pipelines
- self.transforms_fn_direct = transforms.Compose([
- transforms.EnsureChannelFirst(channel_dim='no_channel'),
- transforms.Spacing(pixdim=1.4),
- transforms.ResizeWithPadOrCrop(spatial_size=(130, 130, 130), mode='minimum'),
- transforms.ScaleIntensity(minv=0, maxv=1),
- ])
- self.transforms_fn_multiple = transforms.Compose([
- transforms.CopyItemsD(keys={'scan_path'}, names=['image']),
- transforms.LoadImageD(keys='image'),
- transforms.EnsureChannelFirstD(keys='image', channel_dim='no_channel'),
- transforms.SpacingD(keys='image', pixdim=1.4),
- transforms.ResizeWithPadOrCropD(keys='image', spatial_size=(130, 130, 130), mode='minimum'),
- transforms.ScaleIntensityD(keys='image', minv=0, maxv=1),
- transforms.Lambda(lambda d: d['image']),
- ])
- @torch.inference_mode()
- def run(
- self,
- scan: Union[Nifti1Image, Nifti2Image],
- preprocess: bool = True,
- mr_weighting: str = 't1'
- ) -> float:
- """
- Predict brain age for a single MRI scan.
- Args:
- scan (Nifti1Image | Nifti2Image): Input MRI scan.
- preprocess (bool): Whether to apply skull stripping and alignment.
- mr_weighting (str): MRI contrast type ('t1' or 't2') for template alignment.
- Returns:
- float: Predicted brain age in years.
- """
- if preprocess:
- scan = self._preprocess(scan, mr_weighting)
- scan_tensor = self.transforms_fn_direct(scan.get_fdata())
- scan_tensor = scan_tensor.unsqueeze(0).to(self.device).float()
- return self.model(scan_tensor).view(-1).item() * 100.
- @torch.inference_mode()
- def run_multiple(
- self,
- input_list: List[str],
- batch_size: int = 1,
- preprocess: bool = True,
- preprocess_outdir: Optional[str] = None,
- mr_weighting: str = 't1',
- ) -> pd.DataFrame:
- """
- Predict brain age for multiple MRI scans in batch.
- Args:
- input_list (List[str]): List of paths to input MRI scans.
- batch_size (int): Number of images processed per batch.
- preprocess (bool): Whether to apply skull stripping and alignment.
- preprocess_outdir (Optional[str]): Directory to save preprocessed images.
- mr_weighting (str): MRI contrast type ('t1' or 't2') for template alignment.
- Returns:
- pd.DataFrame: DataFrame with columns ['path', 'pred'] containing predicted brain ages.
- """
- if preprocess and preprocess_outdir is None:
- raise Exception('Please specify where to store the preprocessing output with preprocess_outdir')
- if preprocess:
- prep_input_list = []
- output_paths = _preprocessed_output_paths(input_list, preprocess_outdir)
- for inp_path, out_path in zip(input_list, output_paths):
- self._preprocess(nib.load(inp_path), mr_weighting).to_filename(out_path)
- prep_input_list.append(out_path)
- input_list = prep_input_list
- data = [{'scan_path': p} for p in input_list]
- dataset = Dataset(data=data, transform=self.transforms_fn_multiple)
- loader = DataLoader(dataset=dataset, batch_size=batch_size)
- brain_age_list = []
- for _, images in enumerate(loader):
- brain_ages = self.model(images.to(self.device))
- brain_age_list += list(brain_ages.view(-1).cpu().numpy() * 100.)
- data = [{'path': p, 'pred': y} for p, y in zip(input_list, brain_age_list)]
- return pd.DataFrame(data)
- def _preprocess(self, scan: Union[Nifti1Image, Nifti2Image], mr_weighting: str):
- """
- Apply skull stripping and spatial alignment to an MRI scan.
- Args:
- scan (Nifti1Image | Nifti2Image): Input MRI scan.
- mr_weighting (str): MRI contrast type ('t1' or 't2') for selecting the reference template.
- Returns:
- Nifti1Image | Nifti2Image: Preprocessed and aligned MRI scan.
- """
- if mr_weighting not in self.templates.keys():
- raise Exception('Unknown weighting. Please select between: ' + ', '.join(self.templates.keys()))
- scan = self.skull_stripping.run(scan)[0]
- scan = self.align_fn(scan, self.templates[mr_weighting])
- return scan
synthba.py at commit cc6ca27, no license · at the source
Overview
- UCL Hawkes Institute, UCL, London, United Kingdom
- Department of Neuroimaging, Institute of Psychiatry, Psychology and Neuroscience, King’s College London, London, United Kingdom
- University of Catania, Catania, Italy
- School of Biomedical Engineering & Imaging Sciences, King’s College London, London, United Kingdom
- Department of Neuroradiology, Ruskin Wing, King’s College Hospital NHS Foundation Trust, London, United Kingdom
- Martinos Center for Biomedical Imaging, Massachusetts General Hospital and Harvard Medical School, Charlestown, MA, United States
- Computer Science and Artificial Intelligence Laboratory, Massachusetts Institute of Technology, Cambridge, MA, United States
- Dementia Research Centre, UCL, London, United Kingdom
Abstract
Brain-age estimates the brain’s biological age from neuroimaging data and has been proposed as a biomarker of brain health and disease risk. While brain-age estimation commonly uses high-field (HF) magnetic resonance imaging (MRI) (>1.5 T), this is costly and inaccessible, limiting its applicability. Emerging ultra-low-field (ULF) MRI (<0.1 T) is cheaper and more accessible, but its lower resolution may limit the reliability of biomarkers such as brain-age. We assessed different brain-age pipelines in 23 adults scanned on one HF system (GE Signa Premier at 3 T) and two identical ULF systems (Hyperfine Swoop at 64 mT) located at two different sites, hereafter referred to as ULF1 and ULF2. We used 14 distinct acquisitions defined by T1- or T2-weighting, resolution, and preprocessing: raw anisotropic orientations (axial, coronal, sagittal), isotropic scans, and super-resolution derivatives from multi-resolution registration (MRR) and SynthSR. These inputs (a total of n = 573 scans) were analyzed with five brain-age software packages (BrainageR, SynthBA, MIDI, DeepBrainNet, PyBrainAge). Performance evaluation entailed validity (brain-age vs. actual age), correspondence (ULF brain-age vs. HF brain-age) and test-retest reliability (ULF1 brain-age vs. ULF2 brain-age). Overall, results were mixed across pipelines, although several ULF pipelines performed comparably to HF. The four best-performing combinations were SynthBA on T2 scans without SynthSR, MIDI on T2 scans without SynthSR, PyBrainAge on T1 scans with SynthSR and using FreeSurfer recon-all-clinical, and BrainageR on T1 scans with SynthSR. These showed moderate-to-strong validity (r=
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 2 matches between paragraphs and lines of code.
james-cole/brainageR
f9444605527337b07b9a8eb2f6c8c81261aa8b61, 14 September 2026Availability: 1 check, the latest on 26 September 2026: the link answers
- 26 September 2026: the link answers
9 files
- collate_brain_ages.sh, Shell, 23 lines
- generate_submit_scripts.
sh , Shell, 13 lines - predict_new_data_gm_wm_c
sf.R , R, 74 lines - sge_submit_template.sh, Shell, 18 lines
- slurm_submit_template.sh
, Shell, 14 lines - spm_preprocess_brainageR
.m , MATLAB, 120 lines - submit_template.sh, Shell, 14 lines
- LICENSE, License, 165 lines
- README.md, Text, 153 lines
Zenodo 3476365
Availability: 1 check, the latest on 26 September 2026: the link answers (HTTP 200)
- 26 September 2026: the link answers (HTTP 200)
LemuelPuglisi/SynthBA
cc6ca2737dba481cfbe5e7453971cba62aafdc09, 1 September 2026Availability: 1 check, the latest on 26 September 2026: the link answers
- 26 September 2026: the link answers
6 files
- src/
synthba.py , Python, 197 lines - src/
synthba/ , Python, 243 linescli.py - src/
synthba/ , Python, 70 linesregistration.py - src/
synthba/ , Python, 276 lines, 1 matchskull_stripping.py - src/
synthba/ , Python, 225 lines, 1 matchsynthba.py - readme.md, Text, 247 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 3 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 12 scripts, each with its path and the digest of its content;
- 2 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- openneuro:ds006557, at OpenNeuro; found in “Data and Code Availability”
Data and Code Availability
Data are publicly available https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, pages, dates, 9 authors, 6 keywords, 13 MeSH terms, 2 funders, 48 references.
Cite
This paper
Biondo, F., Bennallick, C., Martin, S. A., Puglisi, L., Booth, T. C., Wood, D. A., Iglesias, J. E., Váša, F., & Cole, J. H. (2026). Brain-age in ultra-low-field MRI: How well does it work? Imaging neuroscience (Cambridge, Mass.), 4, IMAG.a.1352. https://
BibTeX
@article{biondo2026brain
author = {Biondo, Francesca and Bennallick, Carly and Martin, Sophie A and Puglisi, Lemuel and Booth, Thomas C and Wood, David A and Iglesias, Juan Eugenio and Váša, František and Cole, James H},
title = {{Brain-age in ultra-low-field MRI: How well does it work?
journal = {Imaging neuroscience (Cambridge, Mass.)},
year = {2026},
month = sep,
volume = {4},
pages = {IMAG.a.1352},
publisher = {MIT Press},
issn = {2837-6056},
doi = {10.1162/
url = {https://
pmid = {42761967},
pmcid = {PMC13588316}
}
RIS
TY - JOUR
AU - Biondo, Francesca
AU - Bennallick, Carly
AU - Martin, Sophie A
AU - Puglisi, Lemuel
AU - Booth, Thomas C
AU - Wood, David A
AU - Iglesias, Juan Eugenio
AU - Váša, František
AU - Cole, James H
TI - Brain-age in ultra-low-field MRI: How well does it work?
T2 - Imaging neuroscience (Cambridge, Mass.)
J2 - Imaging Neurosci (Camb)
PY - 2026
DA - 2026/
VL - 4
SP - IMAG.a.1352
SN - 2837-6056
PB - MIT Press
DO - 10.1162/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1162/
"type": "article-journal",
"title": "Brain-age in ultra-low-field MRI: How well does it work?
"container-title": "Imaging neuroscience (Cambridge, Mass.)",
"author": [
{
"family": "Biondo",
"given": "Francesca"
},
{
"family": "Bennallick",
"given": "Carly"
},
{
"family": "Martin",
"given": "Sophie A"
},
{
"family": "Puglisi",
"given": "Lemuel"
},
{
"family": "Booth",
"given": "Thomas C"
},
{
"family": "Wood",
"given": "David A"
},
{
"family": "Iglesias",
"given": "Juan Eugenio"
},
{
"family": "Váša",
"given": "František"
},
{
"family": "Cole",
"given": "James H"
}
],
"container-title-short":
"volume": "4",
"page": "IMAG.a.1352",
"DOI": "10.1162/
"PMID": "42761967",
"PMCID": "PMC13588316",
"ISSN": "2837-6056",
"publisher": "MIT Press",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
9,
15
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1002/mrm.70488 [code]
- Advancing the Volumetric Analysis of Ultra-Low-Field Brain MRI Using Image-to-Image Translation.Journal: Magnetic resonance in medicineIn common: MONAI, PyTorch, SciPy, 1 other tool, methods / tools, structural MRI / diffusion, 11 references
- [2] doi:10.1002/hbm.70425 [code]
- Brain Age Estimation on T2-FLAIR Scans for Application to Multiple Sclerosis.Journal: Human brain mappingIn common: MONAI, FSL, PyTorch, 3 other tools, structural MRI / diffusion, 6 references, author James H Cole
- [3] doi:10.1038/s41467-026-71555-0 [code]
- A deep representation learning model to predict response to vagus nerve stimulation.Journal: Nature communicationsIn common: MONAI, ANTs, FreeSurfer, 6 other tools, structural MRI / diffusion, 3 references
- [4] doi:10.1371/journal.pbio.3003856 [code]
- Aging and metabolism contribute separately to brain-body health.Journal: PLoS biologyIn common: ANTs, FreeSurfer, FSL, 6 other tools, structural MRI / diffusion, 3 references
- [5] doi:10.1016/j.crmeth.2026.101473 [code]
- AmygdalaGo-BOLT for boundary-aware segmentation of the human amygdala.Journal: Cell reports methodsIn common: MONAI, ANTs, FreeSurfer, 6 other tools, methods / tools, structural MRI / diffusion, 1 reference
- [6] doi:10.1002/hbm.70547 [code]
- miniMORPH: A Morphometry Pipeline for Low-Field MRI in Infants.Journal: Human brain mappingIn common: ANTs, FreeSurfer, FSL, 3 other tools, structural MRI / diffusion, 5 references
- [7] doi:10.1038/s41398-026-04081-8 [code]
- Functional system-specific brain aging across the Alzheimer's disease continuum.Journal: Translational psychiatryIn common: FreeSurfer, NiBabel, tidyverse, 3 other tools, structural MRI / diffusion, 5 references
- [8] doi:10.1038/s41467-026-76011-7 [code]
- Human cortex organizes dynamic co-fluctuations along the sensorimotor-association
axis. Journal: Nature communicationsIn common: MONAI, ANTs, FreeSurfer, 7 other tools - [9] doi:10.1002/alz.71649 [code]
- Postmortem brain MRI reveals differential associations of subcortical and limbic volumes with cortical thinning and neurodegenerative pathologies.Journal: Alzheimer's & dementia : the journal of the Alzheimer's AssociationIn common: ANTs, FreeSurfer, FSL, 5 other tools, structural MRI / diffusion, 3 references
- [10] doi:10.1093/braincomms/fcag318 [code]
- Antenatal maternal anaemia and infant brain structure: high-field (3 T) and ultra-low-field (64 mT) MRI findings from South Africa.Journal: Brain communicationsIn common: ANTs, FreeSurfer, FSL, 4 other tools, structural MRI / diffusion, 3 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 3 repositories of the authors' code, each at its verified commit and with its license, 12 scripts, and 2 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:6838174893fd8f81…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
