A BIDS App implementation for FreeSurfer 8.0.0 that provides standardized surface reconstruction and morphometric analysis with NIDM output.
This BIDS App runs only FreeSurfer's recon-all pipeline on structural T1w and (optionally) T2w images from a BIDS-valid dataset. It organizes outputs in a BIDS-compliant derivatives structure and provides additional NIDM format outputs for improved interoperability.
Important Note: This app is designed to run the complete recon-all cortical reconstruction pipeline. It does not provide access to other FreeSurfer command-line tools (e.g., tkmedit, tksurfer, mri_vol2vol, etc.). For interactive FreeSurfer tools or additional analyses, you will need a full FreeSurfer installation.
The app implements:
- Automatic identification and processing of T1w images (required)
- Utilization of T2w images when available (optional)
- Multi-session data handling with appropriate processing paths
- NIDM format output generation for standardized data exchange
- BIDS provenance documentation for reproducibility
- Comprehensive version tracking for all components (FreeSurfer, BIDS app, Python packages)
- Docker (for containerized execution)
- FreeSurfer license file (obtainable from https://surfer.nmr.mgh.harvard.edu/registration.html)
Clone the repository (including submodules) using SSH:
git clone --recursive git@github.com:ReproNim/freesurfer-nidm_bidsapp.git
cd freesurfer-nidm_bidsappNote: The
--recursiveflag is required to also clone the git submodules used by this project (e.g.,src/segstats_jsonld).
This BIDS App supports both Docker and Singularity/Apptainer, allowing you to run the application in various environments including HPC clusters.
# Build Docker image (for local development)
python setup.py docker
# Build Singularity/Apptainer image (e.g., on a cluster)
apptainer build --fakeroot --build-arg GIT_COMMIT=$(git rev-parse HEAD) freesurfer-nidm-bidsapp.sif Singularity
# Or specify a custom output location
apptainer build --fakeroot --build-arg GIT_COMMIT=$(git rev-parse HEAD) /path/to/output/freesurfer-nidm-bidsapp.sif SingularityNote: The
--fakerootoption is recommended for cluster environments because it avoids permission issues on shared systems and does not require root privileges. If you encounter issues, contact your system administrator to ensure your user is configured for fakeroot, and make sure you have write permissions in the build directory.
# Run the container
docker run -v /path/to/license.txt:/license.txt \
-v /path/to/bids/data:/data \
-v /path/to/output:/output \
freesurfer-nidm-bidsapp \
/data /output participant \
--participant-label 01 \
--fs-license-file /license.txt# Run the container
apptainer run \
--bind /path/to/license.txt:/license.txt,/path/to/bids/data:/data,/path/to/output:/output \
/path/to/freesurfer-nidm-bidsapp.sif \
/data /output participant \
--participant-label 01 \
--fs-license-file /license.txtNote: The application files are included in the container image, so there's no need to bind the repository directory. Only the license file, input data, and output directory need to be bound.
After building the Singularity/Apptainer image (see Building Containers), create a job submission script like this:
#!/bin/bash
#SBATCH --job-name=freesurfer
#SBATCH --output=freesurfer_%j.out
#SBATCH --cpus-per-task=4
#SBATCH --mem=16G
# Path to the Singularity image
SIF_FILE=/path/to/freesurfer.sif
# Path to license file
LICENSE_FILE=/path/to/license.txt
# Input and output paths
BIDS_DIR=/path/to/bids/data
OUTPUT_DIR=/path/to/output
apptainer run \
--bind $LICENSE_FILE:/license.txt,$BIDS_DIR:/data,$OUTPUT_DIR:/output \
$SIF_FILE \
/data /output participant \
--participant-label sub-01 \
--fs-license-file /license.txt-
Positional arguments:
bids_dir: The directory with the input BIDS datasetoutput_dir: The directory where the output files should be storedanalysis_level: Processing level. Choices areparticipantandsession.
-
Optional arguments:
--participant-label: One participant label, with or without thesub-prefix.--session-label: One session label, with or without theses-prefix. It is accepted in participant mode for BABS session-wise jobs.--fs-license-file: Path to the FreeSurfer license file.--skip-bids-validation: Skip PyBIDS validation.--skip-freesurfer: Reuse a completedrecon-alldirectory and run only the remaining export steps. The directory is checked against the images it was made from; see Reusing an existing reconstruction.--skip-nidm: Skip NIDM output generation.--nidm-input-dir: Directory containing existing NIDM documents to augment. Defaults to<bids_dir>/../NIDM(the standard BABS mount point). Per subject the app searches most-specific first. Session-wise runs trysub-<id>/ses-<session>/nidm.ttl,sub-<id>_ses-<session>/nidm.ttl,sub-<id>/ses-<session>/sub-<id>_ses-<session>.ttlandsub-<id>_ses-<session>.ttl. Every run then triessub-<id>/nidm.ttl,sub-<id>/sub-<id>.ttl,sub-<id>.ttl, and finally a root-levelnidm.ttl, which is taken as a dataset-level document covering all subjects. Other files are never used, so a run cannot pick up another subject's record. The lookup runs before recon-all. Missing input NIDM is not an error: the app logs a warning and buildsnidm.ttlfrom scratch, without the subject's demographics or input provenance. A first match that is a symlink with no content behind it (a datalad/git-annex clone beforedatalad get) is an error, so the run fails instead.--max-voxel-size: Largest voxel dimension in mm accepted for a T1w/T2w input (default2.0). See Input images.--verbose: Enable debug logging.
The app looks for T1w and T2w images in the subject's anat/ directory (restricted to the requested session, if any) and chooses which ones go to recon-all.
- Voxel size first. Every image is checked against
--max-voxel-size(default2.0mm, applied to each of the three voxel dimensions in the header, rounded to 3 decimals) before anything is chosen, and images over the limit are set aside. A too-coarse image therefore never decides which acquisition is used. The check exists because some images labelled high resolution are thick slabs: ABIDE II UCLA_Longacq-hiresT1w images are 1.5x1.5x4.0 mm, andrecon-allon such an image can finish without error and still produce a meaningless reconstruction. An image whose header cannot be read ranks after every readable one; it is used only when nothing readable is left, andrecon-allthen reports the read failure. - Ranking. The remaining images are ranked as the sibling ants-nidm app ranks them: no
acq-entity before anyacq-entity, then no other optional entities (ce-,rec-, ...) before some, then the lowestrun(no run counts as run 0), then the file name. The best-ranked image is the one ants-nidm segments. - T1w. The best-ranked image fixes the acquisition, and every run of that acquisition (same entities apart from
run) is used;recon-allaverages them. Other acquisitions are never mixed in. For example, ABIDE II UCLA_Long sessions hold bothsub-X_ses-N_run-1_T1wandsub-X_ses-N_acq-hires_run-1_T1w; only the first is used. If every T1w is over the limit,recon-allis not run, the subject is marked failed and the app exits non-zero. - T2w.
recon-alltakes one T2w (-T2 ... -T2pial): the best-ranked one within the limit. If none is within the limit,recon-allruns on the T1w alone.
The chosen and excluded files are logged. processing_summary.json records them as input_files and inputs_not_used (paths relative to the BIDS root, each excluded file with its reason), plus a failure_reason when the subject could not be processed.
When the subject's freesurfer/ directory (or the staging copy of an interrupted run) already holds a finished recon-all run, the app does not run recon-all again, and with --skip-freesurfer it never does. Such a directory is judged by the images it was made from, not by what the selection above would choose today:
- The images are read from the
CMDARGSline thatrecon-allwrites intoscripts/recon-all.donewhen it finishes (its-iand-T2arguments). If a laterrecon-allcall without-ihas rewritten that file,input_filesin the subject'sprocessing_summary.jsonis used instead. - Each image must be an
anatimage of this subject (and session) and pass--max-voxel-size, the T2w included. Otherwise the directory is not used, the subject fails and the app exits non-zero; the reason names the directory and the image. - A run that
recon-allitself ended with an error (it leavesscripts/recon-all.error, and writes1torecon-all.done) is not finished: the subject fails rather than reusing or relocating that directory.
Remove the directory to reconstruct the subject from the inputs the current selection chooses.
Process a single subject:
# Using Docker (for local development)
docker run -v /path/to/bids_dataset:/bids_dataset:ro \
-v /path/to/output:/output \
-v /path/to/freesurfer/license.txt:/license.txt \
freesurfer-nidm-bidsapp \
/bids_dataset /output participant \
--participant-label 01 --fs-license-file /license.txt
# Using Apptainer (for clusters)
apptainer run \
--bind /path/to/license.txt:/license.txt,/path/to/bids_dataset:/data,/path/to/output:/output \
freesurfer.sif \
/data /output participant \
--participant-label 01 \
--fs-license-file /license.txtProcess one session explicitly:
apptainer run \
--bind /path/to/license.txt:/license.txt,/path/to/bids_dataset:/data,/path/to/output:/output \
freesurfer.sif \
/data /output session \
--participant-label 01 \
--session-label baseline \
--fs-license-file /license.txtThe CLI processes one participant or participant/session pair per invocation. Use a scheduler or BABS job array for dataset-level parallelism.
The app supports both the original BABS project layout and the configurable BIDS-study layout introduced by PennLINC/babs PR #369. The new layout places the analysis DataLad dataset at the BABS project root and its RIA stores beneath .babs/:
analysis_path: "."
input_ria_path: ".babs/input_ria"
output_ria_path: ".babs/output_ria"See examples/babs-freesurfer-nidm-bids-study.yaml for a complete template. It requires a BABS revision containing PR #369. Omit those three path settings to use the legacy analysis/, input_ria/, and output_ria/ layout.
BABS invokes the standard positional analysis level participant for both subject-wise and session-wise jobs. For a session-wise job, configure $SESSION_SELECTION_FLAG: "--session-label"; this app honors that explicit label and only falls back to auto-detection when exactly one session is visible. If an upstream NIDM dataset is used, configure --nidm-input-dir explicitly in the BABS YAML.
The app writes everything for a subject under that subject's own directory, directly inside output_dir — there is no app-name wrapper directory. The subject directory is therefore also the top level of the per-subject zip in BABS workflows, so results land in the same layout whether the app runs standalone or through BABS.
<output_dir>/
├── dataset_description.json # BIDS derivative dataset description (dataset level)
├── README # Auto-generated derivatives readme (dataset level)
│
├── sub-<id>/ # single-session dataset
│ ├── anat/
│ │ ├── sub-<id>_desc-brain_T1w.nii.gz
│ │ ├── sub-<id>_desc-aparcaseg_dseg.nii.gz
│ │ └── sub-<id>_desc-wmparc_dseg.nii.gz
│ ├── stats/
│ │ ├── sub-<id>_aseg.stats
│ │ ├── sub-<id>_lh.aparc.stats
│ │ └── sub-<id>_rh.aparc.stats
│ ├── freesurfer/ # recon-all output directory for this subject
│ │ ├── mri/ (brain.mgz, aparc.DKTatlas+aseg.mgz, wmparc.mgz, ...)
│ │ ├── surf/ (lh.white, lh.pial, rh.white, rh.pial, ...)
│ │ ├── label/
│ │ ├── stats/ (aseg.stats, lh.aparc.stats, rh.aparc.stats, ...)
│ │ └── scripts/ (recon-all.done, recon-all.log, ...)
│ ├── nidm.ttl # NIDM graph: input NIDM (if any) + this run's measures
│ ├── fs_cde.ttl # FreeSurfer CDE vocabulary (static, shipped alongside)
│ └── processing_summary.json # Per-run processing summary with version info (not written by --skip-freesurfer)
│
└── sub-<id>/ # multi-session dataset: same tree, one level deeper
└── ses-<session>/
├── anat/ (sub-<id>_ses-<session>_desc-*.nii.gz)
├── stats/ (sub-<id>_ses-<session>_*.stats)
├── freesurfer/
├── nidm.ttl
├── fs_cde.ttl
└── processing_summary.json
Notes:
- BIDS-organised derivative files use BIDS-compliant naming (e.g.,
_desc-brain_T1w.nii.gz,_desc-aparcaseg_dseg.nii.gz). freesurfer/is the FreeSurfer subject directory created byrecon-all(the app stagesSUBJECTS_DIRinternally and moves the result here). For multi-session datasets the FreeSurfer subject ID issub-<id>_ses-<session>(e.g.sub-01_ses-baseline).- The NIDM output is always named
nidm.ttl, one per subject (or per session for multi-session data). When an input NIDM document is found (see--nidm-input-dir),nidm.ttlcontains that graph plus this run's measures — the input graph is preserved inside the output, never written to a separate file. fs_cde.ttlholds the shared FreeSurfer common-data-element vocabulary. It is identical across subjects and deliberately kept out ofnidm.ttl.- When no input NIDM document is found, the converter also leaves one intermediate
<stats-name>_nidm.jsonldfile per supported stats file (e.g.aseg_nidm.jsonld) in the subject directory; their content is merged intonidm.ttl. - In BABS workflows each job zips only
sub-<id>/, sodataset_description.jsonandREADMEbelong to the enclosing derivative dataset rather than the zip.
sub-<id>[/ses-<session>]/freesurfer/ is the subject's recon-all output directory. Key files copied into the BIDS-organised anat/ and stats/ trees include:
- Brain-extracted T1w (
brain.mgz→sub-<id>_desc-brain_T1w.nii.gz) - Cortical parcellation (
aparc.DKTatlas+aseg.mgz→sub-<id>_desc-aparcaseg_dseg.nii.gz) - White-matter parcellation (
wmparc.mgz→sub-<id>_desc-wmparc_dseg.nii.gz) - Surface meshes (
lh.white,rh.white,lh.pial,rh.pial) - Statistical measures (
aseg.stats,lh.aparc.stats,rh.aparc.stats)
The NIDM output is a Turtle (.ttl) document named nidm.ttl, written beside the analysis results in each subject (or subject/session) directory, with the static CDE vocabulary alongside as fs_cde.ttl. The graph includes:
- Comprehensive version information:
- FreeSurfer version and source (from base image)
- BIDS app version (from setup.py)
- Python environment and package versions
- Processing provenance
- Volume measurements for brain structures
- Cortical thickness and surface area measurements
- Standard identifiers for interoperability
This BIDS App uses the pre-built FreeSurfer Docker image vnmd/freesurfer_8.0.0 from Neurodesk as its base image. Neurodesk is a containerized data analysis environment for neuroimaging that provides a suite of neuroimaging tools in Docker containers. These containers are built using Neurodocker, a command-line tool that generates custom Dockerfiles for neuroimaging software.
Using the Neurodesk FreeSurfer image offers several advantages:
- Faster build times - no need to download and install FreeSurfer during build
- Smaller container size - uses the optimized FreeSurfer image
- Improved reliability - uses a verified and tested FreeSurfer installation
- Compatibility with FreeSurfer's license terms
- Standardized environment - built using the community-supported Neurodocker tool
- Regular maintenance - benefits from the Neurodesk project's updates and improvements
This BIDS App is licensed under MIT License.
- FreeSurfer (https://surfer.nmr.mgh.harvard.edu/)
- BIDS (https://bids.neuroimaging.io/)
- NIDM (http://nidm.nidash.org/)
- Neurodesk (https://www.neurodesk.org/)
- Neurodocker (https://github.com/ReproNim/neurodocker)
If you use this BIDS App in your research, please cite:
- Fischl B. (2012). FreeSurfer. NeuroImage, 62(2), 774–781. https://doi.org/10.1016/j.neuroimage.2012.01.021
- Gorgolewski, K. J., Auer, T., Calhoun, V. D., Craddock, R. C., Das, S., Duff, E. P., Flandin, G., Ghosh, S. S., Glatard, T., Halchenko, Y. O., Handwerker, D. A., Hanke, M., Keator, D., Li, X., Michael, Z., Maumet, C., Nichols, B. N., Nichols, T. E., Pellman, J., Poline, J. B., … Poldrack, R. A. (2016). The brain imaging data structure, a format for organizing and describing outputs of neuroimaging experiments. Scientific data, 3, 160044. https://doi.org/10.1038/sdata.2016.44
- Maumet, C., Auer, T., Bowring, A., Chen, G., Das, S., Flandin, G., Ghosh, S., Glatard, T., Gorgolewski, K. J., Helmer, K. G., Jenkinson, M., Keator, D. B., Nichols, B. N., Poline, J. B., Reynolds, R., Sochat, V., Turner, J., & Nichols, T. E. (2016). Sharing brain mapping statistical results with the neuroimaging data model. Scientific data, 3, 160102. https://doi.org/10.1038/sdata.2016.102
- Renton, A.I., Dao, T.T., Johnstone, T. et al. Neurodesk: an accessible, flexible and portable data analysis environment for reproducible neuroimaging. Nat Methods 21, 804–808 (2024). https://doi.org/10.1038/s41592-023-02145-x