khanlab / hippunfold

BIDS App for Hippunfold (automated hippocampal unfolding and subfield segmentation)

Home Page:https://hippunfold.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

sample functional data along surface

viktor-pfaffenrot opened this issue · comments

Dear hippunfold folks,

I am trying to sample my high-res functional data along the surfaces generated by hippunfold. I use matlab for that by reading in the inner and outer surface gifti files. In order to bring those surfaces into matlab space (i.e. shift them around such that if I plot them in matlab over the image to be sampled, they are nicely confined to the anatomical boundaries) I use the following transformations:

image

surf = surf/0.75; % divide surfaces by image resolution to achieve units of voxels not mm

surf = bsxfun(@times,surf,shift);
% shift is a 1x3 vector corresponding to a change in sign depending on whether the image was acquired on a different plane, i.e. sagittal as opposed to transversal.

surf = bsxfun(@minus,(0.5*dims),surf) % shift the surfaces by half the size of the image. dims is the size of the image.

This approach always works for surfaces generated by freesurfer but not so for hippunfold surfaces. In fact, to obtain the image above, I ran the code and additionally shifted the surfaces by some voxels but this shift is subject specific so this is not really practial.

My question is: What is the underlying transformation between freesurfer and hippunfold surfaces? This maybe relate to the error one gets when first loading the volume and then the surfaces in freeview instead of the other way around but I cannot really wrap my head around the underlying transformations.

Any idea of where I can search for?

Many thanks for the help and also for this awesome toolbox!!

Viktor

Hi Viktor, thanks for your question.

I recommend using this tool from Workbench Command to easily map data from a volume to a surface. However, if you do want to use Matlab then you'll have to remember that the surface is actually in real-world coordinates (mm) whereas the volume is in voxels with an arbitrary offset from the "origin". For nifti images, this offset is typically written in the image header (you can obtain this using Matlab's niftiinfo(), and it will be the header.affine 4x4 matrix).

To apply this affine, you can EITHER:

  1. use Matlab's affinetform3d on the image matrix itself, but this can be annoying because then your data might get shifted outside of the bounds of your original matrix
    or
  2. invert the affine (invert(tform)) and then apply it to the xyz coordinates of the surface. This can be done by padding the xyz with ones (making it 4xV) which can then be multiplied by the inverted 4x4 transform and then remove the padding once again (bringing it back to Vx3 which can be transposed to get back to 3xV).

I think this is effectively what you were doing with your code anyway, but the code here should help it be more robust to things like rotations in the nifti header affine.

Hopefully this code work for you but if not then please let me know. I've had a problem with FreeSurfer before where it introduces a shift from the original image space that could be present in both your image and your FS-generated surfaces, but perhaps not in your hippunfold results. You can test this by opening the surfaces and volumes from FS alongside the surfaces and volumes from hippunfold (eg. in FreeView). If they are offset from each other then you could consider running hippunfold on the same FS-generated volumes that already contains that shift, or let me know and I can help you get some hacky code for remove the FS-introduced shift.

Thanks for the very fast reply!

Yeah I am aware of the workbench tool. It would maybe result in a bit of a file mess given that for each layer, hemisphere and volume on file is created, e.g. for 100 vols and 20 layers, I would have 4000 files. In the end it will results in toggling between creation and deletion I guess but I first want to try out your matlab suggetions.

Just to be clear:
*in header = niftiinfo(file) I have a field header.Transformation. You're referring to this, right?

  • with invert(tform) you mean to invert header.Transformation?

Ahh yes, header.Transformation should be correct!

Awesome your 2nd point works like a charm!! Many thanks! Haven't seen such a good support for a very long time :)

FYI (mainly for anyone else coming across this issue) -- you can use wb_command -volume-to-surface-mapping to sample 4D nifti data (not just 3D), so it would be one func.gii file for your 100 volumes. You could even then use cifti to put all the layers in the same file too..

Yeah I am aware of the workbench tool. It would maybe result in a bit of a file mess given that for each layer, hemisphere and volume on file is created, e.g. for 100 vols and 20 layers, I would have 4000 files. In the end it will results in toggling between creation and deletion I guess but I first want to try out your matlab suggetions.

Ha that is actually very good to know! Many thanks!

Hi all,

a quick follow-up regarding the workbench command: If I want to run the following command

wb_command -volume-to-surface-mapping volume.nii lh.white.gii out.func.gii -cubic -volume-roi roi.nii I get the error message Unexpected parameter: -volume-roi. Am I messing with the function call?

Yes the function call is incorrect, as the -volume-roi option is specifically for the -ribbon-constrained mapping option (in the usage you'll see the sub-options like -volume-roi are indented relative to the others)..

eg can do:

wb_command -volume-to-surface-mapping volume.nii lh.white.gii out.func.gii -cubic

or

wb_command -volume-to-surface-mapping volume.nii lh.white.gii out.func.gii -ribbon-constrained <innersurf> <outersurf> (then optional args like -volume-roi)

Uff, totally overseen this. Sorry for bothering and thank you again for the fast reply!