neurocausal / neurocausal_meta

the code base of neurocausal meta-analysis platform
BSD 3-Clause "New" or "Revised" License
1 stars 7 forks source link

Neural space(s) determination and conversion/mapping #12

Open vborghe opened 2 years ago

vborghe commented 2 years ago

Once the papers have been filtered (#11) - key part of the preprocessing will be

Whatever the paper is using,

vborghe commented 1 year ago

@pinheirochagas do you think what @complexbrains did here https://github.com/neurocausal/neurocausal_data/pull/5 actually belongs to meta rather than data? regardless of where it ends, clearly helpful for this too, no?

vborghe commented 1 year ago

Next step: adapting the neuroquery code to atlas (rather than coordinates), choose atlas, convert all coordinates (and other atlases) to that one

vborghe commented 1 year ago

@complexbrains's branch now has the MNI coordinates extraction code

templateflow might help with the mapping/conversions, but currently does not cover all the parcellations/atlases we had in mind (mostly MNI-ish spaces)

vborghe commented 1 year ago

neuroparc covers more of the atlases we might need

vborghe commented 1 year ago

@complexbrains @pinheirochagas Following Jerome's suggestion, we might want to stick with MNI coordinates (i.e., convert everything to MNI coordinates) simply putting uniform values to all voxels that fall within a given atlas region

pinheirochagas commented 11 months ago

Here are a set of functions to convert atlas-specific region coordinates to MNI space and plot the regions on a standard MNI brain using nilearn. Some atlases will be fetched directly from nilearn, while others might require manual downloading of the .nii files. @complexbrai @vborghe @margokersey.

Implementation: 1. Fetching the Atlas: We've defined a function fetch_atlas(atlas_name) that fetches the atlas based on its name. Some atlases, like mars_atlas, desikan_killiany, talariach_ba, and talariach_gyrus, aal are placeholders for now and will need the paths to their respective volumetric atlas files (the function already accepts a path to the nii file: e.g.: https://www.oxcns.org/aal3.html). Atlases such as juelich, harvard_oxford and destrieux, can be fetched using nilearn's built-in datasets module.

2. Conversion to MNI Space:

For the current implementation, regions need to be entered as numerical values. In the future, we should create a dictionary that maps paper_region_name to atlas_label in order to retrieve the atlas_region_value and perform the conversion.

3. Plotting: Once the conversion is done, we have a function plot_anatomical_overlay(binary_mask_img) that plots the MNI coordinates of the region on a standard MNI brain for inspection. It looks great to me!

#%%
import numpy as np
import nibabel as nib
from nilearn import plotting, image
import nilearn
import nilearn.datasets
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
# https://github.com/neurocausal/neurocausal_meta/blob/main/atlas_labels_annotation.csv

#%%
def fetch_atlas(atlas_name):
    if atlas_name == 'mars_atlas':
        return None # find the volumetric atlas probably from file
    elif atlas_name == 'desikan_killiany':
        return None # find the volumetric atlas probably from file
    if atlas_name == 'talariach_ba':
        return None # find the volumetric atlas probably from file
    if atlas_name == 'talariach_gyrus':
        return None # find the volumetric atlas probably from file
    if atlas_name == 'juelich':
        return nilearn.datasets.fetch_atlas_juelich('maxprob-thr25-1mm').maps
    elif atlas_name == 'harvard_oxford':
        return nilearn.datasets.fetch_atlas_harvard_oxford('cort-maxprob-thr25-2mm').maps
    elif atlas_name == 'destrieux':
        return nilearn.datasets.fetch_atlas_destrieux_2009().maps
    elif atlas_name == 'aal':
        atlas_name = '/Users/pinheirochagas/Downloads/AAL3/AAL3v1.nii'
        return atlas_name
    else:
        raise ValueError(f"Atlas {atlas_name} is not recognized or not supported in this function.")

#%%
def convert_to_mni(atlas_name, region_value):
    # Fetch the atlas
    atlas_obj = fetch_atlas(atlas_name)

    # Load the atlas if it's a file path, otherwise proceed with the Nifti image
    if isinstance(atlas_obj, str):
        atlas_img = nib.load(atlas_obj)
    else:
        atlas_img = atlas_obj

    atlas_data = atlas_img.get_fdata()

    # Identify the region
    region_voxels = np.argwhere(atlas_data == region_value)

    # Convert the voxels to MNI space
    mni_coordinates = [nib.affines.apply_affine(atlas_img.affine, voxel) for voxel in region_voxels]

    return mni_coordinates

# %%
def create_mni_mask(mni_coordinates, template_shape, affine):
    """Create a binary mask in MNI space from the given coordinates."""
    mask = np.zeros(template_shape)
    for coord in mni_coordinates:
        voxel = nib.affines.apply_affine(np.linalg.inv(affine), coord).astype(int)
        mask[tuple(voxel)] = 1
    mask_img = nib.Nifti1Image(mask, affine=affine)
    return mask_img

def plot_anatomical_overlay(binary_mask_img):
    """Plot the binary mask on top of a standard MNI brain."""

    # Create a custom colormap that only contains the color red
    cmap = ListedColormap(['#000000', '#FF0000'])

    # Create a matplotlib figure with a specified size
    fig = plt.figure(figsize=(10, 8))

    # Plot
    plotting.plot_stat_map(binary_mask_img, display_mode='ortho', colorbar=False, 
                           threshold=0.5, cmap=cmap, figure=fig)
    plotting.show()

#%%
# Example usage:
region_value = 1  # replace with the value for your region of interest
mni_coords = convert_to_mni('aal', region_value)
template = nilearn.datasets.load_mni152_template()
binary_mask_img = create_mni_mask(mni_coords, template.shape, template.affine)
plot_anatomical_overlay(binary_mask_img)
# %%
atlas_list = ['juelich', 'harvard_oxford', 'destrieux', 'aal']
region_value = 1  # replace with the value for your region of interest
[plot_anatomical_overlay(create_mni_mask(convert_to_mni(atlas, region_value), template.shape, template.affine)) for atlas in atlas_list]

Example: Frontal_Inf_Oper_L from AAL into MNI Frontal_Inf_Oper_L from AAL into MNI

vborghe commented 10 months ago

This looks great!! Thanks a lot, Pedro!