nipreps / fmriprep

fMRIPrep is a robust and easy-to-use pipeline for preprocessing of diverse fMRI data. The transparent workflow dispenses of manual intervention, thereby ensuring the reproducibility of the results.
https://fmriprep.org
Apache License 2.0
637 stars 295 forks source link

func not aligned to T1w in space-T1w for AFNI #954

Closed mvdoc closed 4 years ago

mvdoc commented 6 years ago

Hi all, maybe I'm confused, but I would expect the EPIs in space-T1w to be aligned to the T1w_preproc.nii.gz. However, according to AFNI this is not the case, because the T1w is oblique (and has Template Space equal to ORIG) , while the EPIs are de-obliqued (Template Space = TLRC). Am I missing something obvious here? Thanks!

The preprocessing was run with fmriprep 1.0.3, with time-slicing correction and fieldmap correction.

This is the output of 3dinfo for the preprocessed anatomical:

$ 3dinfo ../../../derivatives/fmriprep/sub-sid000005/ses-famfirst/anat/sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc.nii.gz
++ 3dinfo: AFNI version=AFNI_17.0.18 (Mar 29 2017) [64-bit]

Dataset File:    ../../../derivatives/fmriprep/sub-sid000005/ses-famfirst/anat/sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc.nii.gz
Identifier Code: NII_DAj2nsNyWS6EEMIeUcLgSw  Creation Date: Tue Jan 30 13:42:42 2018
Template Space:  ORIG
Dataset Type:    Anat Bucket (-abuc)
Byte Order:      LSB_FIRST {assumed} [this CPU native = LSB_FIRST]
Storage Mode:    NIFTI
Storage Space:   50,331,648 (50 million [mega]) bytes
Geometry String: "MATRIX(-0.89991,-0.002785,-0.01328,85.69025,0.00732,-0.867079,-0.356401,126.7146,-0.010775,-0.356471,0.867011,-95.06398):192,256,256"
Data Axes Tilt:  Oblique (22.360 deg. from plumb)
Data Axes Approximate Orientation:
  first  (x) = Left-to-Right
  second (y) = Posterior-to-Anterior
  third  (z) = Inferior-to-Superior   [-orient LPI]
R-to-L extent:   -86.211 [R] -to-    85.690 [L] -step-     0.900 mm [192 voxels]
A-to-P extent:  -112.348 [A] -to-   126.715 [P] -step-     0.938 mm [256 voxels]
I-to-S extent:   -95.064 [I] -to-   143.999 [S] -step-     0.938 mm [256 voxels]
Number of values stored at each pixel = 1
  -- At sub-brick #0 '?' datum type is float

And this for one of the functionals:

3dinfo ../../../derivatives/fmriprep/sub-sid000005/ses-famfirst/func/sub-sid000005_ses-famfirst_task-fam1back_run-01_bold_space-T1w_preproc.nii.gz
++ 3dinfo: AFNI version=AFNI_17.0.18 (Mar 29 2017) [64-bit]
** AFNI converts NIFTI_datatype=4 (INT16) in file ../../../derivatives/fmriprep/sub-sid000005/ses-famfirst/func/sub-sid000005_ses-famfirst_task-fam1back_run-01_bold_space-T1w_preproc.nii.gz to FLOAT32
     Warnings of this type will be muted for this session.
     Set AFNI_NIFTI_TYPE_WARN to YES to see them all, NO to see none.

Dataset File:    ../../../derivatives/fmriprep/sub-sid000005/ses-famfirst/func/sub-sid000005_ses-famfirst_task-fam1back_run-01_bold_space-T1w_preproc.nii.gz
Identifier Code: NII_rweNOwytG0xdyvva2h0cbw  Creation Date: Tue Jan 30 13:43:09 2018
Template Space:  TLRC
Dataset Type:    Echo Planar (-epan)
Byte Order:      LSB_FIRST {assumed} [this CPU native = LSB_FIRST]
Storage Mode:    NIFTI
Storage Space:   290,111,360 (290 million [mega]) bytes
Geometry String: "MATRIX(-2.5,0,0,70.69025,0,-2.5,0,78.11269,0,0,2.5,-75.52227):58,77,58"
Data Axes Tilt:  Plumb
Data Axes Orientation:
  first  (x) = Left-to-Right
  second (y) = Posterior-to-Anterior
  third  (z) = Inferior-to-Superior   [-orient LPI]
R-to-L extent:   -71.810 [R] -to-    70.690 [L] -step-     2.500 mm [ 58 voxels]
A-to-P extent:  -111.887 [A] -to-    78.113 [P] -step-     2.500 mm [ 77 voxels]
I-to-S extent:   -75.522 [I] -to-    66.978 [S] -step-     2.500 mm [ 58 voxels]
Number of time steps = 280  Time step = 1.25000s  Origin = 0.00000s
  -- At sub-brick #0 '?' datum type is float
  -- At sub-brick #1 '?' datum type is float
  -- At sub-brick #2 '?' datum type is float
** For info on all 280 sub-bricks, use '3dinfo -verb' **

This is the output of 3dinfo on the original files

anatomical:

$ 3dinfo anat/sub-sid000005_ses-famfirst_acq-MPRAGE_T1w.nii.gz
++ 3dinfo: AFNI version=AFNI_17.0.18 (Mar 29 2017) [64-bit]

Dataset File:    anat/sub-sid000005_ses-famfirst_acq-MPRAGE_T1w.nii.gz
Identifier Code: NII_OYQWWTbPz9JZWuTghQngmw  Creation Date: Tue Jan 30 13:41:23 2018
Template Space:  ORIG
Dataset Type:    Anat Bucket (-abuc)
Byte Order:      LSB_FIRST {assumed} [this CPU native = LSB_FIRST]
Storage Mode:    NIFTI
Storage Space:   25,165,824 (25 million [mega]) bytes
Geometry String: "MATRIX(-0.89991,-0.002785,-0.01328,85.69025,0.00732,-0.867079,-0.356401,126.7146,-0.010775,-0.356471,0.867011,-95.06398):192,256,256"
Data Axes Tilt:  Oblique (22.360 deg. from plumb)
Data Axes Approximate Orientation:
  first  (x) = Left-to-Right
  second (y) = Posterior-to-Anterior
  third  (z) = Inferior-to-Superior   [-orient LPI]
R-to-L extent:   -86.211 [R] -to-    85.690 [L] -step-     0.900 mm [192 voxels]
A-to-P extent:  -112.348 [A] -to-   126.715 [P] -step-     0.938 mm [256 voxels]
I-to-S extent:   -95.064 [I] -to-   143.999 [S] -step-     0.938 mm [256 voxels]
Number of values stored at each pixel = 1
  -- At sub-brick #0 '?' datum type is short

functional:

$ 3dinfo func/sub-sid000005_ses-famfirst_task-fam1back_run-01_bold.nii.gz
++ 3dinfo: AFNI version=AFNI_17.0.18 (Mar 29 2017) [64-bit]

Dataset File:    func/sub-sid000005_ses-famfirst_task-fam1back_run-01_bold.nii.gz
Identifier Code: NII__b-iLgduU1F1pHHublcI8g  Creation Date: Tue Jan 30 13:41:38 2018
Template Space:  ORIG
Dataset Type:    Echo Planar (-epan)
Byte Order:      LSB_FIRST {assumed} [this CPU native = LSB_FIRST]
Storage Mode:    NIFTI
Storage Space:   289,013,760 (289 million [mega]) bytes
Geometry String: "MATRIX(2.499738,-0.013961,-0.033383,-122.5418,-0.020335,-2.449777,-0.498176,101.9774,0.029931,-0.498395,2.449634,-47.96387):96,96,56"
Data Axes Tilt:  Oblique (11.520 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:  -122.542 [R] -to-   114.958 [L] -step-     2.500 mm [ 96 voxels]
A-to-P extent:  -135.523 [A] -to-   101.977 [P] -step-     2.500 mm [ 96 voxels]
I-to-S extent:   -47.964 [I] -to-    89.536 [S] -step-     2.500 mm [ 56 voxels]
Number of time steps = 280  Time step = 1.25000s  Origin = 0.00000s
  -- At sub-brick #0 '?' datum type is short
  -- At sub-brick #1 '?' datum type is short
  -- At sub-brick #2 '?' datum type is short
** For info on all 280 sub-bricks, use '3dinfo -verb' **
chrisgorgo commented 6 years ago

It seems that this is just an issue with the code field in the header (which probably should be fixed). Have you tried loading them in the same viewer and assessing the coregistration?

mvdoc commented 6 years ago

@chrisfilo yes, the coregistration looks fine in FSLEyes. but it's impossible to visualize the coregistration in AFNI because of the different template spaces

mvdoc commented 6 years ago

Here's the header info:

anat

contematto@head1 /data/famface_angles/derivatives103/fmriprep/sub-sid000005/ses-famfirst/anat (master) $ fslhd sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc.nii.gz | grep form
qform_name     Aligned Anat
qform_code     2
qform_xorient  Left-to-Right
qform_yorient  Posterior-to-Anterior
qform_zorient  Inferior-to-Superior
sform_name     Scanner Anat
sform_code     1
sform_xorient  Left-to-Right
sform_yorient  Posterior-to-Anterior
sform_zorient  Inferior-to-Superior

func

contematto@head1 /data/famface_angles/derivatives103/fmriprep/sub-sid000005/ses-famfirst/anat (master) $ fslhd ../func/sub-sid000005_ses-famfirst_task-fam1back_run-01_bold_space-T1w_preproc.nii.gz | grep form
qform_name     Aligned Anat
qform_code     2
qform_xorient  Left-to-Right
qform_yorient  Posterior-to-Anterior
qform_zorient  Inferior-to-Superior
sform_name     Aligned Anat
sform_code     2
sform_xorient  Left-to-Right
sform_yorient  Posterior-to-Anterior
sform_zorient  Inferior-to-Superior
descrip        xform matrices modified by FixHeaderApplyTransforms (niworkflows v0.2.4).
chrisgorgo commented 6 years ago

Thanks for reporting. Obviously it's problematic if the images don't work with AFNI viewers. Could you verify that changing sform_code to 2 in func fixes this issue (without breaking things with regards to FSL)?

@effigies you might want to have a look at this as well.

effigies commented 6 years ago

So one issue there is that the qform code in your T1w_preproc should probably be 1, as well. I doubt that will make a difference to your problem, but for consistent treatment across software, we try keep the qforms and sforms synced.

The bigger issue is that AFNI doesn't respectNIFTI_XFORM_ALIGNED_ANAT. We run into this issue when using AFNI tools, because they convert to BRIK+HEAD, operate, and then make a wild stab at reconstructing NIFTI affines because it threw that information out in the conversion.

If I'm not mistaken, AFNI treats every space other than ORIG as non-oblique, right? And I think the only way to get that from a NIFTI is to use NIFTI_XFORM_SCANNER_ANAT, which means to get this to work, we'd need to declare all preprocessed outputs as unaligned. While this may not break other software packages, it certainly would be standard-non-conformant.

Please correct me if I'm wrong.

mvdoc commented 6 years ago

@effigies setting qform and sform to 1 doesn't let me overlay the EPI on top of the anatomical, because of the different template spaces.

I'm not sure about AFNI considering all non-ORIG spaces as non-oblique. The info from the files that I pasted above show that the TLRC is plumb (non-oblique). (EDIT: I meant to say that I can de-oblique the ORIG anyway, while preserving the template space as ORIG...my head is spinning).

The way I found to make AFNI happy wrt alignment (and thus visualize it co-registered) is

  1. Fix the sform_code in the anatomical and set it to 2
  2. Run 3dWarp -deoblique anat.nii.gz

Only doing 1. lets me overlay epi to anat, but they look off. Doing both 1. and 2. makes the co-registration look fine in both FSLEyes and AFNI. I'm not sure though if deobliquing is reslicing stuff, and thus it makes the alignment to the surfaces off now.

chrisgorgo commented 6 years ago

I think deobliquing is reslicing - so we should avoid it.

chrisgorgo commented 6 years ago

However if we could combine deobliquing with other transformations (without adding additional interpolation steps) that would be fine.

effigies commented 6 years ago

I don't think it should affect the alignment to the surfaces; it presumably compensates for the rotation in the affine matrix. The surfaces are defined in RAS space, not with respect to a particular set of voxels.

To be clear, you set the qform and sform to 1 in the BOLD or the anatomical? If the anatomical, I meant you should try it on the BOLD. If the BOLD, then I have zero clue how template spaces work in AFNI. The qform and sform codes are, as far as I understood, the NIFTI equivalent of the template spaces, so setting both to 1 should declare everything ORIG. (Whether ORIG is a common template space is another question...)

mvdoc commented 6 years ago

@effigies to be clear I did the following

  1. set the sform/qform of anat to 1: this makes it impossible to overlay EPI to anat
  2. set the sform/qform of anat to 2: can overlay EPI to anat but they're out of alignment because the anat is oblique
  3. set the sform/qform of func and anat to 1: identical results as 2.

Short script for reproducibility and output follows

#!/bin/bash

ANAT=sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc.nii
FUNC=sub-sid000005_ses-famfirst_task-fam1back_run-01_bold_space-T1w_preproc.nii

# Show qform and sform for anat
echo "ANAT qform/sform"
nifti_tool -disp_hdr -infiles $ANAT | grep form_code

echo "FUNC qform/sform"
nifti_tool -disp_hdr -infiles $FUNC | grep form_code

# Set sform/qform of anat to 1
echo "Setting sform/qform of ANAT to 1 (Scanner)"
ANATFIX="${ANAT/preproc/preproc_fixhdr1}"
cp -v $ANAT $ANATFIX
nifti_tool -mod_hdr -overwrite -infiles $ANATFIX -mod_field sform_code 1 -mod_field qform_code 1
echo "ANAT qform/sform"
nifti_tool -disp_hdr -infiles $ANATFIX | grep form_code

# Set sform/qform of anat to 2
echo "Setting sform/qform of ANAT to 2 (Aligned)"
ANATFIX="${ANAT/preproc/preproc_fixhdr2}"
cp -v $ANAT $ANATFIX
nifti_tool -mod_hdr -overwrite -infiles $ANATFIX -mod_field sform_code 2 -mod_field qform_code 2
echo "ANAT qform/sform"
nifti_tool -disp_hdr -infiles $ANATFIX | grep form_code

# Set functional to 1
echo "Setting sform/qform of ANAT to 1 (Scanner)"
FUNCFIX="${FUNC/preproc/preproc_fixhdr1}"
cp -v $FUNC $FUNCFIX
nifti_tool -mod_hdr -overwrite -infiles $FUNCFIX -mod_field sform_code 1 -mod_field qform_code 1
echo "FUNC qform/sform"
nifti_tool -disp_hdr -infiles $FUNCFIX | grep form_code

Output:

ANAT qform/sform
  qform_code           252      1    2
  sform_code           254      1    1
FUNC qform/sform
  qform_code           252      1    2
  sform_code           254      1    2
Setting sform/qform of ANAT to 1 (Scanner)
sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc.nii -> sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc_fixhdr1.nii
ANAT qform/sform
  qform_code           252      1    1
  sform_code           254      1    1
Setting sform/qform of ANAT to 2 (Aligned)
sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc.nii -> sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc_fixhdr2.nii
ANAT qform/sform
  qform_code           252      1    2
  sform_code           254      1    2
Setting sform/qform of ANAT to 1 (Scanner)
sub-sid000005_ses-famfirst_task-fam1back_run-01_bold_space-T1w_preproc.nii -> sub-sid000005_ses-famfirst_task-fam1back_run-01_bold_space-T1w_preproc_fixhdr1.nii
FUNC qform/sform
  qform_code           252      1    1
  sform_code           254      1    1
rmarkello commented 6 years ago

Apologies for jumping in, and this doesn't resolve the larger issue with the qform/sform codes, but if you're sure the data are coregistered as desired then you can use 3drefit -deoblique anat.nii.gz instead of 3dWarp -deoblique anat.nii.gz. The latter, as mentioned, reslices the data (and can change the dimensions), but the former only modifies the transformation matrix in the header (changing the srow_* and quatern_* values), which may be warranted under certain circumstances.

Wrt to @effigies:

If I'm not mistaken, AFNI treats every space other than ORIG as non-oblique, right?

Not necessarily. You can reset the space to a non-ORIG option (in AFNI terminology: ANAT, TLRC, or MNI) and still have an oblique dataset. It would just be rare to have reset the qform/sform codes on a dataset without applying ANY transform to it, and any transform should reslice (thereby deoblique-ing) the dataset.

mvdoc commented 6 years ago

I did try with 3drefit -deoblique, but in this case the func and anat are not aligned :( So I wonder what FSLEyes is doing to show them co-registered (or conversely, what AFNI is not doing...)

effigies commented 6 years ago

Okay. I was skeptical that modifying the affines without reslicing the data will keep our images in register, and it seems I was right.

I did run into a similar issue in the Connectome Workbench a while back, with datasets with an oblique anatomical image. They just have a checkbox, which I suppose means that it resamples the image on-the-fly to make overlaying possible. Perhaps AFNI just doesn't do that?

mvdoc commented 6 years ago

So after some tests and reasoning, I think it's an AFNI issue (or feature?). Here's my reasoning, please correct me if I'm wrong.

For AFNI, an oblique dataset is a dataset that has a rotation with respect to the cardinal axes (scanner coordinates). By looking at the AFNI source code, it computes obliquity based on the affine. The s/qform_code are only used to figure out what the template space is (ORIG/TRLC).

My anatomical scans have a rotation right off the scanner because of how the scanner is placing the box. FMRIPREP of course doesn't touch the orientation of the anatomical, but aligns the EPI to the anatomical. The resulting aligned EPI is "plumb" in AFNI terminology (i.e. the affine is not a rotation).

The AFNI viewer seems to load the volume without applying the affine first, thus it assumes that whatever is loaded must be already aligned to cardinal axes (scanner coordinates). If it detects a mismatch between the sform_code of the underlay and overlay (thus inferring different template spaces), it won't let overlay them.

Loading the images both with FSLEyes and nibabel shows that the anat and func are indeed aligned in ijk space without further reslicing.

At this point, I'm not sure if this is on you guys. Solving the problem for AFNI would mean that the anatomical needs to be "de-obliqued" at the beginning of the pipeline (with 3dWarp -deoblique), but as @chrisfilo pointed out this implies reslicing the anatomical. For me, this issue can be closed, as in my mind it mostly depends on AFNI's behavior.

effigies commented 6 years ago

I agree this sounds like an AFNI problem, though if it's something they won't fix, we may still want to consider it.

De-obliquing the anatomical might not be too big a deal, at least in theory. Assuming we want to give FreeSurfer the un-de-obliqued image, there could be some trickiness, since we also feed in the skull-stripped image after autorecon1. (Might actually already be solved since we register the T1.mgz and T1w_preproc.nii.gz.)

oesteban commented 6 years ago

Related poldracklab/niworkflows#221

mvdoc commented 6 years ago

UPDATE: I figured out a pipeline to make AFNI see the anatomical and the EPIs aligned. It requires deobliquing the anatomical, that is reslicing. But at least now I can visualize everything in AFNI :-)

  1. Deoblique the anatomical 3dWarp -deoblique -prefix anat_deoblique.nii anat.nii.gz 2. Change the view for the deobliqued file 3drefit -view tlrc anat_deoblique.nii( --> for some reason AFNI still thinks this is orig, so step 3. is necessary)
  2. Change the nifti header for the anatomical and set qform and sform to 2 nifti_tool -mod_hdr -mod_field qform_code 2 -mod_field sform_code 2 -infile anat_deoblique.nii -prefix anat_deoblique_tlrc.nii
chrisgorgo commented 6 years ago

Maybe we can fake this - I wonder what changes to the header steps 1 and 2 make.

mvdoc commented 6 years ago

Thanks for the question @chrisfilo :-) it made me realize that step 2 didn't really do anything, so all is needed is a) deobliquing (i.e., reslicing to cardinal coordinates, no rotation) and b) setting qform and sform to 2 in the anatomical after deobliquing.

chrisgorgo commented 6 years ago

It would be interesting to see the pre/post deobliquing diff of headers.

mvdoc commented 6 years ago

there you go :)

$ diff anat_hdr.txt anat_deoblique_hdr.txt
2c2
< N-1 header file '../../fmriprep/sub-sid000005/ses-famfirst/anat/sub-sid000005_ses-famfirst_acq-MPRAGE_T1w_preproc.nii.gz', num_fields = 43
---
> N-1 header file 'anat_deoblique.nii', num_fields = 43
14c14
<   dim                   40      8    3 192 256 256 1 1 1 1
---
>   dim                   40      8    3 197 350 351 1 1 1 1
22,24c22,24
<   pixdim                76      8    1.0 0.900004 0.9375 0.9375 0.0 0.0 0.0 0.0
<   vox_offset           108      1    352.0
<   scl_slope            112      1    1.0
---
>   pixdim                76      8    1.0 0.900004 0.900004 0.900004 0.0 0.0 0.0 0.0
>   vox_offset           108      1    3360.0
>   scl_slope            112      1    0.0
37c37
<   qform_code           252      1    2
---
>   qform_code           252      1    1
39,47c39,47
<   quatern_b            256      1    -0.193777
<   quatern_c            260      1    0.006661
<   quatern_d            264      1    -0.00283
<   qoffset_x            268      1    -85.690247
<   qoffset_y            272      1    -126.7146
<   qoffset_z            276      1    -95.06398
<   srow_x               280      4    0.89991 0.002785 0.01328 -85.690247
<   srow_y               296      4    -0.00732 0.867079 0.356401 -126.7146
<   srow_z               312      4    -0.010775 -0.356471 0.867011 -95.06398
---
>   quatern_b            256      1    0.0
>   quatern_c            260      1    0.0
>   quatern_d            264      1    1.0
>   qoffset_x            268      1    90.49987
>   qoffset_y            272      1    185.630844
>   qoffset_z            276      1    -188.499954
>   srow_x               280      4    -0.900004 -0.0 -0.0 90.49987
>   srow_y               296      4    -0.0 -0.900004 -0.0 185.630844
>   srow_z               312      4    0.0 0.0 0.900004 -188.499954
chrisgorgo commented 6 years ago

Ok - one thing I can think of trying is to zero non diagonal elements of the affine matrix of the T1w image prior to coregistration with the BOLD image (and save that as T1w_preproc). This should 'fake' deobliquing without the need for interpolation.

I wonder what @afni-rwcox thinks would be the best way to do this.

pjkohler commented 6 years ago

Was any further progress ever made on this? What is the current recommendation for those of us who want to view fmriprep output in AFNI?

effigies commented 6 years ago

Hi @pjkohler, we have not modified the way that T1w images are produced. I don't believe we have a current recommendation, but if AFNI is not displaying your images correctly, I would probably recommend using another tool like freeview or FSLeyes.

emdupre commented 6 years ago

Just to ping that @afni-rickr might have thoughts here on the best way to go about this !

afni-rickr commented 6 years ago

Hi @mvdoc and @emdupre, Yes, this is a long-term aspect of the afni GUI that never been dealt with. The GUI does not resample the data (to apply an obliquity transformation) live. We should do that (suma does, afni does not). So in this case, since the anat is oblique, the obliquity transformation should actually be applied. For example: 3dWarp -deoblique -prefix dset_card.nii.gz dset_oblique.nii.gz The result will cardinal, but with the data where it belongs. Sorry for the confusion.

effigies commented 6 years ago

@afni-rickr To be clear, 3dWarp -deoblique will reslice the data to ensure the same RAS coordinates refer to the same values (modulo interpolation), but with RAS now aligned with (some permutation of) IJK?

I ask because I feel like I've seen some cases where "deoblique" is used to mean diagonalizing the affine matrix without modifying the data, which would be changing the space.

afni-rickr commented 6 years ago

@effigies That is right, 3dWarp -deoblique actually moves the data around (according to the oblique transformation) and resamples it on the (originallly approximated) cardinal grid. The notion of deobliquing where the data is not modified is what 3drefit -deoblique would do, just truncating any oblique angles to the nearest cardinal grid (which is what the GUI was doing).

afni-dglen commented 6 years ago

In the afni GUI, oblique data is shown with an ijk->xyz transformation using the closest cardinal transformation. The data will appear "untilted". As Rick said, there are few operations available:

  1. Replace the oblique transformation in the header with the closest cardinal matrix 3drefit -deoblique mydset There is no difference in the view inside the afni GUI, but there would be a difference in suma's display.

  2. Transform the data so that the cardinal data is accurate, i.e. cardinalize the data. The data will appear tilted with zeros around the original volumes. 3dWarp -deoblique -prefix mycarddset mydset

  3. Transform oblique or cardinal data to match another dataset's cardinal grid where each dataset may be differently oblique. The visual result depends on the target dataset's obliquity. 3dWarp -card2oblique target_oblique_dset -prefix myobldset mydset

You can see this webpage for some examples: https://sscc.nimh.nih.gov/sscc/dglen/Obliquity

In general, I compare anatomical and EPI datasets using the third method. This is, in fact, what the align_epi_anat.py script uses to compute transformations before fine tuning alignment.

pjkohler commented 6 years ago

Hm, @afni-dglen and @afni-rickr, I am still a little confused here. Allow me to get extremely concrete:

I am trying to compare two files: (1) the nifti surface volume sub-xx_SurfVol.nii, generated by applying @SUMA_Make_Spec -NIFTI -sid sub-xx to the freesurfer output of fmriprep. (2) a functional file generated by fmriprep, sub-xx_blah_space-T1w_preproc.nii.gz. I can view both files in fsleyes and they appear perfectly aligned.

However, it is not possible to view the files together in the AFNI viewer, because the Template Space of sub-xx_SurfVol.nii, as viewed by 3dinfo, is ORIG, while the Template Space of sub-xx_blah_space-T1w_preproc.nii.gz is TLRC. Note that the 'space-T1w' part of the filename indicates that the file is not in TLRC space. I have tried the 3 options outlined by @afni-dglen, with sub-xx_SurfVol.nii as target_oblique_dset and sub-xx_blah_space-T1w_preproc.nii.gz as mydset, and none of them changes the header of the functional file to ORIG, or otherwise make it possible to view the files together.

Am I missing something here?

pjkohler commented 6 years ago

I think I understand now that only option 3 really makes sense if I want to modify the functional file from being in cardinal space (TLRC) to being in oblique space (ORIG), apologies for not getting that before.

If I use option 3 to convert my functional file to test3+tlrc, and then run 3drefit -view orig test3+tlrc., the result test3+orig can be viewed with the surface volume in the AFNI viewer, and looks aligned. However, 'Template Space' in the header of test3+orig is still TLRC, and if I convert to .nii.gz with 3dAFNItoNIFTI, the resulting file reverts to TLRC and cannot be viewed with the surface volume.

pjkohler commented 6 years ago

3drefit -view orig -space ORIG test3+tlrc

followed by 3dAFNItoNIFTI did the trick, generated a nifti file that could be viewed in the AFNI viewer. However, simply applying 3drefit to the original functional data:

3drefit -view orig -space ORIG sub-xx_blah_space-T1w_preproc.nii.gz

accomplished the same thing. The output of 3drefit is identical to the output of 3dWarp+3drefit+3dAFNItoNIFTI in both the afni viewer and fsleyes, and both are identical to the original functional data in fsleyes.

This would seem to suggest that the only issue is that afni interprets the fmriprep output as being in TLRC space, so simply correcting that with 3drefit is enough. It would still be great to understand why this is happening.

Hope this is helpful to someone other than me.

/Peter

pjkohler commented 6 years ago

@mvdoc, pretty sure 3drefit used as described above will resolve your original issue as well.

chrisgorgo commented 6 years ago

Does this mean we could achieve compatibility with AFNI viewers without adding extra interpolation to T1w outputs by adding additional affine to the combine transformation applied to space-T1w preprocessed bold outputs?

pjkohler commented 6 years ago

not sure I know the answer, but here's 3dinfo before running 3drefit -view orig -space ORIG:

Dataset File: sub-00XX_blah_bold_space-T1w_preproc.nii.gz Identifier Code: NII_jKkr6ZYQUBjQi47n4aVHdg Creation Date: Wed Oct 24 16:20:37 2018 Template Space: TLRC Dataset Type: Echo Planar (-epan) Byte Order: LSB_FIRST {assumed} [this CPU native = LSB_FIRST] Storage Mode: NIFTI Storage Space: 213,085,200 (213 million [mega]) bytes Geometry String: "MATRIX(-2,0,0,68.278,0,-2,0,85.67899,0,0,2,-91.67909):71,82,75" Data Axes Tilt: Plumb Data Axes Orientation: first (x) = Left-to-Right second (y) = Posterior-to-Anterior third (z) = Inferior-to-Superior [-orient LPI] R-to-L extent: -71.722 [R] -to- 68.278 [L] -step- 2.000 mm [ 71 voxels] A-to-P extent: -76.321 [A] -to- 85.679 [P] -step- 2.000 mm [ 82 voxels] I-to-S extent: -91.679 [I] -to- 56.321 [S] -step- 2.000 mm [ 75 voxels] Number of time steps = 122 Time step = 2.00000s Origin = 0.00000s -- At sub-brick #0 '?' datum type is float -- At sub-brick #1 '?' datum type is float -- At sub-brick #2 '?' datum type is float For info on all 122 sub-bricks, use '3dinfo -verb'

and after:

Dataset File: test4.nii.gz Identifier Code: AFN_GNGdPDWC2YyDPdT3nJ6nwA Creation Date: Wed Oct 24 16:19:02 2018 Template Space: ORIG Dataset Type: Echo Planar (-epan) Byte Order: LSB_FIRST {assumed} [this CPU native = LSB_FIRST] Storage Mode: NIFTI Storage Space: 213,085,200 (213 million [mega]) bytes Geometry String: "MATRIX(-2,0,0,68.278,0,-2,0,85.67899,0,0,2,-91.67909):71,82,75" Data Axes Tilt: Plumb Data Axes Orientation: first (x) = Left-to-Right second (y) = Posterior-to-Anterior third (z) = Inferior-to-Superior [-orient LPI] R-to-L extent: -71.722 [R] -to- 68.278 [L] -step- 2.000 mm [ 71 voxels] A-to-P extent: -76.321 [A] -to- 85.679 [P] -step- 2.000 mm [ 82 voxels] I-to-S extent: -91.679 [I] -to- 56.321 [S] -step- 2.000 mm [ 75 voxels] Number of time steps = 122 Time step = 2.00000s Origin = 0.00000s -- At sub-brick #0 '?' datum type is float: -3493.93 to 84119.1 -- At sub-brick #1 '?' datum type is float: -3065.35 to 63797.2 -- At sub-brick #2 '?' datum type is float: -3107.67 to 64309.6 For info on all 122 sub-bricks, use '3dinfo -verb'

The second file is compatible with the AFNI viewer.

pjkohler commented 6 years ago

header info before:

fslhd sub-00XX_blah_bold_space-T1w_preproc.nii.gz | grep form qform_name Aligned Anat qform_code 2 qform_xorient Left-to-Right qform_yorient Posterior-to-Anterior qform_zorient Inferior-to-Superior sform_name Aligned Anat sform_code 2 sform_xorient Left-to-Right sform_yorient Posterior-to-Anterior sform_zorient Inferior-to-Superior descrip xform matrices modified by FixHeaderApplyTransforms (niworkflows v0.3.4).

and after 3drefit:

fslhd test4.nii.gz | grep form qform_name Scanner Anat qform_code 1 qform_xorient Left-to-Right qform_yorient Posterior-to-Anterior qform_zorient Inferior-to-Superior sform_name Scanner Anat sform_code 1 sform_xorient Left-to-Right sform_yorient Posterior-to-Anterior sform_zorient Inferior-to-Superior

and after 3dWarp+3drefit+3dAFNItoNIFTI:

fslhd test3.nii.gz | grep form qform_name Scanner Anat qform_code 1 qform_xorient Right-to-Left qform_yorient Anterior-to-Posterior qform_zorient Inferior-to-Superior sform_name Scanner Anat sform_code 1 sform_xorient Right-to-Left sform_yorient Anterior-to-Posterior sform_zorient Inferior-to-Superior

The 3 files are aligned and appear identical in fsleyes.

afni-dglen commented 6 years ago

In the afni_proc.py and align_epi_anat.py, we concatenate the transformations including this obliquity transformation. Note that in some cases, the obliquity info is sometimes wrong, and alignment between EPI and anatomical can be computed without considering obliquity at all. We almost always consider the outputs of the processing pipelines to be cardinal, and the datasets are marked as cardinal with the equivalent C function to "3drefit -deoblique"

afni-rickr commented 6 years ago

Hi @pjkohler. In this case, the data seems to start out as cardinal, and so running 3dWarp should really have no effect. The need to match the spaces is due to the original intention of the afni GUI being to provide the mechanism to go from orig to standard space. That ability is really obsolete or mostly unnecessary now, so we will have been planning to relax the restriction. But it currently stands.
On the flip side, if 2 datasets are aligned, why are they listed as being in different spaces? Ah, the confusion is due to sform_code 2 changing to 1. For that you can set AFNI_NIFTI_VIEW to orig.

pjkohler commented 6 years ago

yes, adding the line

AFNI_NIFTI_VIEW = orig

to the ~/.afnirc made the afni viewer treat the functional files as orig rather than tlrc without doing anything to the files. Thanks, @afni-rickr. Still unclear to me whether this is the same issue or different from what @mvdoc was experiencing.

afni-rickr commented 6 years ago

@pjkohler The issue with @mvdoc, which I have not had the chance to read the updates to, was about obliquity, at least last I knew. It is possible this could apply as a secondary issue. I'll look it over tomorrow. Thanks.

afni-rickr commented 6 years ago

Okay, sorry @pjkohler, I hadn't realized the issue @mvdoc had was in this thread. :) Anyway, hopefully that is resolved. Moving forward, we might have the afni GUI effectively run 3dWarp -deoblique under the hood, which is presumably what other packages are doing. We'll see. The downside might be that oblique data would not be shown without interpolation.