align_epi_anat.py registration variability

Dear All,

I have two scans, a T1 (T.nii) with native resolution 1x1x1 mm, and a CT (CT.nii) with native resolution of 0.4375x0.4375x0.8. I have been using align_epi_anat.py to register the CT (mov) to T1 (base), with variable success. I wanted to see if there are any voxel size match/mismatch and isotropy/anisotropy rules for the inputs to align_epi_anat.py. I have been trying different voxel resolutions, because the CT is high resolution, low contrast, and MR is low resolution, high contrast. I wanted to get the middle ground:

I used the following code:

  1. @Align_Centers -base T.nii -dset CT.nii
    (2) 3dresample -input T.nii -prefix T_res.nii (-master $CT) -dxyz x1 y1 z1
    (3) 3dresample -input CT_shft.nii -prefix CT_res_shft.nii (-master $T) -dxyz x2 y2 z2
  2. align_epi_anat.py -dset1 $T -dset2 $CT -dset1_strip None -dset2_strip None -dset2to1 -suffix _done -feature_size x3 -overwrite -cost nmi -giant_move -rigid_body > status.txt

where $T is either T.nii or T_res.nii, and $CT is either CT_shft.nii or CT_res_shft.nii, where steps 2 and 3 were applied or not.

Results:The registration was good (excellent!) when CT was resliced to the T1 (-master T.nii -dxyz 1 1 1), prior to step no 4, which in turn was run with -feature_size 1.

It failed in all other instances:CT at native (anisotropic) resolution and T1 at native resolution;
T1 sliced at native CT (0.4375x0.4375x0.8) resolution
CT sliced at min native (0.4375) isotropic and T1 native (1), -feature_size 0.4375 or 1;
CT and T1 sliced at min native CT (0.4375) isotropic, -feature_size 0.4375CT sliced at 1/2 T1 resolution (0.5) isotropic, T1 native (1), -feature_size 0.5 or 1CT and T1 sliced at 1/2 T1 resolution (0.5), -feature_size 0.5 or 1All the above were tried without and with the -master option (when used on CT not used on T1, and viceversa).

So again,

  1. are there any voxel size match/mismatch and isotropy/anisotropy rules for the inputs to align_epi_anat.py, for a predictably successful registration2. regarding flag -feature_size, recommended in ‘help’ for anat to anat registrations: in the case registrations of two vols with different resolutions, which one of the two should be used as value input to the flag? Also, in case anisotropic vols are allowed as inputs without prior slicing to isotropic, which one of the dx != dy != dz should be used as input, if one decides to use the flag (or should one leave that out?)?
    Thank you,
    Octavian

Hi, Octavian-

A lot of alignment considerations are given here:
https://www.youtube.com/watch?v=PaZinetFKGY&list=PL_CD549H9kgqJ1GDXAs1BWkgEimAHZeNX

Note that a lot of deciding what to do depends on the datasets and understanding their properties, esp. in this not-so-common case of aligning a T1w volume to a CT. It would help if you could post an image of each dset (say, a sagittal one near the middle of the brain but not in the midline).

I don’t know that the voxel size matters that much in this case-- they are fairly similar. I am surprised why that would lead to a difference… I would like to understand more about these data. (The choice of aligning A->B or B->A often depends more on dataset properties, maskability, etc.; in afni_proc.py, by default we align the anatomical to the EPI, and invert the estimated transform to be used later.)

Firstly, I don’t see how/why the option is specified as this in a couple of above commands?: “-dxyz x1 y1 z1”
→ that leads to program failure for me.

What is feature_size of x3? If by that you mean “3” (mm), then that looks quite large to me.

Biggest considerations at the start are:
A) what are the relative tissues contrasts of your 2 dsets (are they similar or different)? this decides the choice of cost function(s) to start with.
→ for example, standard EPIs and T1w volumes have opposite tissue contrasts patterns, so we use lpa or lpa+ZZ as a cost function.
B) how far apart are your datasets to start? The more they overlap, the better. Can you overlay one on the other, and post the image, so we can advise?
→ if they are nooot well aligned to start, we can use @Align_Centers or another program to try to help their coordinates to be reasonable.
C) Are either/both of your dsets oblique?
→ what is the output of “3dinfo -obliquity -prefix DSET_CT DSET_MRI”?

I am curious how much detail there is in your CT? Is it a pretty homogenous dataset? That will make alignment more tricky, if so. But this depends on the detail of your specific dset.

Are both your datasets whole brain coverage, and do they both have similar coverage? If one includes a lot of neck, for example, that might determine how we use @Align_Centers to try to align them (if necessary).

–pt

Thank you, see attached figures of the original inputs. As far as the code, x1 y1 z1 (or x2 y2 z2) are simply three param values I vary during multiple resolutions tried. To give two examples:

  1. registration excellent:
    @Align_Centers -base T.nii -dset CT.nii
    3dresample -input CT_shft.nii -prefix CT_res_shft.nii -master T.nii -dxyz 1 1 1
    align_epi_anat.py -dset1 T.nii -dset2 CT_res_shft -dset1_strip None -dset2_strip None -dset2to1 -suffix _done -feature_size 1 -overwrite -cost nmi -giant_move -rigid_body > status.txt

but
2. registration failed; if 0.4375 is the smallest of the 3 dimensions of the anisotropic CT voxels
@Align_Centers -base T.nii -dset CT.nii
3dresample -input CT_shft.nii -prefix CT_res_shft.nii -master T.nii -dxyz 0.4375 0.4375 0.4375
align_epi_anat.py -dset1 T.nii -dset2 CT_res_shft -dset1_strip None -dset2_strip None -dset2to1 -suffix _done -feature_size 0.4375 -overwrite -cost nmi -giant_move -rigid_body > status.txt

same with
(step 2) 3dresample -input CT_shft.nii -prefix CT_res_shft.nii -master T.nii -dxyz 0.5 0.5 0.5
or
(step 2) 3dresample -input CT_shft.nii -prefix CT_res_shft.nii -dxyz 0.5 0.5 0.5
or slicing T1 to CT resolution dmin prior to align_epi_anat step. Essentially, any voxel size tried smaller than the original T1 one (1 1 1) fails, whether CT is sliced to its dmin, 1/2 T 1 resolution (0.5 0.5 0.5), with or without grid aligned to T1, or T1 gets sliced to CT min 0.4375, or both to 0.5,
or using -feature_size 0.4375, 0.5 or 1, depending of the final voxel sizes of the input to align_epi_anat

Another failure arises if CT is kept anisotropic:
@Align_Centers -base T.nii -dset CT.nii
align_epi_anat.py -dset1 T.nii -dset2 CT_shft.nii -dset1_strip None -dset2_strip None -dset2to1 -suffix _done -feature_size 1 -overwrite -cost nmi -giant_move -rigid_body > status.txt

Finally,
3dinfo -obliquity -prefix temp_T1.nii CT.nii
0.000 T1.nii
11.267 CT.nii

but
3dinfo -obliquity -prefix temp_T1.nii CT_shft.nii
0.000 T1.nii
0.000 CT_shft.nii

and again, there is a voxel size that leads to successful alignment (1 1 1)
Thank you, Octavian

If you’re doing ECOG, you might consider using the ALICE package that uses AFNI to align CT and MRI. Basically it’s the same method as yours except the MRI is inverted first to help make the MRI skull match the CT skull better. The thin dark layer in a T1-weighted dataset is actually the skull, and the skull is one of the few clearly identifiable structures in the CT. If the data header is correct, and the data is not distorted, then the -rigid_body option you used is one I would also recommend. The image shows some distortion on the CT, so I would check on that. The feature_size for the nmi cost function effectively controls the blurring radius (feature_size*2) for the first pass of the alignment. The default in align_epi_anat.py/3dAllineate without settings would be about 11mm radius.

https://doi.org/10.1016/j.jneumeth.2017.10.022

#!/bin/tcsh

mask the T1 mri

3dAutomask -prefix mri_am -dilate 5 -clfrac 0.35 anat+orig.

get the maximum value from the T1 dataset

set max = 3dBrickStat -max anat+orig.

invert values in the dataset 0-max → max-0

3dcalc -a anat+orig. -b mri_am+orig. -expr “step(b)*($max-a)” -prefix mri_rev

align MRI and CT

align_epi_anat.py -dset1 mri_rev+orig -dset2 CT.nii.gz -cost nmi -suffix _al2mri_rigid
-dset1_strip None -dset2_strip None -giant_move -rigid_body -dset2to1

Hi, Octavian-

Thanks for the images. As you can see the contrast in the CT image is quite minimal inside the brain, so in terms of finding “good” alignment, we are mostly talking about aligning the general shape.

This is a pretty special case of things; would you be able to share these two datasets so I can take a look more directly?

And thanks for explaining the “place holder” notation of variables; I am used to shell scripting and seeing those with dollar signs like ${x1} or $x1, or to “all caps” syntax so like X1, Y1, Z1, etc. But sorry for not recognizing that earlier.

–pt