Dear afni experts.
I acquired a functional data that only covers the posterior part of the brain (see attached). I found it is very hard to align it to a T1 volume. I have several questions here:
- I tried the method here, but it did not work very well.
- Is there any method that I can use such that I can first manually align it (I typically use itksnap or the Nudge plugin in afni), then ask align_epi_anat to fine tune it? I find that align_epi_anat has the ‘-pre_matrix’ option which seems can achieve that. But I tried it also did not work very well.
- I also acquired a high-resolution T2 volume. Not sure whether it can help. I am thinking of aligning T2 to T2 and then epi to T2…
Any suggestion here?
ruyuan
Hi, Ruyuan-
What commands have you tried so far, esp. in the Nudge+“align_epi_anat.py -pre_matrix …” case?
–pt
I tried to use itk-snap to manually align epi to T1, and obtain the transformation matrix.
align_epi_anat.py -anat2epi -anat, t1
-save_skullstrip -suffix _al_junk.nii.gz
-epi epi.str, -epi_base 0 -epi_strip 3dAutomask
-volreg off’ -tshift off -anat_has_skull no -patial_coronal -pre_matrix itkxfm.1D
But it did not work. It might due to the coordinate difference between itk-snap and afni
Then I used afni Nudge plugin to manually align the epi to T1. I clicked print button and got the parameter below.
3drotate -quintic -rotate -8.78I -29.47R 5.78A -ashift -7.42S 9.39L 4.00P -prefix ??? inputdataset
Can I ask how to convert these rotation and shift numbers into a matrix file such that I can feed to -pre_matrix option in align_epi_anat.py?
Thanks.
Hi-
That align_epi_anat.py command has commas, as well as a single apostrophe, in it-- are those just copy+paste features?
If the “itkxfm.1D” file is one made by ITK, then no, it will not work-- they use a different format for rotation description.
Would you be able to upload the data sets, and we can take a look? I will PM you instructions for doing so.
–pt
Hi Ruyuan-
PTaylor and I got it working after a few tries. The major thing is to Zeropad your input. Basic flow of our test was to skullstrip your anatomical, zero pad the EPI and then align using 3dAllineate.
@SSwarper -input C1051_SurfVol.nii.gz -base MNI152_2009_template_SSW.nii.gz -subid Subj01 -skipwarp
3dZeropad -I 20 -P 20 -A 5 -prefix epi1_rs.nii.gz epi_mean_test.nii.gz
#Align anat to EPI
3dAllineate \
-base epi1_rs.nii.gz \
-input anatSS.Subj01.nii \
-prefix tmp.anat.aligned.nii.gz \
-1Dmatrix_save epi1_rs_al_12.1D \
-cost lpc \
-final wsinc5 \
-source_automask -autoweight \
-twopass \
-verb
#invert transform
cat_matvec epi1_rs_al_12.1D -I > epi2anat_12.1D
#apply inverted transform
3dAllineate -base C1051_SurfVol.nii.gz -input epi1_rs.nii.gz -1Dmatrix_apply epi2anat_12.1D -prefix epi_aligned.nii.gz
https://blog.cogneurostats.com/wp-content/uploads/2019/06/CorAlTestImage_Molfese.png
Let us know if you have other questions or troubles!
-PM
Thanks so much Peter ! It works very well. But I also have a few questions:
- Instead of 3dAllineate, I also try align_epi_anat.py but it did not align it very well. Do you suggest we should generally use 3dAllineate in partial coverage alignment?
align_epi_anat.py -anat2epi \
-anat anatSS.Subj01.nii -suffix _al_junk.nii.gz \
-epi epi1_rs.nii.gz -epi_base 0 \
-epi_strip None \
-volreg off -tshift off -anat_has_skull no
- I am also curious about the ‘-pre_matrix’ option in align_epi_anat.py. Is there any way that I can first nudge the data to perform a coarse manually alignment and then set it as the starting point for 3dAllineate or align_epi_anat to fine tune it?? I tried the nudge plugin but do not know how to feed the shift and rotation parameters (see below) to align_epi_anat as the starting point…
3drotate -quintic -rotate -8.78I -29.47R 5.78A -ashift -7.42S 9.39L 4.00P -prefix ??? inputdataset
Thanks.
align_epi_anat.py is a wrapper for 3dAllineate.-- that is, when you run align_epi_anat.py, it actually just puts together a command with specific options present for 3dAllineate.
In the AFNI_history part of the 3dinfo output for a file, you can see both. Here is an example from the afni_proc.py Bootcamp example:
[ptaylor@eomer: Mon May 20 12:23:00 2019] align_epi_anat.py -anat2epi -anat FT_anat_ns+orig -suffix _al_junk -epi vr_base_min_outlier+orig -epi_base 0 -epi_strip 3dAutomask -anat_has_skull no -check_flip -volreg off -tshift off
… translates to →
[ptaylor@eomer: Mon May 20 12:21:46 2019] {AFNI_19.1.09:linux_ubuntu_12_64} 3dAllineate -lpc -wtprefix ./FT_anat_ns_unflipped_al_junk_wtal -weight ./vr_base_min_outlier_ts_rs_ns_wt+orig -source ./FT_anat_ns_unflipped+orig -prefix ./FT_anat_ns_al_junk -base ./vr_base_min_outlier_ts_rs_ns+orig -nocmass -1Dmatrix_save ./FT_anat_ns_al_junk_mat.aff12.1D -master SOURCE -weight_frac 1.0 -maxrot 6 -maxshf 10 -VERB -warp aff -source_automask+4 -onepass
So, there are some other things set. If you want to go the align_epi_anat.py route (perhaps you are using afni_proc.py yourself with this?) then you can provide some other defaults/settings. For example, you would twopass on, instead of onepass: “-Allineate_opts -twopass”. It is also possible that the maxrot and maxshf would need to be increased-- in 3dAllineate’s defaults, the help says:
-maxrot dd = Allow maximum rotation of 'dd' degrees. Equivalent
to '-parang 4 -dd dd -parang 5 -dd dd -parang 6 -dd dd'
[Default=30 degrees]
-maxshf dd = Allow maximum shift of 'dd' millimeters. Equivalent
to '-parang 1 -dd dd -parang 2 -dd dd -parang 3 -dd dd'
[Default=32% of the size of the base image]
**N.B.: This max shift setting is relative to the center-of-mass
shift, if the '-cmass' option is used.
So, in the end, you might want to add something like this to your align_epi_anat.py command:
"-Allineate_opts -twopass -maxrot 30 -maxshf 40"
(almost like using -giant_move, but you don’t want the -cmass behavior, because you have a partial dataset)
-pt
I think we need to make some modifications to align_epi_anat.py’s functions regarding partial-coverage. So for now, I would recommend using 3dAllineate directly with the options specified.
For the nudge, I would go ahead and use the plugin, followed by 3dAllineate to do a quick alignment to get a rigid alignment (-warp shirt_rotate), and use cat_matvec to concatenate your two transforms (nudge + partial-coverage to anatomical). That’s similar to what the -pre_matrix does and would potentially reduce interpolation. That said, you may also be able to eyeball the nudge and then use 3drefit to move the origin to get things close into place.
Hi, Peter and Taylor
I tried the method on different sessions but I found this method is not quite robust. The alignment is strongly influenced by the initial starting point and alignment can easily fall into local minima. Can you elaborate more on how to manually nudge and set a good starting point for either aling_epi_anat or 3dAllineate??
I am working on some 7T data. Acquiring only a few slices is very common in ultra-high field MRI. It might be quite useful to develop some utilities to align partial coverage data.
ruyuan
Ruyuan-
We’re working on tools that are more high-field specific. Generally I use 3drefit to move the slab into an approximate position and orientation. Zeropad the functional data, and then use 3dAllineate to work the actual alignment. As I said before, DO NOT use align_epi_anat.py until we have a chance to better modify the options to deal with partial data. You’re welcome to upload more data that is troublesome and we can take a look.
-Peter
Thanks.
Yes, that is what I thought. I typically use the code below to translate the data in 3d space.
3drefit -dxorigin 20 epi.nii.gz
But I am not sure how to set the orientation using 3drefit. Especially, if I get the rotation parameters below after manually nudging the data.
3drotate -quintic -rotate -8.78I -29.47R 5.78A -ashift -7.42S 9.39L 4.00P -prefix ??? inputdataset
So the step would be
(1) manually translate and rotate data
(2) run 3dAllineate
(3) concatenate transformations (nudge + affine)
I think the rotation part is the key barrier for me here. Can you provide some code how to do that?
Best
Ruyuan
Since your last data didn’t require any nudging, can you upload the current troublesome data?
Hi guys–
Sorry to butt in, but Peter and/or Paul, I’m wondering if you recommend a similar approach to the above for getting optimal alignment between full and partial structural images? Say, for example, if Ruyuan wanted to get the best alignment between his high-res T2s and whole brain SPGR… In our case, we’re doing dynamic T1 imaging using Gadolinium and would like to have the best possible alignment between these (partial) T1s and a whole brain SPGR.
Thousand thanks…
Paul
Hi Paul-
It should work for any partial coverage situation. If you have specific data you’d like us to demo with, I’m happy to do that.
-Peter
Thanks Peter ! It takes me some time to figure it out. The method I used below is generally robust and I have tested it for several sessions.
I feel it is helpful to put it here as a reference.
# Before the nudging, two issues here
# 1. If the epi data is too far away from its target position, you might want to use the command below to move its origin (the nudge data plugin seems to clip data...)
# 3drefit -dxorigin 20 -prefix epi_shft.nii.gz epi.nii.gz
# 2. it is generally a good idea to pad the data
# !3dZeropad -I 20 -P 30 -A 30 -overwrite -prefix epi_pad.nii.gz epi_shft.nii.gz
# Then you can nudge the data manually, Once you are happy, click 'print' button. NudgeDataset prints out something as below in your terminal.
3drotate -NN -rotate 0.44I -33.99R 3.73A -ashift 1.82S 0.00L 20.30P \
-prefix tmp.epi.rotated.nii.gz -overwrite epi_pad.nii.gz
# Extract the transform of manual nudge
cat_matvec tmp.epi.rotated.nii.gz::ROTATE_MATVEC_000000 -ONELINE > tmp.init.aff12.1D
# Align the anat to the rotated epi
align_epi_anat.py -anat2epi -anat T1.nii.gz -epi tmp.epi.rotated.nii.gz \
-epi_base 0 -epi_strip 3dAutomask -tshift off -volreg off -deoblique off \
-anat_has_skull no -suffix _al -overwrite
# Combine the two transforms and invert
cat_matvec tmp.init.aff12.1D T1_al_mat.aff12.1D -ONELINE > mat.anat2epi.aff12.1D
cat_matvec mat.anat2epi.aff12.1D -I -ONELINE > mat.epi2anat.aff12.1D
# Apply the combined transform, warp epi to anat
3dAllineate -final wsinc5 -base T1.nii.gz \
-1Dmatrix_apply mat.epi2anat.aff12.1D -input epi_shft.nii.gz \
-prefix epi_al.nii.gz -overwrite
# Clean up
!rm tmp.* T1_al*
Hi Peter–I’ve been playing with your recommended approach and have achieved some cool looking but not-so-useful results. Perhaps you wouldn’t mind taking a look? Feel free to let me know where you’d like me to send the data when you get a minute.
Many thanks…
Paul
Received and replied with a link to the data. While there was a confirmation of the reply being sent to you, I don’t see anything in my SentMail folder so I’m confirming via this route.
Hi Paul-
I think much of the problem is caused by how you Z-padded the image. It looks like you were taking out slices instead of adding. My final commands to get pretty decent alignment are below. I did skull strip both anatomicals.
#strip anatomical
3dSkullStrip -input anat.nii -prefix anat_ns.nii
#z-pad low-res image
3dZeropad -I 20 -P 20 -A 20 -S 20 -L 20 -R 20 -prefix T1_ZP.nii t1_dyn_contrast_acq4.nii
#now skull strip that low-res image
3dSkullStrip -prefix T1_ZP_ss.nii -input T1_ZP.nii
#move low-res image center back
3drefit -dzorigin 20 T1_ZP_ss.nii
#perform alignment with MutualInfo because of low contrast in image
3dAllineate -base anat_ns.nii -input T1_ZP_ss.nii -master anat_ns.nii -prefix spgr_al.nii \
-1Dmatrix_save spgr_to_t1_dyn.1D -cost mi -final wsinc5 -source_automask \
-autoweight -twopass -warp shift_rotate -verb -overwrite
https://blog.cogneurostats.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-18-at-3.44.02-PM.png