Converting affine matrices from AFNI 3dVolReg to FSL or ITK/ANTs

I would like to use the combine the output of AFNI 3dVolReg (the .aff12.1D file) with other FSL and ANTs derived transformation in a single interpolation step. Does anyone know of a tool or script for converting AFNI transformations to FSL or ITK formats?

1 Like

From Bob Cox:

I have no idea about the other formats (FSL or ITK). However, I can tell you that AFNI transformation matrices are coordinate-based (not index-based), and
the coordinates are sign reversed in x and y from FSL — that is, AFNI uses DICOM order for xyz. So if you have an AFNI matrix

[ a b c d ]

T = [ e f g h ]
[ i j k l ]
[ 0 0 0 1 ] — this row is implicit, not in the file

then since x_FSL = [A] x_AFNI where

[ -1  0 0 0 ]

A = [ 0 -1 0 0 ]
[ 0 0 1 0 ]
[ 0 0 1 0 ] which is it’s own inverse, of course;

so the matrix that transforms x_FSL in the same way as T transforms x_AFNI is the matrix product T’ = [ A T A ], which is just

 [  a   b  -c  -d ]

T’ = [ e f -g -h ]
[ -i -j k l ]
[ 0 0 0 1 ]

Hi,

I would also like to use such a script - if it exists. Are the visitors of this thread also looking for something similar?

I’ve seen a 2011 email about the same posted on the AFNI mailing list: https://www.jiscmail.ac.uk/cgi-bin/webadmin?A2=fsl;81d877a8.1101

And again this year (2017): https://www.jiscmail.ac.uk/cgi-bin/webadmin?A2=fsl;49ee0deb.1704

It seems that the translation matrix needs to be converted from neurological (DICOM/ AFNI) to neuroimaging (FSL/SPM) by swapping the order in x and y, and corrected for where the origin is placed (therefore, this calculation is volume dependent).

BW

1 Like

We made some progress on this topic in this PR: https://github.com/poldracklab/fmriprep/pull/1354

Hi, Chris
Have you made this function? I checked the link you provide but still very confused how to use fmriprep utility to do this. Can you give more insignts here?

Thanks

Ruyuan

We are streaming out all the conversions to a submodule in nibabel: https://github.com/nipy/nibabel/pull/656/files

Cheers

@oesteban, Thanks so much. It seems that the transform module has not been released.

But I looked how you implement it. It seems that you follow Bob’s calculation, give an afni transform;

# afni xfm is in LPS+ space
afni_LPS+_xfm = [[a, b, c, d],
            [e, f, g, h],
            [i, j, k, l],
            [0,0,0,1]
# the corresponding xfm in RAS+ space
RAS+_xfm = [[a, b, -c, -d],
            [e, f, -g, -h],
            [-i, -j, k, l],
            [0,0,0,1]

Have you tested whether this conversion is correct? Actually I did some testing. For instance, I aligned volume A to volume B using afni align_epi_anat.py program and obtained afni_B2A_xfm. Then I converted it to RAS+_B2A_xfm using the rationale above. Then I simply did

import nibabel as nib
volB = nib.load('B.nii.gz')
nib.save(volB._class__(volB.get_data(), RAS+_B2A_xfm.dot(B.affine), volB.header), 'Bal2A.nii.gz')

If the afni_B2A_xfm and the conversion above are correct, I can open any visualization tool and the Bal2A.nii.gz and A.nii.gz should aligned. However, it failed on my side.

I also manually created some RAS+_xfm and then converted them back into the afni format, it also failed to produce correct alignments.

I doubt that there are some additional processing performed internally in AFNI. If that is the case, the transformation conversion above (i.e., between LPS+ and RAS+ spaces) are somehow problematic.

Have you tested it or did I miss something here???

cheers

RZ

Hi, this is all the testing I’ve done this far: https://github.com/oesteban/BIDS-X5/blob/master/01%20-%20Preparing%20images.ipynb

AFNI conversions fail when the x-forms are not aligned with the canonical axes. Chris’ original implementation in fMRIPrep enforced this alignment in a previous processing node.

@oesteban, thanks. Yeah, I did run your testing code and I noticed that the afni parts fails. My situation is, I have some transformations generated by afni and I want to somehow use them in nibabel (i.e., directly change the sform/qform in header) without resampling the data. Do you have some suggestions? I am not familar with fmriprep, how can I enforce the alignment with the canonical axes?

I really appreciated your efforts as it is important to unify the transformation across software.

Thanks!

Ruyuan

nibabel.funcs.as_closest_canonical is what you need here.