Extracting Schaefer parcels from CIFTIs

I have a fmriprep-preprocessed dataset (v 20.1.1) in which CIFTIs were generated in standard 91k resolution. I would like to extract the individual vertices within several regions in the Schaefer 400 parcellation. According to the wb_command -file-information command, each hemisphere in my functional data has ~29,700 of the 32k vertices. My understanding is that the uncounted vertices belong to the medial wall.

Meanwhile the Schaefer image (.dlabel.nii) contains all of the 32k vertices in each hemisphere. In addition, it appears that the medial wall in the Schaefer image is a bit expanded compared to the functional data (see image below, in which the inferior portions of the medial wall are not aligned, i.e. the white strip below is the functional data underneath the Schaefer image).

As a result, I have three questions:

  1. Are the outputs of something wb_command -cifti-parcellate , in which the mean timeseries of each region are extracted, correct? If so, how does it account for this mismatch and correctly index the proper vertices/regions?
  2. For my goal, what’s the best approach to extract the correct vertices of my regions of interest (i.e. applying a mask to the array) while accounting for the descrepancies described above?
  3. More generally, what are some folks’ workflows when working with preprocessed CIFTI images (e.g., with nibabel, etc)? I can’t find a lot of good documentation on this sort of stuff (other than Jo Etzel’s excellent blog posts!)

I’m trying to do things with wb_command and nibabel, if that helps.

Thanks!

I have had the best success matching vertices (and generally doing anything with surface datasets) working in gifti, rather than cifti. Have you tried using wb_command -cifti-separate on all the ciftis, then comparing the numbers of vertices/etc. in each hemisphere? In general, wb_command functions work well with HCP pipeline-created ciftis, but I’d be cautious with ciftis from other sources. (wb_command -cifti-separate can also write a standard nifti for its volumetric part.)

You may have already seen it (glad the blog is useful! :blush:), but my most recent surface knitr tutorial has an example working with Schaefer parcels. It’s R, but the logic might help: read in a gifti and extract the data for each vertex as a vector (one entry per vertex, e.g., parcel labels) or array (one row per vertex, one column per timepoint/whatever). If you have a matching set (i.e., parcel and data giftis “belonging” to the same .surf.gii underlay) you can then use the parcel label vector to identify the rows in the data array, making it easy to do further analyses (averaging, etc.). afni can also be useful: many of its functions can work on giftis as well as niftis.

1 Like

Hi @jaetzel!

Thanks for the reply. I hadn’t really considered converting to gifti, but I like that idea. Do you prefer giftis over ciftis because they are generall easier to work with? I’ve pretty much worked with volumetric data up until now, so I’m not clear on their practical differences.

I did end up checking the vertices with nibabel instead of wb_command -cifti-separate, and indeed the vector lengths do differ (~32k per hemisphere in the Schaefer atlas, ~29k in my .dtseries.nii functional data). The difference is due to the medial wall, that I guess is a separate structure in CIFTIs?

Yes, I’ve found working with giftis (and niftis for the subcortical) much easier than ciftis. Working with giftis isn’t all that much different than niftis, once you get used to the idea of indexing a vector of vertices per hemisphere instead of a single 3d array of voxels (and keeping the matching .surf.gii straight, though that applies to cifti as well). There are quite a few gifti-reading packages (I mostly use gifti in R) and software, which helps a lot.

For the mismatching vertex counts, that can be really frustrating, and a big reason I switched to only working with surfaces as giftis. I last dug into this in 2018, so there might be new options now. But, FWIW, we haven’t run into any mismatch issues using the giftis and niftis produced by wb_command -cifti-separate, even when the ciftis are from different pipelines.

1 Like

@danjgale If you do want to write code to work with CIFTIs directly, I’ve recently worked out what’s needed to basically reimplement -cifti-separate in NiBabel (conceptually; I haven’t turned the vertex data into GiftiImages):

2 Likes