3dWarp -deoblique problem

Hi! I have a set of EPI data that were oblique, so I ran the data through the AFNI 3dWarp -deoblique command as an initial step for pre-processing. However, I encountered a problem for one participant, which ultimately resulted in my Run 1 and Run 2 task-based functional data not having the same number of voxels along the x-axis. Could you please take a look for me and let me know what might have caused this problem and how I could resolve this issue? Thank you so much!

Here is the original dimension for my Run1 and Run 2 fMRI data:
Run 1:
Data Axes Tilt: Oblique (37.000 deg. from plumb)
Data Axes Approximate Orientation:
first (x) = Right-to-Left
second (y) = Posterior-to-Anterior
third (z) = Inferior-to-Superior [-orient RPI]
R-to-L extent: -113.855 [R] -to- 102.707 [L] -step- 3.438 mm [ 64 voxels]
A-to-P extent: -188.762 [A] -to- 27.800 [P] -step- 3.438 mm [ 64 voxels]
I-to-S extent: -124.056 -to- 27.944 [S] -step- 4.000 mm [ 39 voxels]

Run 2:
Data Axes Tilt: Oblique (36.304 deg. from plumb)
Data Axes Approximate Orientation:
first (x) = Right-to-Left
second (y) = Posterior-to-Anterior
third (z) = Inferior-to-Superior [-orient RPI]
R-to-L extent: -110.531 [R] -to- 106.032 [L] -step- 3.438 mm [ 64 voxels]
A-to-P extent: -189.005 [A] -to- 27.557 [P] -step- 3.438 mm [ 64 voxels]
I-to-S extent: -125.130 -to- 26.870 [S] -step- 4.000 mm [ 39 voxels]

After I ran 3dWarp -deoblique -prefix $run.warp $run+orig, below is the resulting Run 1 and Run 2 dimension (showing different numbers of voxels on the x-axis, highlighted in red):
Run 1:
Data Axes Tilt: Plumb
Data Axes Orientation:
first (x) = Right-to-Left
second (y) = Anterior-to-Posterior
third (z) = Inferior-to-Superior [-orient RAI]
R-to-L extent: -113.855 [R] -to- 102.707 [L] -step- 3.438 mm [ 64 voxels]
A-to-P extent: -147.001 [A] -to- 121.124 [P] -step- 3.438 mm [ 79 voxels]
I-to-S extent: -125.382 [I] -to- 128.993 [S] -step- 3.438 mm [ 75 voxels]

Run 2:
Data Axes Tilt: Plumb
Data Axes Orientation:
first (x) = Right-to-Left
second (y) = Anterior-to-Posterior
third (z) = Inferior-to-Superior [-orient RAI]
R-to-L extent: -111.612 [R] -to- 108.388 [L] -step- 3.438 mm [ 65 voxels]
A-to-P extent: -149.319 [A] -to- 118.806 [P] -step- 3.438 mm [ 79 voxels]
I-to-S extent: -127.701 [I] -to- 126.674 [S] -step- 3.438 mm [ 75 voxels]

Howdy-

One thing to note at the start, if you are putting your data into afni_proc.py, I wouldn’t worry about deobliquing the EPIs. You can let afni_proc.py deal with it appropriately for you. (Perhaps you would want to deoblique the anatomicals, in a manner discussed below.)

There are 2 meanings of deoblique, with distinct consequences in either case.

  • “3dWarp -deoblique” will apply the obliquity transformation, leading to your data being blurred a bit by the interpolation that will entail. It is also possible your grid dimensions might change slightly. But the benefit is your data will be in the coordinates that they would appear in in the scanner.
  • “3drefit -deoblique” will purge the obliquity transformation, by default in a way that (unfortunately) might make your data look far away from its original coordinates in some cases. But the benefit is that the data is not regridded/interpolated, so you don’t incur a blur.

The reason why obliquity is annoying is primarily a visualization one: because applying it means interpolating the data, there would be a bit of a blur, so it is generally not applied in the GUI and therefore the dataset “appears” to be in a different location relative to other ones acquired at the same time that have no/differing obliquity. But afni_proc.py, via align_epi_anat.py, will deal with this OK if you let it. So there shouldn’t be a need to go down either of these roads.

If you do want to get rid of obliquity while both not regridding and not pushing your data far from its original coordinates, you can run the following for your DSET_IN:



3dcopy DSET_IN _tmp_dset                            # copy to BRIK/HEAD
3drefit -oblique_recenter _tmp_dset+orig         # recenter, obl transform is now just mainly rotation
3drefit -deoblique _tmp_dset+orig                    # purge obl info

# ... and then if you want a NIFTI output
3dcopy _tmp_dset+orig DSET_OUT.nii

That will purge the obliquity in a way that does not regrid/interpolate the data and it also preserves the location of the coordinate origin (x,y,z) = (0, 0, 0).

But again, I don’t think you will need to do this with your EPIs. If you have anatomical datasets with obliquity, then I would probably deoblique them with the above incantation before any processing, to not have to worry about it.

–pt

Adding on to Paul’s sage advice, the output from 3dWarp is different between the two datasets because the input is different - the two oblique angles are different. 3dWarp computes a bounding box for the output, so the boxes are slightly different sizes depending on the input grid and the oblique angles of the acquisition and transformation. You could supply a -gridset option that would serve as the master and make the dataset consistent, but it would cut off a row of voxels in this case.

Instead, follow Paul’s advice, and use afni_proc.py. That will transform datasets similarly to standard space. Or do everything in native space ignoring obliquity, as in Paul’s second example.

Hi Paul and Daniel,
Thank you so much for helping me understand the options, meaning, and consequences of deoblique, and what is the reason that caused my trouble with the participant’s data! It is SO helpful!

The data I am currently analyzing do have both oblique anatomical and EPI data with the same oblique angles for each participant (except for the one that I am having trouble with [mentioned in the initial post]). Following your suggestion, I ran the following codes on each participant’s anatomical data:
3dcopy $anat+orig $anat.deoblique
3drefit -oblique_recenter $anat.deoblique+orig
3drefit -deoblique $anat.deoblique+orig

I then put the $anat.deoblique+orig data and original EPI data (did not deoblique) through my afni.proc.py script. The script ran smoothly, and I opened @ss_review_driver and the html file to check the quality of pre-processing (e.g., the alignment of anatomy and EPI). I have attached two screenshots of what it looks like in the GUI and on the html page.

Paul, I know you mentioned that obliquity is annoying because it causes a visualization problem and would make datasets appear to be in different locations (my deobliqued anatomy and original oblique EPI). However, I also want to make sure that I am analyzing my data correctly. Is this what you would expect to see through @ss_review_driver and html output file? If yes, is there a way for me to accurately check the quality of my pre-processing (e.g., alignment)? Because currently the datasets do appear in different places visually which made it harder for quality check. If not, is there something that I did wrong?

Thank you so much!

Hi-

Can we see how the original EPI and anatomical data (no changes to obliquity) overlay when you run this command:


@djunct_overlap_check -ulay DSET_ANAT -olay DSET_EPI -prefix check_olap

? That should create 2 images: one with obliquity ignored (which will likely have poor overlap) and then one where all obliquity is applied (called _DEOB). The question will be, how well do the data overlap when obliquity is applied? If they overlap well, then great.

Let’s start with that, before getting into the EPI-anatomical alignment failure. (And actually, your APQC HTML should contain essentially these images in the vorig section, but I would like to see as well before the deoblique-while-preserving-coordinate-origin, to be sure).

–pt

Thank you very much, Paul!

I tried to run the @djunct_overlap_check command, but the terminal printed out “command out found”. I took a look at the afni folder on our server, and the command (file) was not there. I tried to google how to resolve this issue but was not able to find much information. Are there any packages/dependencies that I should install?

–Zehua

Hi, Zehua-

What is your AFNI version?


afni -ver

-pt

Overall, I would probably let afni_proc.py handle all this. If you put the exact afni_proc.py command you used, then we can advise. The obliquity that you are working to remove is used to align the data and included in the transformations. The EPI output will be put onto the same grid as the anatomical but with a reduced resolution. One important advantage is the data has only one interpolation.

With a 3dWarp transformation, you will get at least one more interpolation, and consequently, smoother data. It will still work, but you would just make the gridset option the output from the first run. If, on the other hand, you remove the obliquity information from the header with 3drefit, then you would add “-giant_move” to your “-align_opts_aea” in your afni_proc.py command.

Hi Paul,

We just asked our department to update the AFNI version from 20.2.14 to 23.0.07 last week. The version 20.2.14 is still the default, but I can opt to use the 23.0.07 version (via module load afni/23.0.07). Please let me know if we are missing anything! Below are the codes that I typed in the terminal to check our default version and switch to the most updated version.(I will also post the exact afni.proc.py script that I am using in another post in response to Daniel).

hippocampus:~: afni -ver
Precompiled binary linux_openmp_64: Aug 21 2020 (Version AFNI_20.2.14 ‘Aulus Vitellius’)
hippocampus:~: module load afni/23.0.07

The following have been reloaded with a version change:

  1. afni/20.2.14 => afni/23.0.07

hippocampus:~: @djunct_overlay_check
@djunct_overlay_check: Command not found.

Hi Daniel and Paul,

Below are the commands (including the afni.proc.py commands) that I used on my deobliqued anatomical data and original oblique EPI data for pre-processing. Thank you both again so much for helping me with this!

@Align_Centers -cm
-base …/MNI152_T1_2009c+tlrc
-dset T1.deoblique+orig
-child Encoding1+orig Encoding2+orig

echo $name "Running SSwarper"		

@SSwarper
-input T1.deoblique_shft+orig
-base …/MNI152_2009_template_SSW.nii.gz
-subid ${name}
-giant_move

echo $name “Running afni_proc.py”
afni_proc.py
-subj_id $name
-copy_anat anatSS.${name}.nii
-anat_has_skull yes
-anat_follower anat_w_skull anat T1.deoblique_shft+orig
-dsets Encoding1_shft+orig Encoding2_shft+orig
-blocks tshift align tlrc volreg blur mask scale regress
-align_opts_aea -cost lpc+ZZ -check_flip
-align_unifize_epi yes
-tlrc_base …/MNI152_2009_template_SSW.nii.gz
-tlrc_NL_warp
-tlrc_NL_warped_dsets
anatQQ.${name}.nii
anatQQ.${name}.aff12.1D
anatQQ.${name}_WARP.nii
-volreg_align_to MIN_OUTLIER
-volreg_align_e2a
-volreg_tlrc_warp
-mask_epi_anat yes
-blur_size 6.0
-blur_in_automask
(omit -regress commands …)
-execute

My advice is skip the @Align_Centers step and the previous 3dWarp steps you had used. Try with just the @SSwarper and afni_proc.py command.

If you do keep these other steps, then try to add “-giant_move” to the -align_opts_aea line.

That is great that you could update the local AFNI, and the name of the program is:


@djunct_overlap_check

(not @adjunct_overlay_check). Please see if that works?

–pt

Hi Paul and Daniel,

So sorry that it took me a while to respond! I have been getting support from our IT department to get the most updated AFNI working on our server. The @djunct_overlay_check command did not exist in the older version of AFNI folder, but it’s now finally working with the update! I ran this command on some of my participants, I have attached sample outputs from 2 of them (151204 & 151422_overlap_check.PNG). I also put the check_olap.jpg and check_olap_DEOB.jpg side by side (is check_olap_DEOB.jpg showing how anatomy and EPI overlap after both of them are deobliqued?)

I also tried the two options that Daniel provided: 1) skip the @Align_Centers step and the previous 3dWarp steps used, and just run @SSwarper and afni_proc.py command. The skullstrip somehow failed during the pre-processing; 2) I still de-obliqued the anatomy, but left the EPI data oblique, and then added “-giant_move” to the -aligh_opts_aea line. This method worked, and I think it solved the alignment issue that I was seeing through @ss_review_driver?! (151422_review_driver.PNG)

Thank you both so much for helping me patiently with this issue! I do have two more trouble-shooting questions regarding this first participant (151204) related to skull-strip and anatomy-EPI alignment issues if that’s okay! (Sorry I have to explain the problems in another post as this post only allows for two attachments).

(continued from last post) As I was looking at QC_anatSS.151204.jpg, I noticed a skull-stripping issue - it seems that small bits of the cortex were being left-out/cut-off (emphasized using yellow circles). The skullstrip problem also seems to affect the anatomy-EPI alignment (screenshot showing anatomy -EPI alignment through @ss_review_driver)? I have searched some online resources, and learned that using “push_to_edge” with 3dSkullStrip is a potential solution. However, I am not sure how to incorporate this solution into the @SSWarper step, or my afni.proc.py script … Or is there any other option that I can specify in my afni.proc.py script to make the skullstrip less aggressive on this participant? Or if there is more than a skullstrip problem?

I apologize for asking many basic questions… this is my first time learning how to independently analyze and troubleshoot the data, and really want to understand the problems and learning how to deal with them the right way. Thank you so much again for your patience!

Looks like you have made good progress. The initial skull stripping in @SSwarper is mildly aggressive by default, but it combines with the template alignment to create something more filled in. You can dilate the skullstrip mask or even manually fix the mask and feed that back into a 2nd run through of @SSwarper. You can change the options for the 3dSkullstrip command used in @SSwarper with -SSopt. Alternatively, 3dSkullstrip separately to create the mask and use that as input.

Hi Daniel,

Thank you so much for your guidance! I have finally figured out how to edit the skull-stripped volume/mask and tried some other things, but have a couple of follow-up questions.

For editing the skull-stripped volume/mask, should I use anatS.subID.nii (first pass skull-stripped output) or anatSS.subID.nii (second pass skull-stripped output)? Also, I couldn’t figure out how to feed the fixed/edited volume/mask back into a 2nd run through of @SSwarper to solve the skull-strip problem. Could you please give me some guidance on how to properly do that?

I tried the following ways but none of them worked. 1) After getting the edited skullstripped volume, I tried using that as an input for @SSwarper and added the “-init_skullstr_off” option; 2) I also tried using the “-mask_ss MSS” option and supplied an edited skull-stripped mask (as well as a skull-stripped mask using FSL). But both of these options seem to give me the exact same result/skull-strip problems. I guess this might be because both of these options only apply to the first-pass of skull-stripping (per the AFNI help guide)? (Is there a way to turn-off or skip the second pass of skull-stripping? I think the answer is no and probably would defeat the purpose of @SSwaprer, but just out of curiosity…)

One more thing that I tried is to skull-strip this particular participant through FSL and use the output volume as an input for afni.proc.py and skip the @SSwarper step. In the afni.proc.py script, I just let “-tlrc_NL_warp” do its job and grayed out “-tlrc_NL_warped_dsets”. This seems to help. Is this also an acceptable way of solving the problem?

Thank you so much for your patience!

With a mask dataset as input, you would not use the -init_skullstr_off option. See the example 3 in the current @SSwarper help for how to use an external mask dataset as input. The mask provides a replacement for the initial skullstripping step. Voxels included in that mask should be included in the output datasets. The default nonlinear warping in afni_proc.py will work too, but it’s a little different because of the skullstripping in @SSwarper and the default affine alignment in step.

Thank you very much Daniel! I did try supplying an external mask (generated through doing skull-stripping in FSL) as input following the @SSwarper example 3. The voxels included in the mask are indeed included in the anatS.ID.nii output (first pass of skull-stripping) but additional voxels are being cut-off during the second pass of skull-stripping in the anatSS.ID.nii output (I attached a screenshot comparing the two outputs). Therefore, my skull-stripping problem still persists. I don’t know what else I am missing…

If there is no way to skip the second-round of skull-stripping that inevitably causes a problem for skull-stripping, I will just skip the @SSwarper step, do skull-strip separately, and uses the default nonlinear warping in afni_proc.py for this particular participant? I also just want to make sure that it is okay for one participant’s data to be processed slightly different than the rest of the participants.

Thank you so much again!

–Zehua