Convert ROI from MNI to native space

Hi everybody,
I am a new AFNI user (so sorry in advance for a basic question)

I am trying to convert an ROI from MNI space to the subject’s native space. I looked into the 3Dwarp help but I don’t see any flags/options for this type of conversion, and I don’t have any matrix to load.
Can you please help me figuring this out?

Thank a lot in advance.

Hi-

You would do this creating a transformation between the two datasets (MNI template and subject anatomical), and then applying that transformation to the ROI dset. Between two different subject brains (like the MNI template and a person), you would probably want to use nonlinear alignment, because the structural differences are so great. Programs in AFNI for this would be 3dQwarp or @SSwarper (the latter being a program that combines skullstripping (SS) and nonlinear warping). When applying the transformation to the ROI dset of interest, you also have to be careful to apply correct interpolation for the data of interest–in this case, integer values within the ROI dset–which we would typically call “NN” = nearest neighbor interpolation.

It might be worth checking out some of the AFNI Academy videos about these concepts and relevant programs here:
for alignment/warping/transforming:
https://www.youtube.com/watch?v=PaZinetFKGY&list=PL_CD549H9kgqJ1GDXAs1BWkgEimAHZeNX
for atlas/template descriptions and info:
https://www.youtube.com/watch?v=IAjGwwrqtbk&list=PL_CD549H9kgqsb1Core6DhdCIw9vhQhQP

It might be easier to discuss setting up this particular problem, then. Some further details, like, are you running FreeSurfer on your anatomical and some other things might be useful, too.

–pt

In case it helps you or anyone in the future, I just worked on this question myself and this seemed to have worked for me:

I ran @SSwarper to transfer my native space anat into MNI. This outputs a .1D file with the warping info. From there I just ran these two lines:

invert the warp so it is MNI>native:
cat_matvec -ONELINE anatQQ.s${sub}.aff12.1D -I>warp_Matrix.1D
apply the inverted warp to the MNI ROI:
3dAllineate -1Dmatrix_apply warp_Matrix.1D -prefix ATL_tocalc -cost lpa -source_automask -master anatSS.s${sub}.nii -source ATL+tlrc

Hi, heatherb-

Thanks, and that is a good suggestion for people using @SSwarper, which is generally our currently recommended way for people to align a subject anatomical to a template, such as the MNI. However, @SSwarper includes both linear affine and nonlinear warp components, and I only see linear affine pieces included in your inverse transformation. Also, the initial question was about warping and ROI, specifically, which has the particular constraint of wanting to use an “NN” interpolant when applying the transformation (to preserve integer values in the source dset); in your example, that interpolant is not listed, so I don’t think the integer-valued nature of the input atlas dset would be preserved.

Here is a script that I would use to map ROIs to subj anat space when using @SSwarper, with the above considerations applied. It would run in the Bootcamp Dataset directory: ~/AFNI_data6/FT_analysis/Qwarp/anat_warped/, assuming that you have also added the MNI_Glasser_HCP_v1.0_LPI_2009c.nii.gz in that directory
(which could be downloaded here: https://afni.nimh.nih.gov/pub/sscc/staff/ptaylor/MNI_Glasser_HCP_v1.0_LPI_2009c.nii.gz); or any atlas on the MNI*SSW.nii.gz grid will work there.


#!/bin/tcsh

# -------------------------- input info -----------------------------

# subject anatomy, native (subject) space
set dset_anat = anatUA.FT.nii

# MNI "Glasser" atlas (on grid of MNI*SSW*nii.gz), which might need to
# be downloaded, Dear Reader.  NB: any atlas on MNI*SSW*nii.gz grid
# will work here
set dset_atl = MNI_Glasser_HCP_v1.0_LPI_2009c.nii.gz

# SSW transform pieces: affine and NL parts
set ssw_aff   = anatQQ.FT.aff12.1D
set ssw_nl    = anatQQ.FT_WARP.nii

# ------------------------ outputs to be made ---------------------------
# prefix of output warp: could be made using a ${subj} variable
set ssw_full_inv = anatQQ.FT_full_INVWARP.nii.gz

# ... and to be created, in subj anat space
set dset_atl_subj = mni_glass_in_FT.nii.gz

# ----------------------------------------------------------------------

# create full inv warp: (aff + nl)^{-1}
3dNwarpCat                                  \
    -iwarp                                  \
    -warp1  "${ssw_nl}"                     \
    -warp2  "${ssw_aff}"                    \
    -prefix "${ssw_full_inv}"

# apply full inv warp, with NN interpolant to preserve ints
3dNwarpApply                                                  \
    -prefix  "${dset_atl_subj}"                               \
    -nwarp   "${ssw_full_inv}"                                \
    -ainterp  NN                                              \
    -source  "${dset_atl}"                                    \
    -master  "${dset_anat}"

# bonus nicety: attach any labletables/atlas points, as well as have
# it open a nice "ROI-like" colorbar in GUI when overlaid
3drefit -copytables "${dset_atl}"  "${dset_atl_subj}"
3drefit -cmap INT_CMAP             "${dset_atl_subj}"

All the inputs and outputs are listed at the top of the script. I called the script “do_inv_ssw_roi.tcsh”, and it can be run in the Bootcamp data directory like:


tcsh do_inv_ssw_roi.tcsh

It produced the ROIs as desired, see the attached image, which shows even the labels are attached again successfully.

Yet another consideration might be applying “modal smoothing” to the ROIs after warping like this: basically, because we are mapping one discrete grid to another, some odd edge things can happen, and modal smoothing might be nice to apply. But perhaps seeing how the first steps above seem would be a good place to start.

–pt

Hi, @ptaylor,

Seeing this thread, I noticed that in your script you would need to have the output from @SSwarp/3dQwarp before hand, correct?

i.e., 3dNwarpCat just creates the inverted warp from that you already have.

I haven't used 3dQwarp (other than "indirectly" in my preprocessing generated by afni_proc.py). I was wondering... Because in my case I'm using a skull-stripped image, I would have to run 3dQwarp. But I am not sure how to apply it. Say I have sub-01_ss_anat+orig, and an MNI_template...

Would this do...?

3dQwarp
-base MNI_template
-source sub-01_ss_anat+orig
-iwarp
-prefix qwarp

Or how would it work?

Thank you!

1 Like

Howdy-

Perhaps could you please describe what you want to do? And what state is your data in?

For example, did you use nonlinear warping in afni_proc.py, but you didn't run @SSwarper itself ahead of time (instead, using what afni_proc.py would use for nonlinear warping internally, which would be auto_warp.py, which is a different wrapper for 3dQwarp)?

And if you have run afni_proc.py, it would help to see that command, too, just to be more certain.

--pt

Sorry, I'm commenting on this thread because it's just about what I want to do: convert ROIs that are in MNI space to each of my subjects' individual space.

In my preprocessing I didn't run any alignment to MNI template. Just volreg to align anat to epi:

afni_proc.py                                                                       \
    -subj_id sub-00                                                                \
    -copy_anat                                                                     \
    -anat_has_skull yes                                                            \
    -dsets                                                                         \
    sub-00/func/sub-00_task-LexDec_acq-epfid2d188_dir-COL_run-1_echo-1_bold.nii.gz \
    sub-00/func/sub-00_task-LexDec_acq-epfid2d188_dir-COL_run-2_echo-1_bold.nii.gz \
    sub-00/func/sub-00_task-LexDec_acq-epfid2d188_dir-COL_run-3_echo-1_bold.nii.gz \
    sub-00/func/sub-00_task-LexDec_acq-epfid2d188_dir-COL_run-4_echo-1_bold.nii.gz \
    sub-00/func/sub-00_task-LexDec_acq-epfid2d188_dir-COL_run-5_echo-1_bold.nii.gz \
    sub-00/func/sub-00_task-LexDec_acq-epfid2d188_dir-COL_run-6_echo-1_bold.nii.gz \
    -blocks tshift align volreg mask blur scale                                    \
    -tcat_remove_first_trs 6                                                       \
    -align_opts_aea -cost lpc+ZZ                                                   \
    -giant_move                                                                    \
    -volreg_align_to MIN_OUTLIER                                                   \
    -volreg_align_e2a                                                              \
    -volreg_compute_tsnr yes                                                       \
    -blur_size 4.0

So any 1D matrix I have is from the e2a transform.

That's why I guessed I need to run 3dQwarp.

Thank you for your help!

1 Like

OK, indeed, you haven't used the "tlrc" block here, so there is no alignment to standard space here. The final space is the subject anatomical. And I guess you don't want to rerun this with an updated afni_proc.py command, to include the full nonlinear alignment there? It will lead to less extra blur added, because afni_proc.py's processing will concatenate all transforms before applying them---reducing the number of regridding operations during processing.

Sidenote: if you add the "regress" block to your list of -blocks ..---even if you don't care any regression modeling---you will get the lovely QC HTML:

It is certainly possible to run 3dQwarp here to estimate your warp to standard space.

  • I would probably add -allineate, for the initial alignment and possibly add -allopt '-cost lpa+ZZ', to specify a nice cost function for similar-contrast datasets.
  • -pblur is likely useful here:
     Use progressive blurring; that is, for larger patch sizes,
                 the amount of blurring is larger. The general idea is to
                 avoid trying to match finer details when the patch size
                 and incremental warps are coarse. When '-blur' is used
                 as well, it sets a minimum amount of blurring that will
                 be used. 
    

--pt

Exactly. The thing is I already ran the preprocessing on all subjects, and I want to run my analyses on the native space. If I can just do the normalization to get the matrix, I would prefer that over rerunning the whole preprocessing (I know, in the future I'll save time and just do it all in one :sweat_smile:).

Sidenote noted down, thanks! :slightly_smiling_face:

And thank you also for the extra tips for 3dQwarp. I tested it on one subject with the additional arguments you provided and it seems to work perfectly.

All the best,

Abraham

Hi, Abraham-

Cool, glad that is working for creating the warp to standard space. Note that the warp should be a full *_WARP* file---that is, that command creates a full volumetric dataset. The affine matrix that is there was created by the preliminary (internal) 3dAllineate call.

In terms of applying the warp, note that (from the 3dQwarp help):

   ** PLEASE NOTE that if you use the '-allineate' option in 3dQwarp, to   **
   ** do the 3dAllineate step inside 3dQwarp, then you do NOT catenate     **
   ** the affine and nonlinear warps as in the 3dNwarpApply example above, **
   ** since the output nonlinear warp will ALREADY have be catenated with  **
   ** the affine warp -- this output warp is the transformation directly   **
   ** between the '-source' and '-base' datasets (as is reasonable IZHO).  **

That is, you only need to apply the *_WARP* and *_INVWARP* dsets.

Also note that when you apply the warp to an ROI dataset, you will likely want to preserve integer values when you warp. To do so with 3dNwarpApply, you would use this option:

 -ainterp jjj = This option lets you specify a different interpolation mode
                for the data than might be used for the warp.
                ++ In particular, '-ainterp NN' would be most logical for
                   atlas datasets, where the data values being mapped are
                   integer labels.

--> i.e., -ainterp NN.

Note further: many AFNI-distributed atlases have string labels attached to ROIs. You can re-attach those to your warped ROI dataset. Consider the original ROI dset "DSET_ROI_ORIG" and the warped one "DSET_ROI_WRPD". Then:

# copy over labeltables and/or atlas_points
3drefit -copytables  DSET_ROI_ORIG  DSET_ROI_WRPD
# copy over part of header so ROI-based colormap will be used
# by default in AFNI GUI:
3drefit -cmap INT_CMAP DSET_ROI_WRPD

--pt

Paul's recommendations will work fine. Just for reference, there are several ways to go from template space to native space, depending on how the transformation was computed. Consider the options presented on slides 35-38 presented here:

https://afni.nimh.nih.gov/pub/dist/edu/latest/afni11_roi/afni11_roi.pdf

Aah so, I would just need to do the 3dNwarpApply?

For more context, I ran:

3dQwarp                                  \
-base MNI_template                       \
-source sub-01_ss_anat+orig              \
-iwarp                                   \
-allineate                               \
-pblur                                   \
-prefix qwp                              \

And got the yellow output:

imagen

Then, I would run:

3dNwarpApply                        \
-prefix rois_in_sub-01              \
-nwarp qwp_WARPINV+tlrc             \
-ainterp NN                         \
-source MNI_Glasser_HCP_v1.0.nii.gz \
-master sub-01_ss_anat+orig

Is that correct?

Thanks again!

Hi, Abraham-

That looks correct to me, yes.

I would just follow that up with:

3drefit -copytables  MNI_Glasser_HCP_v1.0.nii.gz  rois_in_sub-01+tlrc.HEAD
3drefit -cmap INT_CMAP rois_in_sub-01+tlrc.HEAD

You can verify in the GUI that all went well by clicking around, too.

--pt

Beautiful, it works perfectly :innocent:

Thank you so much!!

Ah, music to my eyes!

--pt

Hi again,

Just as a small follow-up on this, I have another doubt.

Say I have a set of binary ROIs that I created by using whereami. I have n files with binary masks for each ROI. They are not labelled or whatsoever.

I want to create a single labelled volume, as if it were an atlas. How can I do that?

There are several options, but I don't quite get which one(s) would do this.

Thanks once more!

There is actually a tutorial on doing that here, in particular this stage:
https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/tutorials/rois_corr_vis/cat_netcorr.html#combine-rois-into-single-volume-with-integer-and-string-labels

The fundamental steps are:

  • 3dTcat .. your n volumes into a single, 4D "time series" of ROIs. Put these in the order that you eventually want them labelled: the [0]th volume will eventually get an integer value of 1, the [1]th one an integer value of 2, etc.

  • 3dTstat -argmax1 ..` to condense that time series of ROIs into a single 3D volume of integers

    • I will add a step here: run the same 3dTstat .. command, but replace -argmax1 with -sum and use a different output prefix. This 3D volume will count, per voxel, how many ROIs were in that location. The important thing is to check that this new volume only has a maximum value of 1 (i.e., 3dinfo -dmax DSET), meaning that there was no overlap of ROIs---because otherwise, you have to decide how to deal with overlaps (which one gets precedent---in this case, the ROI farther back in your list of initial ROI maps will).
  • @MakeLabelTable .. to attach a string label to each integer

  • Check it visually in AFNI, clicking around and checking the labels, and/or use @chauffeur_afni to make a snapshot of the brainwide ROIs.

--pt

1 Like

Hi again @ptaylor, and thanks for your help (4 months ago).

I have a simpler question about this.

I know that you can extract single atlas ROIs from the atlases in the AFNI path by using whereami.

Is there a way of doing the same thing with "custom" atlases, like the ones created in the subject's native space?

To refresh this a little bit, what I've got is N MNI_Glasser native atlases, where N is the number of subjects. For each one of them, I need to select a certain combination of areas. For a normalised image, I would simply create the binary for each area with whereami, but here I just have the native Glassers, and whereami cannot access those (unless I add the 30 individual atlases to the path, which I'd rather not do). Is this possible?

Thanks!

1 Like

Labeled datasets can be used a lot like atlases. Just specify the label in the range selector in an AFNI command.

3dcalc -a tempglass+orig.'<L_Rostral_Area_6>' -expr 'step(a)' -prefix tempglass_L_Rostral_Area_6 -overwrite

3dBrickStat -count -non-zero tempglass+orig.'<L_Rostral_Area_6>'
3029         

3dBrickStat -count -non-zero tempglass_L_Rostral_Area_6+orig.
3029         

If you specify the dataset as an atlas, which only requires a single entry in a SessionAtlases.niml file, it will also appear in whereami output.

1 Like