Create a 10mm sphere ROI mask around a given coordinate

Hello,

I try to create a 10mm sphere ROI mask around a given coordinate,
I thought the nilearn.maskers.NiftiSpheresMasker() function would work,
but it seems more like to extract the signal from the ROI, instead of creating a binary mask.
Or I just blind myself somewhere…

I firstly defined a coordinate from the peak of a first-level contrast t-map,
and I want to use this coordinate to create a 10mm sphere ROI mask,
and apply this mask on another unsmoothed first-level contrast t-map for further classification.

Question:

  1. Should I use the (fMRIprep) preprocessed T1w.nii.gz image to create the mask,
    or I can directly use the t-map of the subject?
  2. Is NiftiSpheresMasker() the right function for my case? If so, dose the script below make sense?

I tried to create the mask by NiftiSpheresMasker() and mask the t-map as below:

coords = [[56, -5, 40]]
masker = NiftiSpheresMasker(coords, radius=10)
sphere = masker.fit_transform(T1w)
masked_img = image.math_img("img1 * img2", img1=t_map, img2=sphere)

t_map.shape = (73, 86, 73); sphere.shape = (1, 1)

I got an error for masked_img:

TypeError: ("Input images cannot be compared, you provided 'dict_values([<nibabel.nifti1.Nifti1Image object at 0x000001E32DF41050>, array([[196.29353]], dtype=float32)])',", 'Data given cannot be loaded because it is not compatible with nibabel format:\n196.29353')

Hi @ttseng,

Probably easier to use the BOLD image (or derivatives of BOLD images like a statmap) so you don’t have to worry about resampling if voxel sizes differ between anatomical and BOLD.

That function is most helpful for extracting signals within a spherical mask. I do not know the full nature of your analysis, so hard to say one way or the other.

If you want to create a binary mask image object, here is a ChatGPT-generated script.

Here is a ChatGPT generated script.

import numpy as np
import nibabel as nib

def create_sphere_mask(coordinate, radius, voxel_size=1, affine=None, output_filename=None):
    # Generate a 3D grid of coordinates
    x_range = np.arange(-radius, radius + voxel_size, voxel_size)
    y_range = np.arange(-radius, radius + voxel_size, voxel_size)
    z_range = np.arange(-radius, radius + voxel_size, voxel_size)
    xx, yy, zz = np.meshgrid(x_range, y_range, z_range)

    # Compute the distance of each voxel to the center
    distances = np.sqrt((xx - coordinate[0])**2 + (yy - coordinate[1])**2 + (zz - coordinate[2])**2)

    # Create a binary mask where voxels inside the sphere are 1 and outside are 0
    binary_mask = np.where(distances <= radius, 1, 0)

    # If affine is not provided, use identity matrix
    if affine is None:
        affine = np.eye(4)  # Identity affine matrix for MNI space

    # Convert the binary mask to a Nifti image
    binary_nifti = nib.Nifti1Image(binary_mask, affine)

    # Save the binary mask to a file if filename is provided
    if output_filename:
        nib.save(binary_nifti, output_filename)

    return binary_nifti

# Example usage:
coordinate = (0, 0, 0)  # Example coordinate
radius = 10  # Example radius in mm
voxel_size = 1  # Example voxel size in mm
affine = np.eye(4)  # Example affine matrix for MNI space
output_filename = 'sphere_mask.nii.gz'  # Example output filename

binary_nifti = create_sphere_mask(coordinate, radius, voxel_size, affine, output_filename)

Best,
Steven

1 Like

OK so I am adapting things from @emdupre in this post.

from nilearn import datasets, plotting
from nilearn.masking import _unmask_3d
from nilearn.maskers import nifti_spheres_masker
import nibabel as nib
from nibabel import Nifti1Image

# let's assume we are in MNI space
brain_mask = datasets.load_mni152_brain_mask()

_, A = nifti_spheres_masker._apply_mask_and_get_affinity(
    seeds=[(-42, -36, 16)],
    niimg=None,
    radius=10,
    allow_overlap=False, 
    mask_img=brain_mask)

sphere_mask = _unmask_3d(
    X=A.toarray().flatten(), 
    mask=brain_mask.get_fdata().astype(bool))

sphere_mask = Nifti1Image(sphere_mask, brain_mask.affine)

nib.save(sphere_mask, "sphere.nii.gz")

# plot the result to make sure it makes sense
plotting.plot_roi("sphere.nii.gz")
plotting.show()

Figure_1

2 Likes

And here is how to do it with a stat image.

from nilearn import plotting, masking
from nilearn.masking import _unmask_3d
from nilearn.maskers import nifti_spheres_masker
import nibabel as nib
from nibabel import Nifti1Image

coords = (-42, -36, 16)

space_defining_image = masking.compute_brain_mask("sub-TD035_task-loc_desc-13-ROI-LipTongue_stat.nii.gz")

_, A = nifti_spheres_masker._apply_mask_and_get_affinity(
    seeds=[coords],
    niimg=None,
    radius=10,
    allow_overlap=False, 
    mask_img=space_defining_image)

sphere_mask = _unmask_3d(
    X=A.toarray().flatten(), 
    mask=space_defining_image.get_fdata().astype(bool))

sphere_mask = Nifti1Image(sphere_mask, space_defining_image.affine)

nib.save(sphere_mask, "sphere.nii.gz")

plotting.plot_roi("sphere.nii.gz", bg_img="sub-TD035_task-loc_desc-13-ROI-LipTongue_stat.nii.gz")
plotting.show()

Figure_1

1 Like

Dear Rémi,

Thank you so much! This really means a lot for me at this moment.
I see the key “nifti_spheres_masker.” here : )
I tested and it works well.

Many thanks and have a good day,
Tzuyi

Well I would have struggled a lot more if you had not mentioned this other neurostars blog post.

1 Like

Yes, very grateful for people who are willing to put time and efforts in this community!

I have a follow-up question:
Since the mask is based on .astype(bool), if I feed a stat image, the sphere ROIs vary a lot between subject based on the activation.
To include all the voxels in the sphere ROI, I tried to use MNI template to get the mask, and make it binary before resampling it with the stat t-map, so that I can apply the mask later.
Does this make sense?

sphere = _unmask_3d(
    X=A.toarray().flatten(), 
    mask=brain_mask.get_fdata().astype(bool))
sphere = Nifti1Image(sphere, brain_mask.affine)
binary_mask = math_img('(np.abs(img) > 0)', img=sphere_img)
sphere_mask = resample_to_img(binary_mask, space_defining_image)