Source code for laion_fmri.brain

"""Brain space mapping utilities."""

import nibabel as nib
import numpy as np

from laion_fmri.io import load_nifti_mask


[docs] def to_nifti( values, output_path, brain_mask_path, affine, roi_mask=None, custom_mask=None, ): """Map 1D voxel values back to a 3D NIfTI volume. Parameters ---------- values : np.ndarray 1D array of values to place in the volume. output_path : str or Path Output NIfTI file path. brain_mask_path : str or Path Path to the brain mask NIfTI. affine : np.ndarray 4x4 affine matrix. roi_mask : np.ndarray[bool] or None Boolean mask within brain voxels. custom_mask : np.ndarray[bool] or None Custom boolean mask within brain voxels. Raises ------ ValueError If values length does not match the expected voxel count. """ brain_mask = load_nifti_mask(brain_mask_path) volume_shape = nib.load(str(brain_mask_path)).shape # Determine which voxels to fill if roi_mask is not None: expected_n = int(roi_mask.sum()) elif custom_mask is not None: expected_n = int(custom_mask.sum()) else: expected_n = int(brain_mask.sum()) if len(values) != expected_n: raise ValueError( f"Values length mismatch: got {len(values)}, " f"expected {expected_n}" ) # Build full-volume flat array volume_flat = np.zeros(brain_mask.shape[0], dtype=np.float32) brain_indices = np.where(brain_mask)[0] if roi_mask is not None: selected_brain_indices = brain_indices[roi_mask] elif custom_mask is not None: selected_brain_indices = brain_indices[custom_mask] else: selected_brain_indices = brain_indices volume_flat[selected_brain_indices] = values volume_3d = volume_flat.reshape(volume_shape) img = nib.Nifti1Image(volume_3d, affine) nib.save(img, str(output_path))
[docs] def get_voxel_coordinates( brain_mask_path, affine, roi_mask=None, custom_mask=None, ): """Compute MNI coordinates for brain voxels. Parameters ---------- brain_mask_path : str or Path Path to the brain mask NIfTI. affine : np.ndarray 4x4 affine matrix. roi_mask : np.ndarray[bool] or None Boolean mask within brain voxels. custom_mask : np.ndarray[bool] or None Custom boolean mask within brain voxels. Returns ------- np.ndarray Shape (n_voxels, 3) array of coordinates. """ brain_mask = load_nifti_mask(brain_mask_path) volume_shape = nib.load(str(brain_mask_path)).shape # Get 3D indices of brain voxels brain_3d = brain_mask.reshape(volume_shape) ijk = np.array(np.where(brain_3d)).T # (n_brain, 3) if roi_mask is not None: ijk = ijk[roi_mask] elif custom_mask is not None: ijk = ijk[custom_mask] # Apply affine: coords = affine @ [i, j, k, 1]^T ones = np.ones((len(ijk), 1)) ijk_h = np.hstack([ijk, ones]) # (n, 4) coords = (affine @ ijk_h.T).T[:, :3] return coords