Problem with realigning anatomical with partial volume epis

AFNI version info (afni -ver): 25.1.04

Halo everyone,
thanks a lot for a wonderful toolbox and for being such a supportive community! :slight_smile:

We have a problem with our 7T single-echo partial volume dataset, and were hoping you might help us solve it.

In brief, we collected three runs of single-echo multi-band partial volume data (focusing on the amygdala), as well as SBRefs and AP/PA scans for each run, and one mp2rage for the whole session. We want to analyze each individual separately without warping the images to standardized space.

Before running afni_proc (see below), we 'cleaned' the combined mp2rage scan using the INV2 scan together with the MPRAGEise python script. All looks well.
However, for some subjects we get very bad realignments after afni_proc:

We tried to realign the anatomical to the epis using align_epi_anat prior to running afni_proc, which seems to work well, i.e. the anatomical looks nicely aligned to the epis. However, when using this realigned anatomical as input to afni_proc, we get very bad results again (sorry cannot paste more embedded media here because new user):

We feel like we are missing something basic (first time AFNI users), and would be very grateful for any advice!

Thanks a lot and have a nice day!

Kristoffer

afni_proc.py \
            -subj_id                  ${subj}_${run} \
            -out_dir                  ${parrun_outdir} \
            -script                   ${scripts_dir}/${script_file} \
            -dsets                    ${epis} \
            -copy_anat                ${anat} \
            -anat_has_skull no \
            -volreg_base_dset         ${SBref} \
            -align_epi_ext_dset       ${SBref} \
            -blocks                   despike tshift align volreg mask scale regress \
            -anat_follower            anat_w_skull anat ${anat_with_skull}			 \
	        -anat_follower_ROI        allROIs_a anat ${suma_dir}/aparc.a2009s+aseg_REN_all.nii.gz     \
	        -anat_follower_ROI        allROIs_epi epi ${suma_dir}/aparc.a2009s+aseg_REN_all.nii.gz     \
            -anat_follower_ROI        L_LatNuc_a anat ${L_LatNuc} \
            -anat_follower_ROI        L_BasNuc_a anat ${L_BasNuc} \
            -anat_follower_ROI        L_CenNuc_a anat ${L_CenNuc} \
            -anat_follower_ROI        L_MedNuc_a anat ${L_MedNuc} \
            -anat_follower_ROI        L_CorNuc_a anat ${L_CorNuc} \
            -anat_follower_ROI        L_AccBasNuc_a anat ${L_AccBasNuc} \
            -anat_follower_ROI        L_CATA_a anat ${L_CATA} \
            -anat_follower_ROI        L_AAA_a anat ${L_AAA} \
            -anat_follower_ROI        L_ParNuc_a anat ${L_ParNuc} \
            -anat_follower_ROI        R_LatNuc_a anat ${R_LatNuc} \
            -anat_follower_ROI        R_BasNuc_a anat ${R_BasNuc} \
            -anat_follower_ROI        R_CenNuc_a anat ${R_CenNuc} \
            -anat_follower_ROI        R_MedNuc_a anat ${R_MedNuc} \
            -anat_follower_ROI        R_CorNuc_a anat ${R_CorNuc} \
            -anat_follower_ROI        R_AccBasNuc_a anat ${R_AccBasNuc} \
            -anat_follower_ROI        R_CATA_a anat ${R_CATA} \
            -anat_follower_ROI        R_AAA_a anat ${R_AAA} \
            -anat_follower_ROI        R_ParNuc_a anat ${R_ParNuc} \
            -anat_follower_ROI        L_LatNuc_epi epi ${L_LatNuc} \
            -anat_follower_ROI        L_BasNuc_epi epi ${L_BasNuc} \
            -anat_follower_ROI        L_CenNuc_epi epi ${L_CenNuc} \
            -anat_follower_ROI        L_MedNuc_epi epi ${L_MedNuc} \
            -anat_follower_ROI        L_CorNuc_epi epi ${L_CorNuc} \
            -anat_follower_ROI        L_AccBasNuc_epi epi ${L_AccBasNuc} \
            -anat_follower_ROI        L_CATA_epi epi ${L_CATA} \
            -anat_follower_ROI        L_AAA_epi epi ${L_AAA} \
            -anat_follower_ROI        L_ParNuc_epi epi ${L_ParNuc} \
            -anat_follower_ROI        R_LatNuc_epi epi ${R_LatNuc} \
            -anat_follower_ROI        R_BasNuc_epi epi ${R_BasNuc} \
            -anat_follower_ROI        R_CenNuc_epi epi ${R_CenNuc} \
            -anat_follower_ROI        R_MedNuc_epi epi ${R_MedNuc} \
            -anat_follower_ROI        R_CorNuc_epi epi ${R_CorNuc} \
            -anat_follower_ROI        R_AccBasNuc_epi epi ${R_AccBasNuc} \
            -anat_follower_ROI        R_CATA_epi epi ${R_CATA} \
            -anat_follower_ROI        R_AAA_epi epi ${R_AAA} \
            -anat_follower_ROI        R_ParNuc_epi epi ${R_ParNuc} \
            -tshift_interp            -wsinc9 \
            -align_unifize_epi        local \
            -align_opts_aea -big_move -check_flip -cost lpc+ZZ \
            -mask_epi_anat            yes \
            -volreg_compute_tsnr      yes \
            -volreg_align_e2a \
            -regress_compute_tsnr_stats L_LatNuc_epi 1\
            -regress_compute_tsnr_stats R_LatNuc_epi 1\
            -regress_compute_tsnr_stats L_BasNuc_epi 1\
            -regress_compute_tsnr_stats R_BasNuc_epi 1\
            -regress_compute_tsnr_stats L_CenNuc_epi 1\
            -regress_compute_tsnr_stats R_CenNuc_epi 1\
            -regress_compute_tsnr_stats L_MedNuc_epi 1\
            -regress_compute_tsnr_stats R_MedNuc_epi 1\
            -regress_compute_tsnr_stats L_CorNuc_epi 1\
            -regress_compute_tsnr_stats R_CorNuc_epi 1\
            -regress_compute_tsnr_stats allROIs_epi 17 33 \
            -regress_apply_mot_types  demean deriv \
            -regress_censor_motion    0.3 \
            -regress_censor_outliers  0.05 \
            -regress_motion_per_run \
            -regress_compute_fitts \
            -regress_make_ideal_sum   sum_ideal.1D \
            -regress_reml_exec \
            -regress_run_clustsim     no \
            -html_review_style        pythonic \
            -execute

Have you taken a step back from afni_proc.py and tried to get the EPI and anat aligned using align_epi_anat.py (afni_proc uses this under the hood)?

align_epi_anat.py has options for partial coverage that you can try. Assuming some combination of options to align_epi_anat.py produces agreeable results you can pass them to align_epi_anat.py when invoked by the afni_proc.py created script by using the -align_opts_aea option to afni_proc.py.

I've not faced the issue you are having here, this is what I'd try first to remedy the alignment issue.

Halo,
thanks for taking your time to reply!
Yes, i did run align_epi_anat.py separately and managed to nicely align the anatomical to the epis. I then tried to use the realigned anatomical scan as input to afni_proc, with the hope that no further realignment would be performed. Still, the resulting realignment was very bad.

I will now try your suggestion to pass exactly the same options via -align_opts_aea.

Thanks a lot and have a nice day!

Kris

Halo again,
just to follow up on your suggestion.
When i run align_epi_anat.py by itself, i get the following alignment:

The call to align_epi_anat was:
align_epi_anat.py
-anat2epi
-epi sub-11_ses-1_task-learning_run-2_bold.nii
-epi_base 0
-epi_strip 3dAutomask
-anat anatSS.sub-11.nii
-anat_has_skull no
-suffix name_ana
-partial_coverage
-ginormous_move
-volreg on
-output_dir my_output_dir

When i run what i believe is the same analysis in afni_proc, using the following input:

afni_proc.py \
            -subj_id                  subj_run \
            -out_dir                  parrun_outdir \
            -script                   script_file \
            -dsets                    epis \
            -copy_anat                anat \
            -anat_has_skull no \
            -volreg_align_to          first \
            -blocks                   align volreg \
            -align_opts_aea -partial_coverage -ginormous_move  \
            -volreg_align_e2a \
            -html_review_style        pythonic \
            -execute

i get the following alignment:

This is the call to align_epi_anat in the corresponding proc-file:

align_epi_anat.py -anat2epi -anat anatSS.sub-11+orig \
       -suffix _al_junk                              \
       -epi vr_base+orig -epi_base 0                 \
       -epi_strip 3dAutomask                         \
       -anat_has_skull no                            \
       -partial_coverage -ginormous_move             \
       -volreg off -tshift off

It looks like the epis have been warped, because they have rounded edges and also the coverage is now smaller (e.g. the height of the volume is much smaller).

Any suggestions highly appreciated!

Thanks a lot and have a great day!

Kristoffer

OK, the primary thing to help here (and probably with many slab/partial FOV EPI datasets) is that we have now just added a new option to align_epi_anat.py, which is: -large_move; this is available within AFNI version 25.2.05 and higher. This joins the family of options that control the style and amount of degrees of freedom used during EPI-anatomical alignment. This option provides the same functionality as -giant_move, but without the initial center of mass pre-alignment step. This is useful for allowing a bit more of a parameter search but the initial overlap of EPI and anatomical are pretty good.

How to judge EPI-anatomical alignment here? Look at the APQC HTML field for initial overlap, looking at the case where any obliquity is applied (note by default the AFNI GUI will ignore obliquity when displaying datasets, so look at EPI-anatomical overlap at the end of the APQC HTML 'vorig' section, or run @djunct_overlap_check and look at either the only *.jpg created or the one with _DEOB in its file name). In the present case, this is what EPI-anatomical overlap looked like (in the APQC HTML):


The top row shows when obliquity is ignored (which is what the GUI would show) and the bottom shows when obliquity is applied. Note that the bottom row shows the overall alignment between EPI and anatomical is good (no big rotational/translational differences between structures), and so we don't need a center of mass alignment to start. In fact, in general, one probably has to hope/arrange it that the coordinates of the slab EPI are consistent with those of the anatomical for best alignment, because the FOV is so different. Doing a center-of-mass shift might generally push things far afield. Hence, using -large_move both here and generally for slab alignment makes sense.

Note that having obliquity in the EPI data is generally fine. However, we have found it simplifies processing to remove obliquity in the anatomical volume before pretty much any processing starts, using adjunct_deob_around_origin. This program removes obliquity without resampling/blurring the data and while preserving the coordinate origin, (x,y,z)=(0,0,0). That had actually been done here already, so kudos!

Another thing I changed in the AP command for EPI-anatomical alignment was moving from using the "lpc+ZZ" cost function to "nmi". In general, I would always start by trying "lpc+ZZ"; but if that doesn't work, then "nmi" is a good backup. And that is what performed better here. I don't think that is necessarily a general trait with slab alignment, and I would typically still start with "lpc+ZZ", but such is life with working with real data.

On another note, using the external datasets for -volreg_base_dset and -align_epi_ext_dset proved a bit quirky with obliquity considerations. This is something we have to look at more within the processing stream, and will deal with for future cases. In the end, not using those did not cause a problem.

So, as a final comment then, the implemented "align" block options that worked well here were:

-align_unifize_epi           local                           \
-align_opts_aea              -large_move -check_flip         \
                             -cost nmi                       \

... which produced this EPI-anatomical alignment (as shown in the "ve2a" block in the APQC HTML:


So, the structures within the underlayed EPI slab and overlayed anatomical edges appear to be matching up well in most places. Yay.

--pt

ps: on a sidenote, I also mentioned with regards to the initial processing stream that it would be possible to combine many of the separate -anat_follower_ROI ... regions into a single volume, as long as they don't overlap. That would make the overall AP command shorter, and produce a single TSNR/shape table for those ROIs as the end, which is likely more convenient. The more full side commentary on this aspect was:

Another thing I had wanted to comment on earlier---you have many calls to the -anat_follower_ROI option, for individual ROIs rather than for an atlas (though I do see you are using a FS parcellation atlas, too), and doing the same for -regress_compute_tsnr_stats. That is not a problem per se, but it seems less than ideal in terms of command length and things. For the ROIs that don't overlap with each other, you could combine them into a single dataset with 3dcalc, like this (with letters increasing in the same pattern):

3dcalc -a ${L_LatNuc} -b ${L_BasNuc} -c ${L_CenNuc} -expr "1*a + 2*b + 3*c" -prefix MY_REF_ATLAS.nii.gz -datum short -nscale

… where you can give each ROI whatever integer you want---here, I have just chosen 1 for the "a" ROI, 2 for the "b" ROI, etc.

You can then run this to add info to the file header so an ROI-type colorbar comes up automatically in the AFNI GUI:

3drefit -cmap INT_CMAP  MY_REF_ATLAS.nii.gz

You can even use @MakeLabelTable to add atlas labels to each ROI. For example, for the above 3dcalc command, you could make a simple 2 column text file like the following called LABEL_FILE.txt:

1  L_LatNuc
2  L_BasNuc
3  L_CenNuc

… and then run the following to attach those integer-string pairs to the dset as a labeltable:

@MakeLabelTable                        \
    -lab_file LABEL_FILE.txt 1 0       \
    -dset MY_REF_ATLAS.nii.gz

I think it will just make things a bit nicer to view that atlas as a single dataset, as well as to make a single full table within the APQC HTML.

1 Like