Request for Help with EPI-to-Anatomical Alignment in Macaque AFNI Preprocessing

AFNI version info (AFNI_26.0.11):

Dear FNI/NHP preprocessing support team,

I am processing macaque resting-state fMRI data with the NMT v2.1 symmetric template. Because the original head position in the scanner was substantially different from the NMT template orientation, I first used SPM to manually adjust the T1-weighted anatomical image, including rotation and origin correction, based on the NMT template orientation. I then applied the same transformation matrix to the fMRI data from the same subject, so that the anatomical and functional images were adjusted consistently.

After this step, I overlaid the T1-weighted anatomical image onto the fMRI image in individual/native space. The anatomical and fMRI images showed good spatial overlap, as shown in Figure 1.

However, when I ran my AFNI preprocessing script:

afni_proc.py                                                                \
    -subj_id                  ${subj}                                       \
    -blocks            tshift align tlrc volreg blur mask scale regress     \
    -dsets                    ${dsets_epi}                                  \
    -copy_anat                ${anat_cp}                                    \
    -anat_has_skull           no                                            \
    -anat_uniform_method      none                                          \
    -radial_correlate_blocks  tcat volreg                                   \
    -radial_correlate_opts    -sphere_rad 14                                \
    -tcat_remove_first_trs    ${nt_rm}                                      \
    -volreg_align_to          MIN_OUTLIER                                   \
    -volreg_align_e2a                                                       \
    -volreg_tlrc_warp                                                       \
    -volreg_warp_dxyz         ${final_dxyz}                                 \
    -volreg_compute_tsnr      yes                                           \
    -align_opts_aea           -cost "${cost_a2e}" -giant_move               \
                              -cmass cmass -feature_size 0.5 ${aea_extra}   \
    -align_unifize_epi        ${aea_uni_epi}                                \
    -tlrc_base                ${ref_base}                                   \
    -tlrc_NL_warp                                                           \
    -tlrc_NL_warped_dsets     ${dsets_NL_warp}                              \
    -blur_size                ${blur_size}                                  \
    -regress_motion_per_run                                                 \
    -regress_apply_mot_types  demean deriv                                  \
    -regress_censor_motion    ${cen_motion}                                 \
    -regress_censor_outliers  ${cen_outliers}                               \
    -regress_est_blur_errts                                                 \
    -regress_est_blur_epits                                                 \
    -regress_run_clustsim     no                                            \
    -html_review_style        pythonic 

the intermediate preprocessed fMRI dataset generated at the pb02 stage no longer aligned well with the subject’s anatomical image in native space. Specifically, when I overlaid pb02.sub-monkey02.r01.volreg onto the individual-space T1 image, the fMRI and T1 images were clearly misaligned, as shown in Figure 2.

After the full preprocessing completed, the AFNI quality-control output, including the generated index.html / PDF QC report and the final alignment images, also indicated poor alignment between the processed fMRI and the anatomical/template space, as shown in Figure 3 and 4.

As a control, I also ran the same preprocessing workflow on a test/sample dataset, and the alignment looked good throughout the preprocessing procedure. Therefore, the current problem seems to be specific to this subject/data rather than a general failure of the preprocessing script.

In summary:

  1. The SPM-adjusted T1 and fMRI images appear well aligned before AFNI preprocessing.
  2. The same workflow works well on a test/sample dataset.
  3. During AFNI preprocessing of my own data, the pb02 fMRI output already appears misaligned relative to the individual-space T1.
  4. The final QC report also shows poor EPI-to-anatomical/template alignment.

I would appreciate your advice on the following questions:

  1. Could this problem be caused by inconsistent qform/sform information after applying the SPM transformation?
  2. Does AFNI use the qform or sform preferentially during afni_proc.py, align_epi_anat.py, and volreg_tlrc_warp?
  3. Is it appropriate to manually reorient both the anatomical and fMRI data in SPM before AFNI preprocessing, provided that the same transformation matrix is applied to both?
  4. Should I reset or harmonize the qform/sform information before running @animal_warper and afni_proc.py?
  5. Is there a recommended workflow for macaque data when the original head orientation differs greatly from the NMT template?
  6. Since the same workflow works well on the test dataset, what header or spatial metadata differences should I check between the test data and my own data?

I have attached the following materials for reference:

  • Figure 1: T1 overlaid on fMRI after SPM-based rotation and origin correction, showing good overlap.
  • Figure 2: pb02 fMRI output overlaid on individual-space T1 during AFNI preprocessing, showing misalignment.
  • Figure 3: final AFNI QC output showing poor alignment.
  • Figure 4: The final QC report generated by AFNI preprocessing.

Thank you very much for your time and help. Any suggestions on how to correctly preserve the T1-fMRI spatial relationship and avoid this misalignment during AFNI preprocessing would be greatly appreciated.

Best regards,

Chloe

Hi, Chloe-

Thanks for sharing your AP command and some of the relevant APQC HTML output.

What is the cost function you are using for EPI-anatomical alignment? In the code snippet, it is a variable (${cost_a2e}), so I can't tell.

Re. Q1: since processing completed, I am guessing that qform_code/sform_code values are not to blame here. (I still hope they aren't the dreaded, ambiguous "2"... Sigh.) To tell what sform_code and qform_code values you have in your initial EPI and anatomical dsets---I am assuming they are NIFTI format---you could run:

nifti_tool -disp_hdr -field qform_code -field sform_code -infiles DSET

Re. Q2: AP won't be too bothered about sform_code/qform_code here, as long as it gets interpreted as being in "original" space for both dsets, for this processing. You can verify that with:

3dinfo -space -av_space -prefix DSET

... which should show "ORIG" and "+orig" for your input anatomical and EPI dsets.

Re. Q3: That is fine to do manual pre-alignment, as long as nothing gets problematically changed about the header fields. Note that we also have a program "desphinxify" to help with this process of converting sphinx-position to more human-axis labelled. One can then also use "@Align_Centers" if one needs center of mass alignment, but hopefully that is not the case.

Re. Q4: it's best to have the qform_code and sform_code values accurately reflect being in original space, so one of them should be 1 and the other should be 0 or 1. AFNI can be told to interpret a value of 2 as "original" space, using the AFNI_NIFTI_VIEW environment variable; that is our default setting now, I believe. The above 3dinfo command will be key in seeing what AFNI thinks of the qform_code/sform_code values. That will determine if you would need to adjust it, if it were the dreaded 2 for example. As long as AFNI is treating is like "orig" you would still be fine (though, in general, it would be better to have more straightforward values of 1 for original space data).

Re. Q5: desphinxify is useful to give the dsets "proper" view planes. You just have to make sure you get the left/right correct, because it won't be visually apparent if you get that wrong (an Anterior-Posterior flip is easier to see quickly). The center of mass alignment with @Align_Centers could also be done, to help initial overlap. Here, your EPI-anatomical and anatomical-template alignments do seem good though. The commands mentioned here might just simplify your life a bit, not needing to do manual stuff.

Also, your anatomical has no obliquity in it, which is good; otherwise, that would create issues for applying some alignments, and we would probably recommend using obliquity_remover.py to purge obliquity from that dset and move that rotation over to the EPI data (either giving those obliquity or appending to existing obliquity), to preserve the original relative alignment. The EPI can have obliquity, fine, and AP will deal with it appropriately.

Re. Q6: brightness inhomogeneities and field of view coverage differences can matter. But some thoughts:

There is a lot of prominent non-brain material in the EPI. I'm not sure what your value for -align_unifize_epi ... is, because that is a variable, but in general I would only use "local" as an argument there for human data, which does not have so much material outside the brain. I would not use that for NHP data, at least not as an initial choice.

Since your EPI-anatomical have good alignment to start with (which is not always the case, esp. in NHP datasets!), I think you could remove -giant_move and -cmass cmass. We don't actually want the initial EPI-anatomical alignment to shift around by a center-of-mass alignment, because things are in a good spot. Both of those options would lead to that. If one still needed a large-ish search space for alignment parameters, one could have -large_move instead of -giant_move---they are the same except for the former not including a center-of-mass initial step.

For a cost function, since I think the EPI and anatomical have opposite contrasts, I would start with -cost lpc+ZZ for the align_opts_aea .. option.

  • if that doesn't work, I would use -cost nmi perhaps.
  • If that doesn't work well, perhaps because the EPI has so much non-brain material and the anatomical has been skullstripped nicely (so doesn't), we could choose to use the non-skullstripped anatomical (i.e., the input to @animal_warper) as the anatomical and let those align; we would also keep -anat_has_skull no, which would technically be a lie, but we don't want AP to skullstrip the anatomical in this case.

How does that sound?

--pt

Dear Paul,

Thank you again for your detailed suggestions.

I would like to clarify what I changed in the preprocessing script and ask for your advice on the next step.

The main modification I made was to add a recentering step before running afni_proc.py, based on another example I found. Specifically, I copied the EPI dataset, removed the obliquity information from the EPI copy, and reset its dataset center to 0 0 0:

3dcalc -overwrite -a ${dset_epi} -expr 'a' -prefix ${bold_deob}
3drefit -deoblique ${bold_deob}
3dCM -set 0 0 0 ${bold_deob}

Then I matched the anatomical orientation to the @animal_warper shifted anatomy and duplicated the shifted-anatomy origin into the copied anatomical dataset:

set new_ori = `3dinfo -orient ${anat_shft}`
3dresample -overwrite -prefix ${anat_recen} -orient ${new_ori} -input ${anat_nsu}
3drefit -overwrite -duporigin ${anat_shft} ${anat_recen}

Finally, I center-aligned the deobliqued EPI copy to the recentered anatomy:

@Align_Centers -overwrite -cm \
    -base `basename ${anat_recen}` \
    -dset `basename ${bold_deob}` \
    -prefix `basename ${bold_recen}`

I then used ${bold_recen} and ${anat_recen} as the inputs to afni_proc.py.

In afni_proc.py, the current alignment-related options are:

-align_opts_aea   -cost lpc+ZZ \
                          -feature_size 0.5

I also tested -cost nmi, but in this dataset the nmi result was worse than lpc+ZZ. The current lpc+ZZ result is better, but the APQC still shows some residual EPI-to-anatomical mismatch, especially in the inferior temporal/orbitofrontal and lower brain regions. The final EPI mask also still includes some non-brain areas(Fig A).

I also tested -mask_epi_anat yes. This successfully reduced the final EPI mask outside the anatomical brain, but—as expected—it did not improve the EPI-to-anatomical alignment itself. The remaining issue is still local mismatch in the inferior temporal/orbitofrontal and lower brain regions(Fig B). I also compared -epi_strip 3dAutomask and -epi_strip None, and the results were almost identical, so EPI stripping does not seem to be the main factor in this case.

Now it's mainly not the final mask, but the EPI-to-anat alignment is still not good enough locally. Would it be reasonable to test the following alternatives?

Thank you very much for your help.

Best regards,
Chloe

Hi, Chloe-

Re. masking: this option -mask_epi_anat yes is typically recommended, but it just refers to making the final mask by intersecting the anatomical and EPI masks. And masking is not applied to the data, just nice to have around when estimating whole brain statistics, etc.

Glad that the lpc+ZZ cost works pretty well. Much of the alignment looks better. I think the reason that the more inferior slices have poorer alignment is due to EPI distortion, and there is only so much the affine alignment will overcome. There is probably a shearing-type distortion at work. You could add the -large_move option to your AEA part, so that there is a larger search space in the affine fitting---the hope would be that maybe a more appropriate shear value would get found, rather than getting stuck in a local min of a poor fit. So, then your EPI-anatomical alignment opt would be:

-align_opts_aea   -cost lpc+ZZ       \
                  -large_move        \
                  -feature_size 0.5

If that does not work, then since the EPI values in the inferior slices seems to be generally dimmer, you could try boosting them with a kind of unifizing:

-align_unifize_epi      unif

Note that this is different than the local unifizing we would typically recommend for human datasets. This one will use 3dUnifize. I think it might include automasking, so we will want to be sure that it doesn't crop away those lower regions of the brain, simply because they are dim.

--pt

Hi Paul,

Thank you very much for your detailed suggestions.

I tried adding -large_move to the AEA alignment options and also tested -align_unifize_epi unif, as you suggested. However, the alignment is still not satisfactory, especially in the inferior slices. The lower EPI regions remain poorly matched to the anatomical image.

I have attached my current processing script and several screenshots of the alignment results. Could you please take a look when you have time and let me know whether there are any other options I should try? I am wondering whether this is mainly due to EPI distortion that cannot be fully corrected by affine alignment, or whether there may still be an issue in my preprocessing/alignment setup.

Thanks again for your help.

Best,
Chloe

# directories
# ---------------------------------------------------------------------------
set dir_inroot = /Users/chole/Desktop/TI/project_macaque_TI
set dir_basic  = ${dir_inroot}/data_00_basic
set dir_aw     = ${dir_inroot}/data_13_aw
set dir_work   = ${dir_inroot}/data_19_recenter_align/${subj}/${ses}/${cond}
set dir_ap     = ${dir_inroot}/data_20_ap_vox_recenter_rigid/${subj}/${ses}/${cond}

set sdir_basic = ${dir_basic}/${subj}/${ses}
set sdir_anat  = ${sdir_basic}/anat
set sdir_epi   = ${sdir_basic}/func/${cond}
set sdir_aw    = ${dir_aw}/${subj}/${ses}
set sdir_int   = ${sdir_aw}/intermediate

# ---------------------------------------------------------------------------
# input datasets from basic and @animal_warper outputs
# ---------------------------------------------------------------------------
set dset_epi   = ${sdir_epi}/*bold*.nii.gz

set anat_nsu   = ${sdir_aw}/${subj}_anat_nsu.nii.gz
set anat_shft  = ${sdir_int}/${subj}_anat_shft.nii.gz
set anat_nmt   = ${sdir_aw}/${subj}_anat_warp2std_nsu.nii.gz
set aff_shft   = ${sdir_int}/${subj}_anat_shft_al2std_mat.aff12.1D
set nl_warp    = ${sdir_aw}/${subj}_anat_shft_WARP.nii.gz
set nmt_base   = ${sdir_aw}/NMT_v2.1_sym_05mm_SS.nii.gz

# ---------------------------------------------------------------------------
# intermediate recentered copies
# ---------------------------------------------------------------------------
set bold_deob  = ${dir_work}/${cond}_bold_deob.nii.gz
set bold_recen = ${dir_work}/${cond}_bold_RECEN.nii.gz
set anat_recen = ${dir_work}/${subj}_anat_nsu_RECEN.nii.gz

# ---------------------------------------------------------------------------
# control variables
# ---------------------------------------------------------------------------
set nt_rm        = 2
set final_dxyz   = 1.25
set cen_motion   = 0.1
set cen_outliers = 0.02
set cost_a2e     = lpc+ZZ

# ---------------------------------------------------------------------------
# checks
# ---------------------------------------------------------------------------
foreach ff ( ${dset_epi} ${anat_nsu} ${anat_shft} ${anat_nmt} ${aff_shft} ${nl_warp} ${nmt_base} )
    if ( ! -e ${ff} ) then
        echo "** ERROR: missing required input: ${ff}"
        exit 1
    endif
end

\mkdir -p ${dir_work} ${dir_ap}

setenv AFNI_DECONFLICT OVERWRITE
setenv AFNI_COMPRESSOR GZIP

# ---------------------------------------------------------------------------
# make recentered copies, following the bash script logic
# ---------------------------------------------------------------------------
echo "== Make recentered copies =="

# Copy EPI, remove obliquity information, and reset dataset center to 0 0 0.
3dcalc -overwrite -a ${dset_epi} -expr 'a' -prefix ${bold_deob}
3drefit -deoblique ${bold_deob}
3dCM -set 0 0 0 ${bold_deob}

# Match anatomical orientation to the animal_warper shifted anatomy,
# then duplicate the shifted-anatomy origin into the copied anatomy.
set new_ori = `3dinfo -orient ${anat_shft}`
3dresample -overwrite -prefix ${anat_recen} -orient ${new_ori} -input ${anat_nsu}
3drefit -overwrite -duporigin ${anat_shft} ${anat_recen}

# Center-align the deobliqued EPI copy to the recentered anatomy.
pushd ${dir_work}
@Align_Centers -overwrite -cm                         \
    -base `basename ${anat_recen}`                     \
    -dset `basename ${bold_deob}`                      \
    -prefix `basename ${bold_recen}`
popd

# ---------------------------------------------------------------------------
# write and run afni_proc.py command
# ---------------------------------------------------------------------------
set ap_cmd = ${dir_ap}/ap.cmd.${subj}.${cond}

cat <<EOF_AP >! ${ap_cmd}
#!/bin/tcsh

# afni_proc.py command generated by do_20_ap_nmt_recenter_nmi.tcsh
# Alignment setting: -cost ${cost_a2e}
# HTML QC: -html_review_style pythonic

afni_proc.py                                                              \
    -subj_id                  ${subj}                                   \
    -script                   proc.${subj}.${cond}                      \
    -scr_overwrite                                                    \
    -out_dir                  ${dir_ap}/${subj}.results                 \
    -blocks                   tshift align tlrc volreg mask scale regress \
    -dsets                    ${bold_recen}                             \
    -copy_anat                ${anat_recen}                             \
    -anat_has_skull           no                                        \
    -anat_uniform_method      none                                      \
    -tlrc_base                ${nmt_base}                               \
    -tlrc_NL_warp                                                       \
    -tlrc_NL_warped_dsets     ${anat_nmt} ${aff_shft} ${nl_warp}        \
    -radial_correlate_blocks  tcat volreg                               \
    -radial_correlate_opts    -sphere_rad 14                            \
    -tcat_remove_first_trs    ${nt_rm}                                  \
    -volreg_align_to          MIN_OUTLIER                               \
    -volreg_align_e2a                                                   \
    -volreg_tlrc_warp                                                   \
    -volreg_warp_dxyz         ${final_dxyz}                             \
    -volreg_compute_tsnr      yes  \
    -mask_epi_anat            yes                                     \
    -align_opts_aea           -cost lpc+ZZ                   \
                              -large_move   \
                              -feature_size 0.5   \
    -align_unifize_epi        unif                       \
    -regress_motion_per_run                                             \
    -regress_apply_mot_types  demean deriv                              \
    -regress_censor_motion    ${cen_motion}                             \
    -regress_censor_outliers  ${cen_outliers}                           \
    -regress_est_blur_errts                                             \
    -regress_est_blur_epits                                             \
    -regress_run_clustsim     no                                        \
    -html_review_style        pythonic

EOF_AP


Indeed, the frontal and lower/inferior regions do seem to have more notable distortion, and this might be presenting a very large challenge for the affine alignment, which is a global fit. There is also less tissue contrast in, say, the temporal lobes (from looking at the vorig image of the EPI data).

Actually, taking one step back, do you have the QC images of the @animal_warper results? I'm wondering if some of the anatomical is trimmed in places, like the temporal lobes (I'm looking at the vorig image of the anatomical). I wonder if a bit of GM is being left off.

It would be nice to the qc_02_input+mask.sag.png image, to see the estimated mask overlaid on the input anatomical, sagittal view.

And then seeing either qc_00*.sag.png or qc_01*.sag.png, to see the edges of the template over the input, in either the template or input space, respectively.

thanks,
pt

Hi Paul,

Thank you very much for your detailed feedback.

Yes, after checking the results more carefully, I agree that the anatomical warping itself seems to have some issues. The frontal and lower/inferior regions show more obvious mismatch, and the temporal lobe regions also seem to have poorer tissue coverage/contrast. This may be contributing to the difficulty in the subsequent EPI-anatomical affine alignment.

I have attached the relevant QC images from @animal_warper, including the mask-overlaid input anatomical image and the template-edge overlay images, as well as my current processing script. In particular, I included the qc_02_input+mask.sag.png image for checking whether part of the anatomical image may have been trimmed or whether some gray matter is being excluded.

Could you please take a look and let me know whether the anatomical preprocessing/warping step looks problematic to you? If so, I would appreciate any suggestions on how to adjust the @animal_warper setup or masking procedure before moving on to the EPI alignment.

Thanks again for your help.

Best,
Chloe

 # labels
set subj           = $1
set ses            = $2

# upper directories
set dir_inroot     = /Users/chole/Desktop/TI/project_macaque_TI
set dir_log        = ${dir_inroot}/logs
set dir_ref        = ${dir_inroot}/NMT_v2.1_sym/NMT_v2.1_sym_05mm

set dir_basic      = ${dir_inroot}/data_00_basic
set dir_aw         = ${dir_inroot}/data_13_aw

# subject directories
set sdir_basic     = ${dir_basic}/${subj}/${ses}
set sdir_anat      = ${sdir_basic}/anat
set sdir_epi       = ${sdir_basic}/func
set sdir_aw        = ${dir_aw}/${subj}/${ses}

# --------------------------------------------------------------------------
# data and control variables
# --------------------------------------------------------------------------

# dataset inputs, with abbreviations for each 
set anat_orig    = ${sdir_anat}/*T1w*.nii.gz
set anat_orig_ab = ${subj}_anat

set ref_base     = ${dir_ref}/NMT_v2.1_sym_05mm_SS.nii.gz
set ref_base_ab  = NMT2

set ref_atl      = ( ${dir_ref}/CHARM_in_NMT_v2.1_sym_05mm.nii.gz     \
                     ${dir_ref}/SARM_in_NMT_v2.1_sym_05mm.nii.gz)
set ref_atl_ab   = ( CHARM SARM)

set ref_seg      = ${dir_ref}/NMT_v2.1_sym_05mm_segmentation.nii.gz
set ref_seg_ab   = SEG

set ref_mask     = ${dir_ref}/NMT_v2.1_sym_05mm_brainmask.nii.gz 
set ref_mask_ab  = MASK

# control variables

# check available N_threads and report what is being used
# + consider using up to 16 threads (alignment programs are parallelized)
# + N_threads may be set elsewhere; to set here, uncomment the following line:
### setenv OMP_NUM_THREADS 16

set nthr_avail = `afni_system_check.py -disp_num_cpu`
set nthr_using = `afni_check_omp`

echo "++ INFO: Using ${nthr_avail} of available ${nthr_using} threads"

echo "++ INFO: anat input = ${anat_orig}"
echo "++ INFO: outdir     = ${sdir_aw}"

# ---------------------------------------------------------------------------
# run programs
# ---------------------------------------------------------------------------

time @animal_warper                                 \
    -echo                                           \
    -input            ${anat_orig}                  \
    -input_abbrev     ${anat_orig_ab}               \
    -base             ${ref_base}                   \
    -base_abbrev      ${ref_base_ab}                \
    -atlas_followers  ${ref_atl}                    \
    -atlas_abbrevs    ${ref_atl_ab}                 \
    -seg_followers    ${ref_seg}                    \
    -seg_abbrevs      ${ref_seg_ab}                 \
    -skullstrip       ${ref_mask}                   \
    -outdir           ${sdir_aw}                    \
    -ok_to_exist

echo "++ FINISHED AW"

exit 0

Howdy-

You could add:

-cost lpa+ZZ

to your AW command, mainly changing the nonlinear cost function used to be "lpa" instead of "pcl".

I would try to add that and see if it improves some of the frontal region and ends of temporal lobes.

-pt

Hi Paul,

Thank you again for the suggestion.

I tried adding -cost lpa+ZZ to the @animal_warper command and reran the anatomical warping. The overall alignment appears somewhat reasonable, but the temporal lobe alignment is still not very satisfactory. In particular, the template edges still do not match the temporal regions well in both the sagittal and coronal QC views.

I have attached the updated QC images after using -cost lpa+ZZ, including:

Do you think this residual mismatch is mainly due to anatomical distortion / tissue contrast issues in the input T1 image, or are there any other @animal_warper options that might be worth trying?

Any suggestions would be greatly appreciated.

Best,
Chloe