Using AFNI to co-register two surfaces


I have a NIFTI file that shows how many participants show tuned responses at each location on the cortical surface (Image 1 attached to the message).
This NIFTI file is in Talairach space (TT_N27_SurfVol in AFNI). I have mapped this file on std.141.TT_N27_both.spec in AFNI (Image 2 attached to the message). I want to map the activity from std.141.TT_N27_both.spec on each of my subjects surfaces (std.141). I have created the surface of each subject in FreeSurfer and convert it to AFNI format using @SUMA_Make_Spec_FS. Would you please tell me which command I should use in AFNI to project activity from one surface to another? Is it SurfToSurf? I read about this command that is used to interpolate data from one surface (S2) to another (S1), assuming the surfaces are quite similar in shape but having different meshes (non-isotopic). But here, the two surfaces have a similar mesh (std.141) and different shapes.
After projecting the activity on the subject’s surface, I want to save it as a NIFTI file to use it as an ROI for the analysis. Would you please tell me what the command is for this conversion?
Actually, what I want is a mask (nii file) of yellow and orange activity. But I want the mask in my subject’s native space.



An anatomical brain mesh is a 2D surface, made up of nodes (points in space) that are connected by edges. It is embedded in a 3D space. A common way of making it is finding the gray-white boundary in a T1w anatomical scan of a subject’s brain; we often also estimate the “outer” gray matter surface, called the pial. In volumetric datasets, the “unit” for storing data is a voxel; in surface meshes, it is nodes.

There are 2 concepts of the mesh that are important here: topology and geometry.

  • Geometry is the (x,y,z) location of each point in space—this is what defines the fact that a mesh “fits” the bumps and wiggles of my brain.
  • Topology is the connections of the nodes that make up the mesh—which nodes are connected to which others?
    Imagine drawing a simple mesh on a balloon. If I inflate the balloon, I change the mesh’s geometry (where each node is in 3D space), but not its topology (the node connections have not changed). In a volume, the “topology” is described by which voxels are neighbors of which voxels; in the mesh, it is described by which nodes are connected to which node. Because we use standard meshes, the multiple surfaces estimated fora subject (i.e., gray-white boundary and pial) have a correspondence of nodes between themselves—so for each node on the gray-white boundary, there is a corresponding node of the same number on the pial, making it useful for projecting data that lie between them, within the GM itself.

SUMA was designed to use standard meshes ( When you run, say, FreeSurfer’s recon-all, you get a mesh associated with a brain, but each subject will have different numbers of nodes. AFNI’s @SUMA_Make_Spec_FS program will estimate meshes that have a standard number of nodes, with each node of a particular number corresponding to approximately the same physical location on the brain across all subjects. (there are actually 2 standard meshes: std.60 and std.141, with former being less-dense and corresponding to about the same spacing at a typical EPI volume voxel centroids, and the latter approximately the same spacing as a typical T1w volume voxel spacing.) If you think about a “standard space” in volumetric data, but these properties hold true—2 dsets in the same standard space have the same number of voxels, and a given voxel with indices (i,j,k) should correspond to the same anatomical location; in a surface, 2 standard meshes have the same number of nodes, and a given node with index i should correspond to the same location. If you have an overlay created from subject A, you can display it directly on subject B without resampling, as long as both subject A and B are in the same standard space.

To map (or project data) between a surface and a volume of the same subject, you would use 3dVol2Surf and 3dSurf2Vol; this is actually what the AFNI GUI uses when you have both the afni and suma GUIs open and talking, and you can see the surface mesh lines in the AFNI GUI and the volumetric overlays from AFNI in the SUMA surfaces. This is what you appear to have done in your attached image (your “subject” is just the TT_N27 dataset, which is perfectly fine).

You can use 3dVol2Surf to project your volumetric data onto the std.141 TT_N27 mesh. Then you will have a standard mesh carrying that information. At that point, you can display that new mesh on any other subject. If you wanted to make a volumetric dataset of that new mesh in the subject space of subject A, for example, then you could use 3dSurf2Vol to project that mesh into that specific subject’s volumetric space.

You can project information in different ways—use just one surface and “grab” voxels to take data from or pass data to. In each case, I would use the gray-white boundary surface (e.g., “smoothwm”) and the pial surface, and project using both of those (you are essentially “grabbing” the voxels in between those surfaces, which should mainly be GM).

Does that make sense conceptually, and is that what you would like to do?


Thank you for your clear and thorough answer.
Yes, exactly. It is what I want to do. I used the following commands to convert the map from Talairach space to the subject’s native space based on your answer.
I used this command to map the activity on the surface. 'sumMaps.nii.gz is the activity map in Talairach space that I want to map on the surface:
3dVol2Surf -spec std.141.TT_N27_both.spec -surf_A lh.smoothwm -surf_B lh.pial -sv TT_N27_SurfVol.nii -grid_parent sumMaps.nii.gz -map_func ave -f_steps 10 -f_index nodes -out_niml sumMap.niml.dset

Then I used the following command to map the activity on surface from the output of the above command (sumMap.niml.dset) on my subject surface. ‘std.141.mySubj_both.spec’, ‘lh.smoothwm’, and ‘lh.pial’ are the output of @SUMA_Make_Spec_FS:
3dSurf2Vol -spec std.141.mySubj_both.spec -surf_A lh.smoothwm -surf_B lh.pial -grid_parent sumMap.niml.dset -sv mySubj.nii -map_func ave -f_steps 10 -f_index voxels -prefix sumMapSubj

The output of the above command (sumMapSubj.niml.dset) was not a NIFTI file so I convert it to NIFTI with the following command:
3dAFNItoNIFTI -float sumMapSubj.niml.dset

But the NIFTI output seems to be corrupted. Would you please tell me in which steps I made a mistake?

Also, I used the left hemisphere for the -surf_A and surf_B in the first two commands because files for both hemispheres were not available. However, for the -spec I used the spec file of both hemispheres. Is that OK?


I would loop over each hemisphere like there, rather than use the “both” file, because you would need to specify the hemisphere in the surface, anyways.

foreach hemi ( lh rh ) 
  3dVol2Surf \
      -spec std.141.TT_N27_${hemi}.spec \
      -surf_A smoothwm \
      -surf_B pial \
      -sv TT_N27_SurfVol.nii \
      -grid_parent sumMaps.nii.gz \
      -map_func ave \
      -f_steps 10 \
      -f_index nodes \
      -out_niml std.141.${hemi}.sumMap.niml.dset

    # "-grid_parent .." should be a volume here
    # you can also make the output a NIFTI directly, by including the suffix on the dset in "-prefix .."
    # use "-sdata .." to provide the surface dataset that should be mapped into the vol
     3dSurf2Vol \
          -spec std.141.mySubj_both.spec \
           -surf_A lh.smoothwm \
           -surf_B lh.pial \
           -grid_parent mySubj.nii \
           -sv mySubj.nii \
           -map_func ave \
           -f_steps 10 \
           -f_index voxels  \
           -sdata std.141.${hemi}.sumMap.niml.dset \
          -prefix sumMapSubj_${hemi}.nii.gz

Note how you can output a NIFTI directly, above. You can add the two files to make a single NIFTI:

3dcalc \
   -a sumMapSubj_lh.nii.gz \
   -b sumMapSubj_rh.nii.gz \
    -expr 'a+b*not(bool(a))' \
   -prefix sumMapSubj_both.nii.gz

The reason the expression isn’t just ‘a+b’, is juuust in case there is any overlap of nonzero values between the two volumetric datasets. By construction of the two hemispheric surfaces, I don’t think there should be, but this should ensure that.

Though, just to note for future reference, to copy a BRIK/HEAD file to NIFTI, you can:


The dataset you tried to convert with 3dAFNItoNIFTI wasn’t actually a BRIK/HEAD dset, I guess, because the “-grid_parent …” being used wasn’t a volumetric dataset.

How does that work?


It works perfectly well. Thank you.

Adding on a minor tweak to this. The 3dSurf2Vol command can leave holes where the projections from the surface nodes do not cross through voxels. The finer the surface mesh, the fewer holes there are. You can get around this with @surf_to_vol_spackle instead (for those who may not know, spackle is the glop used to patch holes in drywall for home repair). The command requires a volumetric mask to fill in, like the pial “ribbon” datasets that FreeSurfer generates.

@surf_to_vol_spackle -maskset mymask.nii.gz -spec mysurfs.spec
-surfA smoothwm -surfB pial -surfset thickness.niml.dset
-prefix vol_thick

If the holes aren’t a big concern, then you can ignore this.