Skip to content

Commit

Permalink
Merge pull request #5 from BIDS-Apps/fs
Browse files Browse the repository at this point in the history
add recon-all
  • Loading branch information
fliem authored Aug 14, 2017
2 parents 97a3e91 + d09c9dc commit f6eef41
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 129 deletions.
88 changes: 56 additions & 32 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,46 +1,68 @@
FROM ubuntu:trusty
FROM bids/base_validator:latest

RUN apt-get update \
&& apt-get install -y wget tcsh

RUN wget -qO- ftp://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/5.3.0-HCP/freesurfer-Linux-centos4_x86_64-stable-pub-v5.3.0-HCP.tar.gz | tar zxv -C /opt \
--exclude='freesurfer/trctrain' \
--exclude='freesurfer/subjects/fsaverage_sym' \
--exclude='freesurfer/subjects/fsaverage3' \
--exclude='freesurfer/subjects/fsaverage5' \
--exclude='freesurfer/subjects/fsaverage6' \
--exclude='freesurfer/subjects/cvs_avg35' \
--exclude='freesurfer/subjects/cvs_avg35_inMNI152' \
--exclude='freesurfer/subjects/bert' \
--exclude='freesurfer/subjects/V1_average' \
--exclude='freesurfer/average/mult-comp-cor' \
--exclude='freesurfer/lib/cuda' \
--exclude='freesurfer/lib/qt'
RUN wget -qO- https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/5.3.0/freesurfer-Linux-centos6_x86_64-stable-pub-v5.3.0.tar.gz | tar zxv -C /opt \
--exclude='freesurfer/trctrain' \
--exclude='freesurfer/subjects/fsaverage_sym' \
--exclude='freesurfer/subjects/fsaverage3' \
--exclude='freesurfer/subjects/fsaverage5' \
--exclude='freesurfer/subjects/fsaverage6' \
--exclude='freesurfer/subjects/cvs_avg35' \
--exclude='freesurfer/subjects/cvs_avg35_inMNI152' \
--exclude='freesurfer/subjects/bert' \
--exclude='freesurfer/subjects/V1_average' \
--exclude='freesurfer/average/mult-comp-cor' \
--exclude='freesurfer/lib/cuda' \
--exclude='freesurfer/lib/qt'


RUN /bin/bash -c 'touch /opt/freesurfer/.license'

ENV OS Linux
ENV FS_OVERRIDE 0
ENV OS=Linux
ENV FS_OVERRIDE=0
ENV FIX_VERTEX_AREA=
ENV SUBJECTS_DIR /opt/freesurfer/subjects
ENV FSF_OUTPUT_FORMAT nii.gz
ENV MNI_DIR /opt/freesurfer/mni
ENV LOCAL_DIR /opt/freesurfer/local
ENV FREESURFER_HOME /opt/freesurfer
ENV FSFAST_HOME /opt/freesurfer/fsfast
ENV MINC_BIN_DIR /opt/freesurfer/mni/bin
ENV MINC_LIB_DIR /opt/freesurfer/mni/lib
ENV MNI_DATAPATH /opt/freesurfer/mni/data
ENV FMRI_ANALYSIS_DIR /opt/freesurfer/fsfast
ENV PERL5LIB /opt/freesurfer/mni/lib/perl5/5.8.5
ENV MNI_PERL5LIB /opt/freesurfer/mni/lib/perl5/5.8.5
ENV PATH /opt/freesurfer/bin:/opt/freesurfer/fsfast/bin:/opt/freesurfer/tktools:/opt/freesurfer/mni/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV SUBJECTS_DIR=/opt/freesurfer/subjects
ENV FSF_OUTPUT_FORMAT=nii.gz
ENV MNI_DIR=/opt/freesurfer/mni
ENV LOCAL_DIR=/opt/freesurfer/local
ENV FREESURFER_HOME=/opt/freesurfer
ENV FSFAST_HOME=/opt/freesurfer/fsfast
ENV MINC_BIN_DIR=/opt/freesurfer/mni/bin
ENV MINC_LIB_DIR=/opt/freesurfer/mni/lib
ENV MNI_DATAPATH=/opt/freesurfer/mni/data
ENV FMRI_ANALYSIS_DIR=/opt/freesurfer/fsfast
ENV PERL5LIB=/opt/freesurfer/mni/lib/perl5/5.8.5
ENV MNI_PERL5LIB=/opt/freesurfer/mni/lib/perl5/5.8.5
ENV PATH=/opt/freesurfer/bin:/opt/freesurfer/fsfast/bin:/opt/freesurfer/tktools:/opt/freesurfer/mni/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH

RUN sudo apt-get update && apt-get install -y tree htop unzip
RUN sudo apt-get update && apt-get install -y tcsh
RUN sudo apt-get update && apt-get install -y bc
RUN sudo apt-get update && apt-get install -y tar libgomp1 perl-modules

# make freesurfer python scripts python3 ready
RUN 2to3-3.4 -w $FREESURFER_HOME/bin/aparcstats2table
RUN 2to3-3.4 -w $FREESURFER_HOME/bin/asegstats2table
RUN 2to3-3.4 -w $FREESURFER_HOME/bin/*.py

# download models
RUN mkdir /code
RUN wget -qO models.zip https://www.dropbox.com/s/5xbqw8i2e7x0g02/models.zip?dl=0 && \
unzip models.zip && mv models /code/ && rm models.zip

# freesurfer repo
RUN wget https://github.com/bids-apps/freesurfer/archive/v6.0.0-5.tar.gz && \
tar xfz v6.0.0-5.tar.gz && rm -r v6.0.0-5.tar.gz && \
cd freesurfer-6.0.0-5 && mv run.py /code/run_freesurfer.py
# since we are using freesurfer-bids-app-run-code from FS6 and we run it with FS5.3,
# we need to remove the parallel flag of recon-all
RUN sed -e "s/-parallel //g" -i /code/run_freesurfer.py
RUN echo "FS5.3_BIDSAPPv6.0.0-5" > /code/version
ENV PATH=/code:$PATH


# Install anaconda
RUN echo 'export PATH=/usr/local/anaconda:$PATH' > /etc/profile.d/conda.sh && \
wget --quiet https://repo.continuum.io/archive/Anaconda3-4.2.0-Linux-x86_64.sh -O anaconda.sh && \
Expand All @@ -56,11 +78,13 @@ ENV LC_ALL=C.UTF-8


RUN pip install nibabel
RUN pip install pybids
RUN pip install duecredit


COPY . /code/
RUN cd /code && ls && pip install -e .

RUN apt-get install -y unzip
RUN wget -qO models.zip https://www.dropbox.com/s/5xbqw8i2e7x0g02/models.zip?dl=0 && \
unzip models.zip && mv models /code/ && rm models.zip


ENTRYPOINT ["run_brain_age_bids.py"]
94 changes: 55 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,30 @@ based on data from Freesurfer 5.3.
It combines data from cortical thickness, cortical surface area, and
subcortical information (see Liem et al., 2017).

**How to cite BARACUS:** If you use BARACUS in your work please cite:
1. Liem et al. (2017) and
## Requirements
Your data has to be organized according to the
[BIDS standard](http://bids.neuroimaging.io) and each subject needs at
least one T1w image.
In a first step, BARACUS runs [FreeSurfer's](http://freesurfer.net)
`recon-all` command and saves the output in `--freesurfer_dir`.
If the data has previously been analyzed with FreeSurfer version 5.3.0,
and BARACUS finds them in `--freesurfer_dir` this step ist skippen.

**Important:** if you use previously processed FreeSurfer data

1. the data has to be preprocessed with
Freesurfer's 5.3.0 installation, not the 5.3.0-HCP installation;
2. FreeSurfer data needs to be BIDS-formatted, i.e. subject folders
should be named *sub-<subject_label>*, (e.g., sub-01, sub-02...)


## Acknowledgements
If you use BARACUS in your work please cite:

1. Liem et al. (2017),
1. the [zenodo DOI](https://zenodo.org/badge/latestdoi/93560323)
of the version you used.
of the BARACUS version you used, and
1. The [FreeSurfer tool](https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferMethodsCitation)

Liem et al. (2017). Predicting brain-age
from multimodal imaging data captures cognitive impairment.
Expand All @@ -19,26 +39,6 @@ Neuroimage, 148:179–188,
[\[preprint\]](http://www.biorxiv.org/content/early/2016/11/07/085506)


## Requirements
Before age prediction can be performed, [FreeSurfer's](http://freesurfer.net)
`recon-all` command has to be run with Freesurfer version 5.3.
Freesurfer data has to be in [BIDS format](http://bids.neuroimaging.io),
i.e. subject folders should be named
*sub-<subject_label>*, (e.g., sub-01, sub-02...).

**Important:** The data has to be preprocessed with
Freesurfer's 5.3.0 installation, not the 5.3.0-HCP installation.
The [fliem/freesurfer:v6.0.0-3-FSv5.3.0-1](https://hub.docker.com/r/fliem/freesurfer/tags/)
docker image can be used for that and can be run like this:

docker run -ti --rm \
-v /Users/filo/data/ds005:/bids_dataset:ro \
-v /Users/filo/outputs:/outputs \
fliem/freesurfer:v6.0.0-3-FSv5.3.0-1 \
/bids_dataset /outputs participant --participant_label 01 \
--license_key "XXXXXXXX"


## Models
**Liem2016__OCI_norm**: Model trained on subjects that have no
objective cognitive impairment (OCI) (*OCI norm* in Liem et al., 2017).
Expand All @@ -50,10 +50,8 @@ Sample: N = 2377, 1133f/1244m, age: M=58.4, SD=15.4, 18-83y;
containing data from the LIFE and NKI studies.




## Modes
It can be run in **BIDS mode** and in in **FILE mode**.
It can be run in **BIDS mode** (recommended) and in in **FILE mode**.

In BIDS mode the input is a BIDS formatted Freesurfer folder.

Expand All @@ -66,42 +64,50 @@ aseg files extracted via asegstats2table.

## BIDS mode
### Example
#### Introduction
These examples demonstrate how to run the `bids/baracus` docker container.
For a brief introduction how to run BIDS Apps see
[this site](http://bids-apps.neuroimaging.io/tutorial/).
In the examples `project/freesurfer` and `/project/out` are directories
In the examples `/project/bids_sourcedata`, `/project/freesurfer` and
`/project/baracus` are directories
on your hard drive, which are mapped into the docker container directories
`/data/in` and `/data/out`, respectively, via the `-v` flag.
`/data/in`, `/data/freesurfer` and `/data/out`, respectively, via
the `-v` flag.

#### Participants

docker run -ti --rm \
-v /project/freesurfer/:/data/in \
-v /project/out:/data/out \
bids/baracus /data/in /data/out participant
-v /project/bids_sourcedata/:/data/in \
-v /project/freesurfer/:/data/freesurfer \
-v /project/baracus:/data/out \
bids/baracus /data/in /data/out participant \
--license_key "XX" --freesurfer_dir /data/freesurfer

#### Group

docker run -ti --rm \
-v /project/freesurfer/:/data/in \
-v /project/out:/data/out \
bids/baracus /data/in /data/out group
-v /project/bids_sourcedata/:/data/in \
-v /project/freesurfer/:/data/freesurfer \
-v /project/baracus:/data/out \
bids/baracus /data/in /data/out group \
--license_key "XX" --freesurfer_dir /data/freesurfer

### Usage

docker run -ti --rm bids/${CIRCLE_PROJECT_REPONAME,,} -h
usage: run_brain_age_bids.py [-h]
[--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]]
--freesurfer_dir FREESURFER_DIR
[--models {Liem2016__OCI_norm,Liem2016__full_2samp_training} [{Liem2016__OCI_norm,Liem2016__full_2samp_training} ...]]
freesurfer_dir out_dir {participant,group}
--license_key LICENSE_KEY [--n_cpus N_CPUS] [-v]
bids_dir out_dir {participant,group}

BARACUS: Brain-Age Regression Analysis and Computation Utility Software. BIDS
mode. You specify a BIDS-formatted freesurfer folder as input. All data is
extracted automatiacally from that folder.

positional arguments:
freesurfer_dir Folder with freesurfer subjects formatted according to
BIDS standard.
bids_dir The directory with the input dataset formatted
according to the BIDS standard.
out_dir Results are put here.
{participant,group} Level of the analysis that will be performed.
"participant": predicts single subject brain age,
Expand All @@ -116,8 +122,18 @@ on your hard drive, which are mapped into the docker container directories
parameter is not provided all subjects should be
analyzed. Multiple participants can be specified with
a space separated list.
--freesurfer_dir FREESURFER_DIR
Folder with FreeSurfer subjects formatted according to
BIDS standard. If subject's recon-all folder cannot be
found, recon-all will be run.
--models {Liem2016__OCI_norm,Liem2016__full_2samp_training} [{Liem2016__OCI_norm,Liem2016__full_2samp_training} ...]

--license_key LICENSE_KEY
FreeSurfer license key - letters and numbers after "*"
in the email you received after registration. To
register (for free) visit
https://surfer.nmr.mgh.harvard.edu/registration.html
--n_cpus N_CPUS Number of CPUs/cores available to use.
-v, --version show program's version number and exit


## FILE mode
Expand Down
3 changes: 2 additions & 1 deletion baracus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
with open(os.path.join(dir_path, "../version")) as fi:
__version__ = fi.read().strip()

models_list = ["Liem2016__OCI_norm", "Liem2016__full_2samp_training"]
models_list = ["Liem2016__OCI_norm", "Liem2016__full_2samp_training"]

__changes__ = """
* 1.0.0: compute recon-all
* 0.9.4: fixed models in brain_age_files
* 0.9.3: fix tagging issue
* 0.9.2: fixed typo, -v flag
Expand Down
48 changes: 24 additions & 24 deletions baracus/prepare.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
import os
from subprocess import Popen, PIPE
import subprocess


# https://github.com/BIDS-Apps/freesurfer/blob/master/run.py#L12
def run(command, env={}, ignore_errors=False):
merged_env = os.environ
merged_env.update(env)
# DEBUG env triggers freesurfer to produce gigabytes of files
merged_env.pop('DEBUG', None)
process = Popen(command, stdout=PIPE, stderr=subprocess.STDOUT, shell=True, env=merged_env)
while True:
line = process.stdout.readline()
line = str(line, 'utf-8')[:-1]
print(line)
if line == '' and process.poll() != None:
break
if process.returncode != 0 and not ignore_errors:
raise Exception("Non zero return code: %d" % process.returncode)
from baracus.utils import run, run_fs_if_not_available


def prepare_fs_data(fs_dir, out_dir, subject):
Expand Down Expand Up @@ -54,17 +37,34 @@ def prepare_aseg(fs_dir, out_dir, subject):
return out_file


def run_prepare_all(freesurfer_dir, out_dir, subjects_to_analyze):
# downsample surfaces to fsaverage4 and extract subcortical data from aseg
def run_prepare_all(bids_dir, freesurfer_dir, out_dir, subjects_to_analyze, sessions_to_analyze, n_cpus, license_key):
"""
:param bids_dir:
:param freesurfer_dir:
:param out_dir:
:param subjects_to_analyze:
:param sessions_to_analyze: {"subject_label": ["test", "retest"],...}; {} if not truly_long_study
:return:
"""

fsav_dir = os.path.join(os.environ["FREESURFER_HOME"], "subjects")
for fsav in ["fsaverage", "fsaverage4"]:
if not os.path.exists(os.path.join(freesurfer_dir, fsav)):
os.symlink(os.path.join(fsav_dir, fsav), os.path.join(freesurfer_dir, fsav))

out_files = {}
# check if freesurfer is available and run if missing
freesurfer_subjects = []
for subject in subjects_to_analyze:
print("preparing %s" % subject)
out_files[subject] = prepare_fs_data(freesurfer_dir, out_dir, subject)
sessions = sessions_to_analyze.get(subject)
freesurfer_subjects.extend(run_fs_if_not_available(bids_dir, freesurfer_dir, subject, license_key, n_cpus,
sessions))

# downsample surfaces to fsaverage4 and extract subcortical data from aseg
out_files = {}
for fs_subject in freesurfer_subjects:
print("preparing %s" % fs_subject)
out_files[fs_subject] = prepare_fs_data(freesurfer_dir, out_dir, fs_subject)

print("FINISHED. Prepared %s" % " ".join(subjects_to_analyze))
print("FINISHED. Prepared %s" % " ".join(freesurfer_subjects))
return out_files
Loading

0 comments on commit f6eef41

Please sign in to comment.