align one run to another using align_api_anat.py and 3DAllineate - bad results

AFNI version info (afni -ver): Apr 2 2024 (Version AFNI_24.1.00 'Publius Septimius Geta')

Hi Afni people,
I am trying to align one scanning session (with many api runs and one anat) to another session by aligning the 2 anat scans first using align_api_anat.py, and then aligning the epi using the transformation matrix using 3DAllineate.

Something in these transformations is not working, and the first step already produces bad-looking results (that are less aligned than the original images).

Thanks in advance!
Maya

align_epi_anat.py \
			-dset1 $anat_ref_path/anat_final.${subject}.MovieStability.${group}.s3.rest1+orig.BRIK.gz \
			-dset2 $rest_path/anat_final.${subject}.MovieStability.${group}.${session}.rest1+orig.BRIK.gz \
			-dset2to1 \
			-cost lpa


		3dAllineate \
			-cubic \
			-1Dmatrix_apply $data_path/anat_final.${subject}.MovieStability.${group}.${session}.rest1_al_mat.aff12.1D \
			-prefix alignTOs3_$errts_name \
			-input $errts

		3dresample \
			-master $anat_ref_path/errts.${subject}.MovieStability.${group}.s3.rest1.tproject+orig.BRIK.gz \
			-prefix alignTOs3_resampled_$errts_name \
			-input alignTOs3_$errts_name+orig.BRIK.gz

Underlay here is the reference anat_final (session 3), and overlay is anat_final of the scan I want to align (session 1) before any alignment:

Underlay here is the reference anat_final (session 3), and overlay is anat_final of the scan I want to align (session 1) after align_api_anat:

also, in the epi after 3DAllineate there is an addition of a contour line that I don't know where it comes from:
(here the overlay is the epi after 3DAllineate and resample)

This is the proc.py code that I performed to all runs:

afni_proc.py \
     -subj_id $subject.$experiment.$group.$session.$scan \
     -out_dir ${output_path}/$subject.$experiment.$group.$session.$scan.results \
     -script ${output_path}/proc.$subject.$experiment.$group.$session.$scan \
     -blocks despike tshift align volreg mask combine scale regress \
     -radial_correlate_blocks tcat volreg                      \
     -blip_forward_dset $subject.$experiment.$group.$session.AP+orig.HEAD -align_unifize_epi local \
     -blip_reverse_dset $subject.$experiment.$group.$session.PA+orig.HEAD \
     -copy_anat $subject.$experiment.$group.$session.anatMASK+orig.BRIK \
     -anat_has_skull no \
     -dsets_me_run $subject.$experiment.$group.$session.${scan}*0?+orig.HEAD \
     -echo_times 13.2 34.72 56.24 \
     -reg_echo 1                                               \
     -tcat_remove_first_trs 4                                  \
     -tshift_interp -wsinc9                                    \
     -align_opts_aea -cost lpc+ZZ -check_flip            \
     -volreg_align_to MIN_OUTLIER                              \
     -volreg_align_e2a                                         \
     -mask_epi_anat yes                                        \
     -mask_apply anat \
     -combine_method m_tedana                                    \
     -html_review_style pythonic \
     -scr_overwrite

Hi, Maya-

Taking a step back. Here is your afni_proc.py cmd, just spaced vertically:

afni_proc.py                                                                 \
    -subj_id                  $subject.$experiment.$group.$session.$scan     \
    -out_dir                  ${output_path}/$subject.$experiment.$group.$session.$scan.results \
    -script                   ${output_path}/proc.$subject.$experiment.$group.$session.$scan \
    -blocks                   despike tshift align volreg mask combine scale \
                              regress                                        \
    -radial_correlate_blocks  tcat volreg                                    \
    -blip_forward_dset        $subject.$experiment.$group.$session.AP+orig.HEAD \
    -align_unifize_epi        local                                          \
    -blip_reverse_dset        $subject.$experiment.$group.$session.PA+orig.HEAD \
    -copy_anat                $subject.$experiment.$group.$session.anatMASK+orig.BRIK \
    -anat_has_skull           no                                             \
    -dsets_me_run             $subject.$experiment.$group.$session.${scan}*0?+orig.HEAD \
    -echo_times               13.2 34.72 56.24                               \
    -reg_echo                 1                                              \
    -tcat_remove_first_trs    4                                              \
    -tshift_interp            -wsinc9                                        \
    -align_opts_aea           -cost lpc+ZZ                                   \
                              -check_flip                                    \
    -volreg_align_to          MIN_OUTLIER                                    \
    -volreg_align_e2a                                                        \
    -mask_epi_anat            yes                                            \
    -mask_apply               anat                                           \
    -combine_method           m_tedana                                       \
    -html_review_style        pythonic                                       \
    -scr_overwrite

I notice it doesn't include an align block or a tlrc block.

Are you wanting to move the EPIs before processing with afni_proc.py? That will incur extra blurring in them, because they will be regridded separately many times. I might have thought using the second anatomical as the anatomical dataset (via -copy_anat ..) would be the way to go for this?

Re. the alignment here, are any of the involved EPIs or anatomical datasets oblique? (Check using 3dinfo -obliquity ..) That can complicate this.

--pt

Hi Paul,
I want to keep the data in original space, that's why I removed align and tlrc blocks.
I don't think I fully understand what you mean with the second anatomical - should I put the anatomy of session 3 in the processing code of session 1 in -copy_anat line? will this align the epi to the other anatomy?
All raw data here is oblique, but I fix it before the proc.py - the input for copy_anat (*anatMASK) is already plumb, and the errts output is also plumb.

Maya

Hi, Maya-

You do still have an "align" block in your list of blocks in the original AP command. Do you want it there?

Re. obliquity: I expect the output of afni_proc.py to be non-oblique, as a result of processing, indeed.

Having oblique EPIs as input is fine and pretty common. Having oblique anatomicals can be fine, but can also create hassles in some cases (different software deal with obliquity differently; in concatenating transforms it has to be accounted for separately in some cases; it is ignored in some of the visualizations, to avoid blurring/resampling and to allow for direct time series viewing in the GUI still).

As another principle, it will generally be preferable to not regrid the EPIs separately, because that incurs extra blurring on them. Every regridding processing (resampling to a new grid or applying obliquity) leads to interpolation, which inherently blurs. Only things like pure translation, purging obliquity or rescaling voxels are coordinate transforms that do not lead to interpolation+blurring.

Maybe stepping back, you have data (EPI + anatomicals) in session 1 and data in session 2. You want all EPIs in the "space" of session 2; more specifically, is the final space in session 2 that of the subject EPI or that of the subect anatomical?

--pt

Hi Paul,

I think it didn't work when I removed the block completely. Should I try again without it?

I don't think it matters if the final space is the anatomical or the EPI, but I want all EPI's to be aligned. I guess the subject's anatomical from session 3 should be the better space to align to.

Thank you,
Maya

Hi,
And a follow-up question - what does the afni_proc.py do without align and volreg blocks? What should I consider when doing so?

Thanks,
Maya

Hi Maya,

There are many alignment steps that can possibly be combined with afni_proc.py. Here you seem to have blip distortion correction data, and the align and volreg blocks. And you also have -volreg_align_e2a. So at the end, everything will be aligned with the passed anatomical dataset.

If your plan is to align all of the EPI to a single anat, then you might as well just give that anat to similar afni_proc.py commands with -volreg_align_e2a. That would probably imply adding -giant_move to -align_opts_aea. This is what I would do, at least initially.

But without volreg/align/tlrc blocks, then there should simply be no registration... except that you have the distortion correction included. So later warping these afni_proc.py results would indeed incur an extra blur.

Note that some people view aligning everything to a single anat to be slightly biased, as the EPI from that anat's session will possibly start in good alignment. But if they move around like normal humans do, that might not matter so much.

-rick

Hi Rick,
It actually worked quite well now to use the other anat as input in the proc.py.

I'm aware of the bias problem and plan to use intermediate anatomy later on, so this is more of an initial step.

Thank you!
Maya