Warping tck files using ANTS warps

Dear all,

Based on the documentation I tried the following sequence of commands hoping that I would be able to warp .tck files from the moving image to the fixed image.

  1. First I made a 4D file of the warp from the original 5D warp file spit out by ANTS using warpinit and Matlab.
  2. Then I ran warpcorrect 4DWarp.nii.gz 4DWarp.mif.
  3. Then I ran tcknormalise Moving.tck 4DWarp.mif MovingWarped.tck.

The tckinfo on both Moving.tck and the MovingWarped.tck is identical except for the time stamp. But the mrview does not show the tracks for aligned on the fixed image.

Is there a way to warp tck files using ANTS warps?
Thanks so much!
Nagesh

3 Likes

OK, the process isn’t documented particularly well, I have to admit… I’ll try to clarify here.

Not sure what you’re using Matlab for, but what you want to do is to generate a ‘no-warp’ image (for want of a better word) in the target space that you want to warp your tracks into - in your case, the template space:

$ warpinit some_image_in_template_space no-warp.nii

This create a 4D image (no-warp.nii) with 3 volumes. For each voxel, the 3 volumes correspond to the xyz coordinates in real space of the voxel’s location.

Then you will need to apply the warp that you have previously estimated using whatever registration package you use (ANTs in your case) to warp this image into the original space (subject space, in your case). The process for this will obviously depends on the software used for the registration. If the software can’t handle a 4D NIfTI, break up the NIfTI into a set of 3×3D volumes using the square bracket syntax:

$ warpinit some_image_in_template_space no-warp-[].nii

And warp each of those images into the original space.

At this point, you should have a 4D image (or a set of 3×3D images), where for each voxel, the 3 volumes correspond to the xyz coordinates of the location that this voxel came from in the target space. I’m assuming you’ve called this image warp.nii (or warp-0.nii, warp-1.nii, warp-2.nii if you broke it up into 3D volumes).

At this point, you can apply the warp:

$ tcknormalise original.tck warp.nii target.tck

Or if your warp was broken up into individual volumes:

$ tcknormalise original.tck warp-[].nii target.tck

This should work as-is, but you may need to play around with it a little…

3 Likes

Hi,
Maybe I can add something (I just got this to work on my system using ANTS transformations):

Step 1. Create the identity images:
warpinit FOD.mif FOD_ID[].nii

Step 2. Use ANTS to warp the IDs. If you are e.g. warping FOD images to a group template you use the regular warps. If you are warping tracks you need the inverse warps (for some reason - I used trial and error to figure it out)
for i in {0..2} do WarpImageMultiTransform 3 \ FOD_ID${i}.nii \ FOD_invmrtrixwarp${i}.nii \ -R TEMPLATE.nii.gz \ -i \ 2TEMPLATE_0GenericAffine.mat \ 2TEMPLATE_1InverseWarp.nii.gz done

Step 3. Correct and merge the IDwarps.
warpcorrect FOD_invmrtrixwarp[].nii FOD_invmrtrixwarp_corrected.mif

Step 4. Finally, normalize the tracks.
tcknormalise TRACKS.tck FOD_invmrtrixwarp_corrected.mif TRACKS_2TEMPLATE.tck

That worked for me.
/Örjan

Yes, the reason for that is that when warping images, you are pulling intensity values from the orignal space onto known positions (voxel centres) in the target space. So you need to know where a voxel in target space maps to in original space to figure out where to fetch the intensity value from (and an interpolation method to fetch values at arbitrary locations).

With streamline data, we have vertices in the original space, and we need to figure out where to push them to in the target space, So we need to know where a location in the original space maps to in the target space. As Örjan says, this is the inverse of the transformation required for images.

Hope that makes sense…

Thanks for the clarification!

Thank you Donald and Orhan so much for the help. It worked.

I am a little confused about the inverse
I think the command of tcknormalise is registering the tck form native space to standard space ,but the warp.nii is a registration form standard space to native space .Is it right?
Maybe the input of tcknormalise is a standard to native warp image,but actually the tcknormlise will invert the warp image?

Thanks

OK, tcknormalise will transform the coordinates of each vertex in the input streamline, and transform it directly into the target space (e.g. your template space). So the image provided as the warp argument to tcknormalise should basically provide a lookup for where a given position maps to in target space, given its position in the original (native) space. The simplest way to get that is to apply whatever warp you’re interested in, in whichever format your registration software expects, to an image that provides positions in the target space, given positions in the target space -this is what the warpinit command provides: the values for each voxel correspond to the position in real/scanner coordinates of that voxel. By the time that’s been warped to the original (native) space, the values in each voxel will correspond to the position of that voxel as it maps to target (template) space.

So that’s a forward transform, and is the inverse of what you’d use to transform an image to target space, as explained earlier in this thread. So in this context, to get an inverse of that transform, you would swap the original and target spaces around and repeat the process: warpinit from an image in native space, warp that to the target space, and you could then use that warp to transform tracks in template space back to native (although it’s difficult to envisage a situation where you’d need to do that). So the inverse in this case isn’t simply a matter of applying the inverse warp (using your preferred registration software) to the same warp.mif that you might have originally produced - maybe that’s the source of the confusion…?

Thank you for your patience !

Dear all,

I have a very specific question about the tcknormalise. Currently, I’m trying to use the MRtrix for the nonlinear transformation on the tractogram directly. I have been working with the HCP (Human Connectom project) diffusion MRI dataset and with the dataset ‘nonlinear_acpc_dc2standardnii.gz.’ is available which is nonlinear volume transformation from the subject’s native volume space to MNI space [Reference Paper: The minimal preprocessing pipelines for the Human Connectome Project]. This nonlinear transformation file is created using the FSL. As far as I understand, this file is appropriate for transforming the tractogram using the tcknormalise.

So far I followed the following step :

With the Wrapinit command, I first create a identity map named ''nonlinear_acpc_dc2standard.mif “from the "nonlinear_acpc_dc2standard.nii.gz” and afterwards I ran tcknormalise command with the “nonlinear_acpc_dc2standard.mif”
for transformation.

My question is following, am I doing the right step or do I need to Inverse the warp file(nonlinear_acpc_dc2standardnii.gz.) to use the tcknormalise to transform the tractogram.

Thanks in advance.

I just noticed this hadn’t been answered, thought I’d follow up in case you were still stuck?

I’m not sure exactly what you’ve done (it would be better to copy & paste the exact commands used and their full output so we can avoid any confusion), but it looks like you’ve essentially only run warpinit using the nonlinear_acpc_dc2standard.nii.gz file as the template, and then provided that file as the warp information to tcknormalise. This won’t do anything, since the warpinit command only generates an identity warp (i.e. no warp as such) in the same space as its template argument - at this stage there is no warp information at all.

Normally, you’d need to follow the instructions on this page - but this requires access to the software used to perform the registration in the first place. However, in this case you might be able to use the transformation information provided directly, although that’ll depend on exactly what information is contained in that transformation file.

The file you refer to seems to be MNINonLinear/xfms/acpc_dc2standard.nii.gz (?), and appears to consists of a displacement field. Thankfully, recent versions of MRtrix3 include the warpconvert command, which can convert that to the requisite deformation field required by tcknormalise. However, what I’m not sure about is the exact convention assumed for the HCP-supplied displacement map. Specifically: is the displacement in millimeters or voxel units? is the displacement vector relative to the image axes, or to scanner standard space? I couldn’t find a clear description from a quick cursory look through.

Thankfully, this image seems to be scanner aligned, so there should be no difference between scanner and image space (at least on the example I’ve looked at). Note the identity transform in the output of mrinfo:

$ mrinfo acpc_dc2standard.nii.gz
************************************************
Image:               "acpc_dc2standard.nii.gz"
************************************************
  Dimensions:        91 x 109 x 91 x 3
  Voxel size:        2 x 2 x 2 x 1
  Data strides:      [ -1 2 3 4 ]
  Format:            NIfTI-1.1 (GZip compressed)
  Data type:         32 bit float (little endian)
  Intensity scaling: offset = 0, multiplier = 1
  Transform:                    1           0           0         -90
                               -0           1           0        -126
                               -0           0           1         -72
  comments:          FSL5.0

However, there may be a inversion for the x component, depending on exactly what the convention is (due to the reversed stride for the x axis). Also, the voxel size is 2mm in this image, so displacements may be off by a factor of 2 is they are assumed to be in voxel units (since warpconvert will assume they are provided in millimeter units).

So if the acpc_dc2standard.nii.gz image does provide displacements in scanner space, in units of millimeters, all you’d need to do is:

warpconvert acpc_dc2standard.nii.gz -type displacement2deformation warp.nii

and use the resulting warp.nii image as the transformation for tcknormalise. However, if the displacements are actually in voxel units, you’d need to scale them by a factor of 2 first:

mrcalc acpc_dc2standard.nii.gz 2 -mult - | warpconvert - -type displacement2deformation warp.nii

If the x direction is inverted, you’d need to invert the x component of the displacement field first. Simplest way to do that would probably be:

mrconvert acpc_dc2standard.nii.gz tmp-[].nii
mv tmp-0.nii x.nii
mrcalc x.nii -neg tmp-0.nii

then:

warpconvert tmp-[].nii -type displacement2deformation warp.nii

or if on top of that the displacements are in voxel units:

mrcalc tmp-[].nii 2 -mult - | warpconvert - -type displacement2deformation warp.nii

So you’d need to try some of these commands and see whether the resulting normalised tracks correspond to what you’d expect…

Thank you for the above post @jdtournier

The following commands work fine for bringing tracts in MNI space:

sub=100307 cd /data/jet/dvp/HCP/$sub/mrtrix warp=/data/HCP_data/S900_2016_03_14/$sub/MNINonLinear/xfms/standard2acpc_dc.nii.gz warpconvert $warp -type displacement2deformation TCKwarp2MNI.nii.gz tcknormalise ComissL.tck TCKwarp2MNI.nii.gz ComissL_MNI.tck

For new users, note the selection of standard2acpc, which is counterintuitive, but this is what is needed to bring tracts in standard space.

… note the selection of standard2acpc, which is counterintuitive, …

I suspect this will be due to the fact that:

  • Non-linear warping of streamlines requires a push field: For each streamline point, read the image values at that position in the image; these define the new spatial position of that streamline point.

  • In image normalisation a pull field is used: For each voxel position in standard space, the image values within that voxel define the position from which the subject image should be read.

Hence streamlines normalisation requires the inverse field to what the file naming convention would otherwise imply.

Thank you for sharing your pipeline @DorianP
Can you however specify the MNI template you use? I’ve tried FSL 1mm template and googled with little help (found out only that HCP is using the 6th gen MNI template).
Thanks,
Lassi

Sorry for answering so late @lassibjo

Looks like the template I was using is the MNI152 from FSL. Here are the details:

filename       MNI152_T1_1mm.nii.gz

sizeof_hdr     348
data_type      INT16
dim0           3
dim1           182
dim2           218
dim3           182
dim4           1
dim5           1
dim6           1
dim7           1
vox_units      mm
time_units     s
datatype       4
nbyper         2
bitpix         16
pixdim0        0.000000
pixdim1        1.000000
pixdim2        1.000000
pixdim3        1.000000
pixdim4        1.000000
pixdim5        0.000000
pixdim6        0.000000
pixdim7        0.000000
vox_offset     352
cal_max        8000.0000
cal_min        3000.0000
scl_slope      1.000000
scl_inter      0.000000
phase_dim      0
freq_dim       0
slice_dim      0
slice_name     Unknown
slice_code     0
slice_start    0
slice_end      0
slice_duration 0.000000
time_offset    0.000000
intent         Unknown
intent_code    0
intent_name    
intent_p1      0.000000
intent_p2      0.000000
intent_p3      0.000000
qform_name     MNI_152
qform_code     4
qto_xyz:1      -1.000000  0.000000  -0.000000  90.000000
qto_xyz:2      0.000000  1.000000  -0.000000  -126.000000
qto_xyz:3      0.000000  0.000000  1.000000  -72.000000
qto_xyz:4      0.000000  0.000000  0.000000  1.000000
qform_xorient  Right-to-Left
qform_yorient  Posterior-to-Anterior
qform_zorient  Inferior-to-Superior
sform_name     MNI_152
sform_code     4
sto_xyz:1      -1.000000  0.000000  0.000000  90.000000
sto_xyz:2      0.000000  1.000000  0.000000  -126.000000
sto_xyz:3      0.000000  0.000000  1.000000  -72.000000
sto_xyz:4      0.000000  0.000000  0.000000  1.000000
sform_xorient  Right-to-Left
sform_yorient  Posterior-to-Anterior
sform_zorient  Inferior-to-Superior
file_type      NIFTI-1+
file_code      1
descrip        FSL5.0
aux_file       

Thanks for your help! It seems antsApplyTransform wasn’t warping the template as needed. Worked with FSL applywarp…
Cheers,
Lassi