Resampling volume atlas to BOLD space

Hi there,

I would like to resample a volume atlas (other than freesurfer aseg) in BOLD space similar to fmriprep output <...>_space-T1w_desc-aseg_dseg.nii.gz. I have registered the atlas to individual T1 as following

  1. Generate subject space surface .annot files
subject_name= ...
gcs_file_dir= ./gcs_Schaefer2018_update20190916/gcs

mris_ca_label -l $SUBJECTS_DIR/$subject_name/label/lh.cortex.label \
  $subject_name lh $SUBJECTS_DIR/$subject_name/surf/lh.sphere.reg \
  $gcs_file_dir/lh.$atlas.gcs \

mris_ca_label -l $SUBJECTS_DIR/$subject_name/label/rh.cortex.label \
  $subject_name rh $SUBJECTS_DIR/$subject_name/surf/rh.sphere.reg \
  $gcs_file_dir/rh.$atlas.gcs \
  1. Project labels from surface to volume
mri_aparc2aseg --s $subject_name --o $SUBJECTS_DIR/$subject_name/mri/$atlas.mgz --annot $atlas

May I ask which transformation matrix should I use to resample this $atlas.mgz (in subject T1 space) to each BOLD run and ensure the output is also .nii.gz? Should it be <...>_from-T1w_to-scanner_mode-image_xfm.txt under the func folder? I guess I will just need to conduct the exact same process as fMRIprep generated <...>_space-T1w_desc-aseg_dseg.nii.gz. Could you please show me a demo code or just a hint like in which fMRIprep script I could find relevant information to see how this resampling is calculated? Thanks a lot.


I tried the following steps to resample aseg.mgz (from freesurfer mri folder) to boldref.nii.gz (from fmriprep output func folder), The idea is to check if I can reproduce what fmriprep did to generate _space-T1w_desc-aseg_dseg.nii.gz in the func folder, if so, then I could apply to any other atlas.

Step1: convert aseg.mgz to aseg.nii.gz

mri_convert $SUBJECTS_DIR/$subject_name/mri/aseg.mgz \ # freesurfer folder under fmriprep folder

Step 2: resample aseg.nii.gz to boldref.nii.gz using from-fsnative_to-T1w_mode-image_xfm.txt

antsApplyTransforms --default-value 0 --float 1 --interpolation MultiLabel \
    --input $SUBJECTS_DIR/$subject_name/mri/aseg.nii.gz \
    --output $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-1_space-T1w_desc-aseg_manual.nii.gz \
    --reference-image $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-1_space-T1w_boldref.nii.gz \
    --transform $fmriprep_DIR/$subject_name/anat/${subject_name}_run-1_from-fsnative_to-T1w_mode-image_xfm.txt 

then compared the output _space-T1w_desc-aseg_manual.nii.gz with _space-T1w_desc-aseg_dseg.nii.gz , but they look different as the following .gif shows. I was not sure whether fmriprep resampled aseg.mgz or to get _space-T1w_desc-aseg_dseg.nii.gz, so I tried both these two .mgz, neither of them matched with _space-T1w_desc-aseg_dseg.nii.gz.

Could you please help to correct my process? Thanks a lot.


In case this might be useful to someone who wants to conduct the similar process. After researching this issue a bit I could reproduce <...>_space-T1w_desc-aseg_dseg.nii.gz generated by fmriprep.

First of all, this bug is the reason why sub-<subjID>_run-<runID>_desc-aseg_dseg.nii.gz under fmriprep/sub-<>/anat folder looks different to aseg.mgz under fmriprep/source/freesurfer/sub-<>/mri folder

Then I rerun fmriprep with 21.0.0rc2 version and did the following to reproduce <...>_space-T1w_desc-aseg_dseg.nii.gz from aseg.mgz in freefurfer folder, after reading the source code. Tested with 3 subjects and got identical segmentations resampled in BOLD resolution

# fmriprep used two steps 
# step 1, resample aseg.mgz to T1w.nii.gz and convert it to aseg.nii.gz, smriprep code below
# step 1a, use fsnative2t1w_xfm to calculate lta file () from T1.mgz to T1w.nii.gz
#fsnative2t1w_xfm = pe.Node(
#        RobustRegister(auto_sens=True, est_int_scale=True), name="fsnative2t1w_xfm"
#    )
# RobustRegister is from freesurfer mri_robust_register auto_sens is --satit est_int_scale is --iscale
mri_robust_register --mov $SUBJECTS_DIR/$subject_name/mri/T1.mgz \
    --dst $root_DIR/$subject_name/anat/${subject_name}_run-01_T1w.nii.gz \
    --lta $work_DIR/${subject_name}_run-01_fsnative2t1w_xfm.lta \
    --satit \
# step 1b, use fs.ApplyVolTransform with nearest interpolation to transfer 
# aseg.mgz to T1w space and convert to aseg.nii.gz
#    # Resample from T1.mgz to T1w.nii.gz, applying any offset in fsnative2t1w_xfm,
#    # and convert to NIfTI while we're at it
#    resample = pe.Node(
#        fs.ApplyVolTransform(transformed_file="seg.nii.gz", interp="nearest"),
#        name="resample",
#    )
# fs.ApplyVolTransform is mri_vol2vol
mri_vol2vol --mov $SUBJECTS_DIR/$subject_name/mri/aseg.mgz \
     --targ $root_DIR/$subject_name/anat/${subject_name}_run-01_T1w.nii.gz \
     --lta $work_DIR/${subject_name}_run-01_fsnative2t1w_xfm.lta \
     --o $work_DIR/${subject_name}_run-01_t1_aseg.nii.gz \

# 2 use antsApplyTransforms resample aseg.nii.gz to bold ref 
# # Resample aseg and aparc in T1w space (no transforms needed), fmriperp code below
#        aseg_t1w_tfm = pe.Node(
#            ApplyTransforms(interpolation='MultiLabel', transforms='identity'),
#            name='aseg_t1w_tfm', mem_gb=0.1)
#        aparc_t1w_tfm = pe.Node(
#            ApplyTransforms(interpolation='MultiLabel', transforms='identity'),
#            name='aparc_t1w_tfm', mem_gb=0.1)

antsApplyTransforms --dimensionality 3 --float 1 --interpolation MultiLabel \
    --input $work_DIR/${subject_name}_run-01_t1_aseg.nii.gz \
    --reference-image $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-2_space-T1w_boldref.nii.gz \
    --output $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-2_space-T1w_desc-aseg-rep.nii.gz \
    --transform identity

According to FsAnat-to-NativeAnat - Free Surfer Wiki freesurfer suggested using mri_label2vol to transform segmentation back to native space, so I tried the following. It could reproduce the above process, but in one subject only very few voxels are labeled differently, not sure why.

# using freesurfer mri_label2vol
mri_label2vol --seg $SUBJECTS_DIR/$subject_name/mri/aseg.mgz \
    --temp $SUBJECTS_DIR/$subject_name/mri/rawavg.mgz \
    --o $work_DIR/${subject_name}_run-01_t1_aseg_rep.mgz \
    --regheader $SUBJECTS_DIR/$subject_name/mri/aseg.mgz  

antsApplyTransforms --dimensionality 3 --float 1 --interpolation MultiLabel \
    --input $work_DIR/${subject_name}_run-01_t1_aseg_rep.mgz\
    --reference-image $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-2_space-T1w_boldref.nii.gz \
    --output $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-2_space-T1w_desc-aseg-rep.nii.gz \
    --transform identity

Finally, I tried the very first logic, using _run-1_from-fsnative_to-T1w_mode-image_xfm.txt provided by fmriprep to ignore recalculation of transformation from fs to T1w. The following code still can not reproduce <...>_space-T1w_desc-aseg_dseg.nii.gz. According to this bug I was expecting the _run-1_from-fsnative_to-T1w_mode-image_xfm.txtbe different from fmriprep versions, but the one I got from 20.2.4 is identical to 21.0.0rc2, this explains why the following code gave me the same result as the snapshot showed in the first post. Maybe I am wrong so _run-1_from-fsnative_to-T1w_mode-image_xfm.txt is not the transformation from fs to T1w. Also, the above mri_robust_register and then mri_vol2vol process could not reproduce <...>_space-T1w_desc-aseg_dseg.nii.gz generated by fmriprep 20.2.4

antsApplyTransforms --dimensionality 3 --float 1 --interpolation MultiLabel \
    --input $SUBJECTS_DIR/$subject_name/mri/aseg.mgz\
    --reference-image $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-2_space-T1w_boldref.nii.gz \
    --output $fmriprep_DIR/$subject_name/func/${subject_name}_${task_name}_run-2_space-T1w_desc-aseg-rep.nii.gz \
    --transform $fmriprep_DIR/$subject_name/anat/${subject_name}_run-1_from-fsnative_to-T1w_mode-image_xfm.txt
1 Like