Source code for sekupy.ext.nilearn.utils

"""
Transformer for computing seeds signals
----------------------------------------

Mask nifti images by spherical volumes for seed-region analyses
"""
import os
import numpy as np
import sklearn
from sklearn import neighbors
from distutils.version import LooseVersion
from nilearn.image.resampling import coord_transform
from scipy.sparse import load_npz, save_npz

import logging
logger = logging.getLogger(__name__)


def _get_affinity(seeds, 
                  coords, 
                  radius, 
                  allow_overlap, 
                  affine, 
                  mask_img=None):
    
    seeds = list(seeds)

    # Compute world coordinates of all in-mask voxels.           
    mask_coords = list(zip(*coords.T))
    # For each seed, get coordinates of nearest voxel
    nearests = []
    for sx, sy, sz in seeds:
        nearest = np.round(coord_transform(sx, sy, sz, np.linalg.inv(affine)))
        nearest = nearest.astype(int)
        nearest = (nearest[0], nearest[1], nearest[2])
        try:
            nearests.append(mask_coords.index(nearest))
        except ValueError:
            nearests.append(None)

    mask_coords = np.asarray(list(zip(*mask_coords)))
    mask_coords = coord_transform(mask_coords[0], mask_coords[1],
                                  mask_coords[2], affine)
    mask_coords = np.asarray(mask_coords).T

    if (radius is not None and
            LooseVersion(sklearn.__version__) < LooseVersion('0.16')):
        # Fix for scikit learn versions below 0.16. See
        # https://github.com/scikit-learn/scikit-learn/issues/4072
        radius += 1e-6

    clf = neighbors.NearestNeighbors(radius=radius)
    A = clf.fit(mask_coords).radius_neighbors_graph(seeds)
    A = A.tolil()
    for i, nearest in enumerate(nearests):
        if nearest is None:
            continue
        A[i, nearest] = True

    # Include the voxel containing the seed itself if not masked
    mask_coords = mask_coords.astype(int).tolist()
    for i, seed in enumerate(seeds):
        try:
            A[i, mask_coords.index(seed)] = True
        except ValueError:
            # seed is not in the mask
            pass

    if not allow_overlap:
        if np.any(A.sum(axis=0) >= 2):
            raise ValueError('Overlap detected between spheres')

    return A


[docs] def check_proximity(ds, radius): logger.info("Checking proximity matrix...") radius = float(radius) fname = os.path.join(ds.a.data_path, "proximity_radius_%s_%s.npz" % (str(radius), ds.a.brain_mask)) return os.path.exists(str(fname))
[docs] def load_proximity(ds, radius): logger.info("Loading proximity matrix...") radius = float(radius) fname = os.path.join(ds.a.data_path, "proximity_radius_%s_%s.npz" % (str(radius), ds.a.brain_mask)) A = load_npz(str(fname)) return A.tolil()
[docs] def save_proximity(ds, radius, A): logger.info("Saving proximity matrix...") radius = float(radius) fname = os.path.join(ds.a.data_path, "proximity_radius_%s_%s.npz" % (str(radius), ds.a.brain_mask)) logger.debug(fname) save_npz(str(fname), A.tocoo())