Exemplo n.º 1
0
def get_streamvals(streamlines, affine, value_array, voxel_array = None):
    """With a set of streamlines and a value matrix,
    iterates through the set of streamlines in order to determine what is the average and maximum values found in that array
    expected to work with FA, MD, etc (must be properly registered and in same voxel space)"""

    #vals = np.ndarray(shape=(3, 0), dtype=int)
    #locations = np.ndarray(shape=(3, 0), dtype=int)
    if voxel_array is None:
        stream_voxels = []
        lin_T, offset = _mapping_to_voxel(affine)
        for sl, _ in enumerate(streamlines):
            # Convert streamline to voxel coordinates
            entire = _to_voxel_coordinates(streamlines[sl], lin_T, offset)
            stream_voxels_temp = array_to_tuplelist(entire)
            stream_voxels = stream_voxels + stream_voxels_temp

        stream_voxels_uniq = catch_unique(stream_voxels) #to ensure that voxels arent counted multiple times. Remove if voxel weight is considered a positive
        voxel_array = np.array(stream_voxels_uniq)

    i,j,k = voxel_array.T
    if np.size(value_array) == 2:
        value_array = value_array[0]
    vals = value_array[i,j,k]
    meanvals = np.mean(vals)
    maxvals = np.max(vals)

    return meanvals, maxvals, stream_voxels_uniq
Exemplo n.º 2
0
def fa_extraction(
    groupsl,
    fa_vol,
    N,
    voxel_size=None,
    affine=None,
):
    # input: groupsl, streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        fa_vol, fa values in the image domain
    #        N, # of ROIs
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    fa_group = defaultdict(list)

    for i in range(1, N):
        for j in range(i + 1, N):
            tmp_streamlines = groupsl[i, j]
            tmp_streamlines = list(tmp_streamlines)
            fa_streamlines = []
            for sl in tmp_streamlines:
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)

                #get FA for each streamlines
                ii, jj, kk = slpoints.T
                fa_value = fa_vol[ii, jj, kk]
                fa_streamlines.append(fa_value)
            fa_group[i, j].append(fa_streamlines)
    return fa_group
Exemplo n.º 3
0
def streamline_zerolab_endpoints(streamlines,label_volume,voxel_size=None,affine=None):
    # input: streamlines, input streamlines
    #        anaimg, input image
    endpointimg = np.zeros(label_volume.shape, dtype='int')

    # get the ending points of streamlines
    streamlines = list(streamlines)
    endpoints = [sl[0::len(sl)-1] for sl in streamlines]

    # Map the streamlines coordinates to voxel coordinates
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    endpoints = _to_voxel_coordinates(endpoints, lin_T, offset)

     #process the endpoints
    Nstreamlines = len(endpoints)
    endlabels = np.zeros((2,Nstreamlines),dtype=int)
    for i in range(0,Nstreamlines):
        endpoint = endpoints[i]
        endlabel = endpoints_processing(endpoint,label_volume)
        if(endlabel[0] == 0):
            endpointimg[endpoint[0][0],endpoint[0][1],endpoint[0][2]]=1

        if(endlabel[1] == 0):
            endpointimg[endpoint[1][0],endpoint[1][1],endpoint[1][2]]=1

    return endpointimg
Exemplo n.º 4
0
def rois_countmatrix_matinput(label_img,
                              N,
                              groupsl,
                              voxel_size=None,
                              affine=None):
    # input: label_img: image of labels, index from 0 - N
    #        N: # of ROIs
    #        groupsl: streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        voxel_size, affine: some parameters to transfore streamlines to voxel
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    countm = np.zeros([N + 1, N + 1])

    for i in range(0, N - 1):
        for j in range(i + 1, N):
            tmp_streamlines = groupsl[i, j]
            [tmp1, tmp2, Nfibers] = tmp_streamlines.shape
            for n in range(0, Nfibers):
                tmp = tmp_streamlines[:, :, n]
                sl = tmp.transpose(
                )  #flip the matrix to get the right input for extracting fa;
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)
                ii, jj, kk = slpoints.T

                newlabel_img = label_img[ii, jj, kk]
                roi_id = list(set(newlabel_img))
                Nid = len(roi_id)
                for aa in range(1, Nid - 1):
                    for bb in range(aa + 1, Nid):
                        countm[roi_id[aa],
                               roi_id[bb]] = countm[roi_id[aa], roi_id[bb]] + 1
    return countm
Exemplo n.º 5
0
def rois_passingrois_matinput(label_img,
                              N,
                              groupsl,
                              voxel_size=None,
                              affine=None):
    # input: label_img: image of labels, index from 0 - N
    #        N: # of ROIs
    #        groupsl: streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        voxel_size, affine: some parameters to transfore streamlines to voxel
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    passroicm = defaultdict(list)

    for i in range(0, N - 1):
        for j in range(i + 1, N):
            tmp_streamlines = groupsl[i, j]
            [tmp1, tmp2, Nfibers] = tmp_streamlines.shape
            passroicm_2nodes = []
            for n in range(0, Nfibers):
                tmp = tmp_streamlines[:, :, n]
                sl = tmp.transpose(
                )  #flip the matrix to get the right input for extracting fa;
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)
                ii, jj, kk = slpoints.T

                newlabel_img = label_img[ii, jj, kk]
                passroicm_2nodes.append(newlabel_img)
            passroicm[i, j].append(passroicm_2nodes)

    return passroicm
Exemplo n.º 6
0
def tworoi_inters_streamlines_matinput(label_img,
                                       N,
                                       groupsl,
                                       roia,
                                       roib,
                                       voxel_size=None,
                                       affine=None):
    # input: label_img: image of labels, index from 0 - N
    #        N: # of ROIs
    #        groupsl: streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        voxel_size, affine: some parameters to transfore streamlines to voxel
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    roia_roib_stls = []
    for i in range(0, N - 1):
        for j in range(i + 1, N):
            tmp_streamlines = groupsl[i, j]
            [tmp1, tmp2, Nfibers] = tmp_streamlines.shape
            for n in range(0, Nfibers):
                tmp = tmp_streamlines[:, :, n]
                sl = tmp.transpose(
                )  #flip the matrix to get the right input for extracting fa;
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)
                ii, jj, kk = slpoints.T

                newlabel_img = label_img[ii, jj, kk]
                if ((roia in newlabel_img) & (roib in newlabel_img)):
                    roia_roib_stls.append(sl)
                    print newlabel_img

    return roia_roib_stls
Exemplo n.º 7
0
def streamline_endpoints(streamlines,label_volume,voxel_size=None,affine=None):
    # input: streamlines, input streamlines
    #        anaimg, input image
    endpointimg = np.zeros(label_volume.shape, dtype='int')

    # get the ending points of streamlines
    streamlines = list(streamlines)
    endpoints = [sl[0::len(sl)-1] for sl in streamlines]

    # Map the streamlines coordinates to voxel coordinates
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    endpoints = _to_voxel_coordinates(endpoints, lin_T, offset)

    
    i, j, k = endpoints.T
    
    #processing the i,j,k, because of the offset, some endpoints are mapped
    #to the outside of the brain 
    dim = label_volume.shape
    if(np.max(i)>dim[0] and np.max(j)>dim[1] and np.max(k)>dim[2]):
        raise IndexError('streamline has points that map to outside of the brain voxel')
    i[np.where(i>dim[0]-1)] = dim[0]-1
    j[np.where(j>dim[1]-1)] = dim[1]-1
    k[np.where(k>dim[2]-1)] = dim[2]-1

    #pdb.set_trace()
    endpointimg[i, j, k] = 1

    return endpointimg
Exemplo n.º 8
0
def fa_extraction_use_cellinput(cell_streamlines,
                                cell_id,
                                fa_vol,
                                N,
                                voxel_size=None,
                                affine=None):
    # input: groupsl, streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        fa_vol, fa values in the image domain
    #        N, # of ROIs
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    fa_group = defaultdict(list)

    idx = 0
    for i in range(1, N):
        for j in range(i + 1, N):
            tmp_streamlines = cell_streamlines[idx]
            ROI_pair = cell_id[idx]
            idx = idx + 1

            fa_streamlines = []
            for sl in tmp_streamlines:
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)

                #get FA for each streamlines
                ii, jj, kk = slpoints.T
                fa_value = fa_vol[ii, jj, kk]
                fa_streamlines.append(fa_value)
            fa_group[i, j].append(fa_streamlines)


#            if(len(fa_streamlines)>20):
#                pdb.set_trace()
    return fa_group
Exemplo n.º 9
0
def convert_to_indices(streamline, papaya_aff, aff, img):
    #print(streamline)
    topoints = lambda x : np.array([[m["x"], m["y"], m["z"]] for m in x["world_coor"]])
    points_orig = topoints(streamline)
    points_nifti_space = list(utils.move_streamlines([points_orig], aff, input_space=papaya_aff))[0]
    from dipy.tracking._utils import _to_voxel_coordinates, _mapping_to_voxel
    lin_T, offset = _mapping_to_voxel(aff, None)
    idx = _to_voxel_coordinates(points_orig, lin_T, offset)
    return points_nifti_space, idx
	def _run_interface(self, runtime):
		# Loading the ROI file
	    import nibabel as nib
	    import numpy as np
	    from dipy.tracking import utils

	    img = nib.load(self.inputs.ROI_file)
	    data = img.get_data()
	    affine = img.get_affine()

	    # Getting the FA file
	    img = nib.load(self.inputs.FA_file)
	    FA_data = img.get_data()
	    FA_affine = img.get_affine()

	    # Loading the streamlines
	    from nibabel import trackvis
	    streams, hdr = trackvis.read(self.inputs.trackfile,points_space='rasmm')
	    streamlines = [s[0] for s in streams]
	    streamlines_affine = trackvis.aff_from_hdr(hdr,atleast_v2=True)

	    # Checking for negative values
	    from dipy.tracking._utils import _mapping_to_voxel, _to_voxel_coordinates
	    endpoints = [sl[0::len(sl)-1] for sl in streamlines]
	    lin_T, offset = _mapping_to_voxel(affine, (1.,1.,1.))
	    inds = np.dot(endpoints, lin_T)
	    inds += offset
	    negative_values = np.where(inds <0)[0]
	    for negative_value in sorted(negative_values, reverse=True):
			del streamlines[negative_value]

	    # Constructing the streamlines matrix
	    matrix,mapping = utils.connectivity_matrix(streamlines=streamlines,label_volume=data,affine=streamlines_affine,symmetric=True,return_mapping=True,mapping_as_streamlines=True)
	    matrix[matrix < 10] = 0

	    # Constructing the FA matrix
	    dimensions = matrix.shape
	    FA_matrix = np.empty(shape=dimensions)

	    for i in range(0,dimensions[0]):
	        for j in range(0,dimensions[1]):
	            if matrix[i,j]:
	                dm = utils.density_map(mapping[i,j], FA_data.shape, affine=streamlines_affine)
            		FA_matrix[i,j] = np.mean(FA_data[dm>0])
	            else:
	                FA_matrix[i,j] = 0

	    FA_matrix[np.tril_indices(n=len(FA_matrix))] = 0
	    FA_matrix = FA_matrix.T + FA_matrix - np.diagonal(FA_matrix)

	    from nipype.utils.filemanip import split_filename
	    _, base, _ = split_filename(self.inputs.trackfile)
	    np.savetxt(base + '_FA_matrix.txt',FA_matrix,delimiter='\t')
	    return runtime
Exemplo n.º 11
0
def convert_to_indices(streamline, papaya_aff, aff, img):
    #print(streamline)
    topoints = lambda x: np.array([[m["x"], m["y"], m["z"]]
                                   for m in x["world_coor"]])
    points_orig = topoints(streamline)
    points_nifti_space = list(
        utils.move_streamlines([points_orig], aff, input_space=papaya_aff))[0]
    from dipy.tracking._utils import _to_voxel_coordinates, _mapping_to_voxel
    lin_T, offset = _mapping_to_voxel(aff, None)
    idx = _to_voxel_coordinates(points_orig, lin_T, offset)
    return points_nifti_space, idx
Exemplo n.º 12
0
def target(streamlines, affine, target_mask, include=True, strict=False):
    """Filters streamlines based on whether or not they pass through an ROI.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines. Each streamline should be a (N, 3) array,
        where N is the length of the streamline.
    affine : array (4, 4)
        The mapping between voxel indices and the point space for seeds.
        The voxel_to_rasmm matrix, typically from a NIFTI file.
    target_mask : array-like
        A mask used as a target. Non-zero values are considered to be within
        the target region.
    include : bool, default True
        If True, streamlines passing through `target_mask` are kept. If False,
        the streamlines not passing through `target_mask` are kept.

    Returns
    -------
    streamlines : generator
        A sequence of streamlines that pass through `target_mask`.

    Raises
    ------
    ValueError
        When the points of the streamlines lie outside of the `target_mask`.

    See Also
    --------
    density_map
    """
    target_mask = np.array(target_mask, dtype=bool, copy=True)
    lin_T, offset = _mapping_to_voxel(affine)
    yield
    # End of initialization

    for sl in streamlines:
        try:
            ind = _to_voxel_coordinates(sl, lin_T, offset)
            i, j, k = ind.T
            state = target_mask[i, j, k]
        except IndexError:
            raise ValueError("streamlines points are outside of target_mask")
        if state.any() == include:
            if strict == 'strict':
                yield sl[state == include]
            elif strict == 'longstring':
                longsl=longstring(state == include,margin=2)
                yield sl[longsl]
            else:
                yield sl
Exemplo n.º 13
0
def path_length(streamlines, affine, aoi, fill_value=-1):
    """Compute the shortest path, along any streamline, between aoi and
    each voxel.

    Parameters
    ----------
    streamlines : seq of (N, 3) arrays
        A sequence of streamlines, path length is given in mm along the curve
        of the streamline.
    aoi : array, 3d
        A mask (binary array) of voxels from which to start computing distance.
    affine : array (4, 4)
        The mapping between voxel indices and the point space for seeds.
        The voxel_to_rasmm matrix, typically from a NIFTI file.
    fill_value : float
        The value of voxel in the path length map that are not connected to the
        aoi.

    Returns
    -------
    plm : array
        Same shape as aoi. The minimum distance between every point and aoi
        along the path of a streamline.

    """
    aoi = np.asarray(aoi, dtype=bool)

    # path length map
    plm = np.empty(aoi.shape, dtype=float)
    plm[:] = np.inf
    lin_T, offset = _mapping_to_voxel(affine)
    for sl in streamlines:
        seg_ind = _to_voxel_coordinates(sl, lin_T, offset)
        i, j, k = seg_ind.T
        # Get where streamlines passes through aoi
        breaks = aoi[i, j, k]
        # Where streamline passes aoi, dist is zero
        i, j, k = seg_ind[breaks].T
        plm[i, j, k] = 0

        # If a streamline crosses aoi >1, re-start counting distance for each
        for seg in _as_segments(sl, breaks):
            i, j, k = _to_voxel_coordinates(seg[1:], lin_T, offset).T
            # Get the distance, in mm, between streamline points
            segment_length = np.sqrt(((seg[1:] - seg[:-1])**2).sum(1))
            dist = segment_length.cumsum()
            # Updates path length map with shorter distances
            minimum_at(plm, (i, j, k), dist)
    if fill_value != np.inf:
        plm = np.where(plm == np.inf, fill_value, plm)
    return plm
Exemplo n.º 14
0
def target_line_based(streamlines, affine, target_mask, include=True):
    """Filter streamlines based on whether or not they pass through a ROI,
    using a line-based algorithm. Mostly used as a replacement of `target`
    for compressed streamlines.

    This function never returns single-point streamlines, whatever the
    value of `include`.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines. Each streamline should be a (N, 3) array,
        where N is the length of the streamline.
    affine : array (4, 4)
        The mapping between voxel indices and the point space for seeds.
        The voxel_to_rasmm matrix, typically from a NIFTI file.
    target_mask : array-like
        A mask used as a target. Non-zero values are considered to be within
        the target region.
    include : bool, default True
        If True, streamlines passing through `target_mask` are kept. If False,
        the streamlines not passing through `target_mask` are kept.

    Returns
    -------
    streamlines : generator
        A sequence of streamlines that pass through `target_mask`.

    References
    ----------
    [Bresenham5] Bresenham, Jack Elton. "Algorithm for computer control of a
                 digital plotter", IBM Systems Journal, vol 4, no. 1, 1965.
    [Houde15] Houde et al. How to avoid biased streamlines-based metrics for
              streamlines with variable step sizes, ISMRM 2015.

    See Also
    --------
    dipy.tracking.utils.density_map
    dipy.tracking.streamline.compress_streamlines

    """
    target_mask = np.array(target_mask, dtype=np.uint8, copy=True)
    lin_T, offset = _mapping_to_voxel(affine)
    streamline_index = _streamlines_in_mask(streamlines, target_mask, lin_T,
                                            offset)
    yield
    # End of initialization

    for idx in np.where(streamline_index == [0, 1][include])[0]:
        yield streamlines[idx]
Exemplo n.º 15
0
def path_length(streamlines, aoi, affine, fill_value=-1):
    """ Computes the shortest path, along any streamline, between aoi and
    each voxel.

    Parameters
    ----------
    streamlines : seq of (N, 3) arrays
        A sequence of streamlines, path length is given in mm along the curve
        of the streamline.
    aoi : array, 3d
        A mask (binary array) of voxels from which to start computing distance.
    affine : array (4, 4)
        The mapping from voxel indices to streamline points.
    fill_value : float
        The value of voxel in the path length map that are not connected to the
        aoi.

    Returns
    -------
    plm : array
        Same shape as aoi. The minimum distance between every point and aoi
        along the path of a streamline.
    """
    aoi = np.asarray(aoi, dtype=bool)

    # path length map
    plm = np.empty(aoi.shape, dtype=float)
    plm[:] = np.inf
    lin_T, offset = _mapping_to_voxel(affine, None)
    for sl in streamlines:
        seg_ind = _to_voxel_coordinates(sl, lin_T, offset)
        i, j, k = seg_ind.T
        # Get where streamlines passes through aoi
        breaks = aoi[i, j, k]
        # Where streamline passes aoi, dist is zero
        i, j, k = seg_ind[breaks].T
        plm[i, j, k] = 0

        # If a streamline crosses aoi >1, re-start counting distance for each
        for seg in _as_segments(sl, breaks):
            i, j, k = _to_voxel_coordinates(seg[1:], lin_T, offset).T
            # Get the distance, in mm, between streamline points
            segment_length = np.sqrt(((seg[1:] - seg[:-1]) ** 2).sum(1))
            dist = segment_length.cumsum()
            # Updates path length map with shorter distances
            minimum_at(plm, (i, j, k), dist)
    if fill_value != np.inf:
        plm = np.where(plm == np.inf, fill_value, plm)
    return plm
Exemplo n.º 16
0
def target_line_based(streamlines, target_mask, affine=None, include=True):
    # Copy-Paste from Dipy to get indices
    target_mask = np.array(target_mask, dtype=np.uint8, copy=True)
    lin_T, offset = _mapping_to_voxel(affine)

    streamline_index = _streamlines_in_mask(
        streamlines, target_mask, lin_T, offset)

    target_indices = []
    target_streamlines = []
    for idx in np.where(streamline_index == [0, 1][include])[0]:
        target_indices.append(idx)
        target_streamlines.append(streamlines[idx])

    return target_streamlines, target_indices
Exemplo n.º 17
0
def target_line_based(streamlines, target_mask, affine=None, include=True):
    """Filters streamlines based on whether or not they pass through a ROI,
    using a line-based algorithm. Mostly used as a replacement of `target`
    for compressed streamlines.

    This function never returns single-point streamlines, whatever the
    value of `include`.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines. Each streamline should be a (N, 3) array,
        where N is the length of the streamline.
    target_mask : array-like
        A mask used as a target. Non-zero values are considered to be within
        the target region.
    affine : array (4, 4)
        The affine transform from voxel indices to streamline points.
    include : bool, default True
        If True, streamlines passing through `target_mask` are kept. If False,
        the streamlines not passing through `target_mask` are kept.

    Returns
    -------
    streamlines : generator
        A sequence of streamlines that pass through `target_mask`.

    References
    ----------
    [Bresenham5] Bresenham, Jack Elton. "Algorithm for computer control of a
                 digital plotter", IBM Systems Journal, vol 4, no. 1, 1965.
    [Houde15] Houde et al. How to avoid biased streamlines-based metrics for
              streamlines with variable step sizes, ISMRM 2015.

    See Also
    --------
    dipy.tracking.utils.density_map
    dipy.tracking.streamline.compress_streamlines
    """
    target_mask = np.array(target_mask, dtype=np.uint8, copy=True)
    lin_T, offset = _mapping_to_voxel(affine, voxel_size=None)
    streamline_index = _streamlines_in_mask(
        streamlines, target_mask, lin_T, offset)
    yield
    # End of initialization

    for idx in np.where(streamline_index == [0, 1][include])[0]:
        yield streamlines[idx]
Exemplo n.º 18
0
def streamline_pruning(streamlines,
                       label_volume,
                       voxel_size=None,
                       affine=None):
    """Cut streamlines such that it only connects two regions of interests

    Parameters
    ----------
    streamlines : sequence
        A sequence of streamlines.
    label_volume : ndarray
        An image volume with an integer data type, where the intensities in the
        volume map to anatomical structures.
    voxel_size :
        This argument is deprecated.
    affine : array_like (4, 4)
        The mapping from voxel coordinates to streamline coordinates.
    """

    # Error checking on label_volume
    kind = label_volume.dtype.kind
    labels_positive = ((kind == 'u')
                       or ((kind == 'i') and (label_volume.min() >= 0)))
    valid_label_volume = (labels_positive and label_volume.ndim == 3)
    if not valid_label_volume:
        raise ValueError("label_volume must be a 3d integer array with"
                         "non-negative label values")

    streamlines = list(streamlines)
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)

    # for each streamlines, we will check it and cut it.
    new_streamlines = []
    for sl in streamlines:
        # Map the streamlines coordinates to voxel coordinates
        sl_volidx = _to_voxel_coordinates(sl, lin_T, offset)
        sl_labels = label_volume[sl_volidx[:, 0], sl_volidx[:, 1],
                                 sl_volidx[:, 2]]
        temp_streamlines, num_sl = streamline_cut(sl, sl_labels)
        if (num_sl == 1):
            curr_sl = temp_streamlines
            new_streamlines.append(curr_sl)
        else:
            for i in range(0, num_sl):
                curr_sl = temp_streamlines[i]
                new_streamlines.append(curr_sl)

    return new_streamlines
Exemplo n.º 19
0
def bundle_map(bundle, affine, img_shape, dir_out, cnt_out):

    lin_T, offset = _mapping_to_voxel(affine)

    for tract in bundle:
        inds = _to_voxel_coordinates(tract.streamline, lin_T, offset)
        i, j, k = inds.T
        cnt_out[i, j, k] += np.uint16(1)
        vecs = tract.data_for_points["t"].astype(np.float16)
        dir_out[i, j, k] += vecs * safe_sign(
            np.sum(dir_out[i, j, k] * vecs, axis=1, keepdims=True))

    dir_out /= (np.expand_dims(cnt_out, -1) + np.float16(10**-6))

    dir_out /= (np.linalg.norm(dir_out, axis=-1, keepdims=True) +
                np.float16(10**-6))
Exemplo n.º 20
0
def vol_map(streamlines, affine, vol_vec, vol_dims):
    from dipy.tracking._utils import (_mapping_to_voxel, _to_voxel_coordinates)
    """Calculates the mean volume of the streamlines that pass through each voxel.
    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines.
    affine : array_like (4, 4)
        The mapping from voxel coordinates to streamline points.
        The voxel_to_rasmm matrix, typically from a NIFTI file.
    vol_vec : ndarray, shape (1, N) while N is the number of streamlines
        The volume (ADD for example) according which the code calculates the new image.
    vol_dims : 3 ints
        The shape of the volume to be returned containing the streamlines
        counts
    Returns
    -------
    vol_vox : ndarray, shape=vol_dims
        The mean volume of the streamlines that pass through each voxel.
    Raises
    ------
    IndexError
        When the points of the streamlines lie outside of the return volume.
    Notes
    -----
    A streamline can pass through a voxel even if one of the points of the
    streamline does not lie in the voxel. For example a step from [0,0,0] to
    [0,0,2] passes through [0,0,1]. Consider subsegmenting the streamlines when
    the edges of the voxels are smaller than the steps of the streamlines.
    """
    streamlines = set_number_of_points(streamlines, 50)
    lin_T, offset = _mapping_to_voxel(affine)
    counts = np.zeros(vol_dims, 'int')
    vols_sum = np.zeros(vol_dims, 'float64')
    for sl, vl in zip(streamlines, vol_vec):
        inds = _to_voxel_coordinates(sl, lin_T, offset)
        i, j, k = inds.T
        # this takes advantage of the fact that numpy's += operator only
        # acts once even if there are repeats in inds
        counts[i, j, k] += 1
        vols_sum[i, j, k] += vl
    vox_vol = np.true_divide(vols_sum,
                             counts,
                             out=np.zeros_like(vols_sum),
                             where=counts != 0)

    return vox_vol
Exemplo n.º 21
0
def target(streamlines, target_mask, affine, include=True):
    """Filters streamlines based on whether or not they pass through an ROI.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines. Each streamline should be a (N, 3) array,
        where N is the length of the streamline.
    target_mask : array-like
        A mask used as a target. Non-zero values are considered to be within
        the target region.
    affine : array (4, 4)
        The affine transform from voxel indices to streamline points.
    include : bool, default True
        If True, streamlines passing through `target_mask` are kept. If False,
        the streamlines not passing through `target_mask` are kept.

    Returns
    -------
    streamlines : generator
        A sequence of streamlines that pass through `target_mask`.

    Raises
    ------
    ValueError
        When the points of the streamlines lie outside of the `target_mask`.

    See Also
    --------
    density_map

    """
    target_mask = np.array(target_mask, dtype=bool, copy=True)
    lin_T, offset = _mapping_to_voxel(affine, voxel_size=None)
    yield
    # End of initialization

    for sl in streamlines:
        try:
            ind = _to_voxel_coordinates(sl, lin_T, offset)
            i, j, k = ind.T
            state = target_mask[i, j, k]
        except IndexError:
            raise ValueError("streamlines points are outside of target_mask")
        if state.any() == include:
            yield sl
Exemplo n.º 22
0
def connectivity_matrix2(streamlines,
                         label_volume,
                         affine,
                         shape,
                         voxel_size=None):
    endpoints = [sl for sl in streamlines]
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    # endpoints = _to_voxel_coordinates(streamlines, lin_T, offset)
    # endpoints = endpoints.astype(int)
    # streamlines = list(endpoints)
    # endlabels2 = label_volume[i2, j2, k2]
    myList = []
    indexROI = np.unique(label_volume)
    indexROI.sort(0)
    matriz = np.zeros(shape=(len(indexROI), len(indexROI)))
    from decimal import Decimal

    print("ROI Number = " + str(len(indexROI)))

    for ROI in indexROI:
        ROIimg = (label_volume == ROI)
        ROIimg = ROIimg.astype(int)

        for ROI2 in indexROI:
            # if ((ROI == 1) & (ROI2 == 2)):
            if (1):
                if (ROI2 > ROI):
                    ROI2img = (label_volume == ROI2)
                    ROI2img = ROI2img.astype(int)

                    for sl in streamlines:
                        # sl += offset
                        sl_Aux = sl
                        sl = _to_voxel_coordinates(sl, lin_T, offset)
                        i, j, k = sl.T
                        # i2, j2, k2 = endpoints.T

                        labelsROI = ROIimg[i, j, k]
                        labelsROI2 = ROI2img[i, j, k]

                        if ((sum(labelsROI) > 0) & (sum(labelsROI2) > 0)):
                            matriz[ROI, ROI2] = matriz[ROI, ROI2] + 1
                            # myList.append(sl_Aux)
        print(ROI)

    return matriz.astype(int)
Exemplo n.º 23
0
def test_create_density_map():
    """
    Test for create_density_map functionality
    """
    from pynets.dmri import track
    from dipy.tracking._utils import _mapping_to_voxel

    base_dir = os.path.abspath(
        pkg_resources.resource_filename("pynets", "../data/examples"))
    dir_path = f"{base_dir}/BIDS/sub-25659/ses-1/dwi"
    dwi_file = f"{base_dir}/BIDS/sub-25659/ses-1/dwi/final_preprocessed_" \
               f"dwi.nii.gz"
    dwi_img = nib.load(dwi_file)

    # Load output from test_filter_streamlines: dictionary of streamline info
    streamlines_trk = f"{base_dir}/miscellaneous/streamlines_model-csd_" \
                      f"nodetype-parc_tracktype-local_traversal-prob_" \
                      f"minlength-0.trk"
    streamlines = nib.streamlines.load(streamlines_trk).streamlines

    # Remove streamlines with negative voxel indices
    lin_T, offset = _mapping_to_voxel(np.eye(4))
    streams_final_filt_final = []
    for sl in streamlines:
        inds = np.dot(sl, lin_T)
        inds += offset
        if not inds.min().round(decimals=6) < 0:
            streams_final_filt_final.append(sl)

    conn_model = 'csd'
    node_radius = None
    curv_thr_list = [40, 30]
    step_list = [0.1, 0.2, 0.3, 0.4, 0.5]
    subnet = None
    roi = None
    traversal = 'prob'
    max_length = 0

    [dir_path, dm_path
     ] = track.create_density_map(dwi_img, dir_path, streams_final_filt_final,
                                  conn_model, node_radius, curv_thr_list,
                                  step_list, subnet, roi, traversal,
                                  max_length, '/tmp')

    assert dir_path is not None
    assert dm_path is not None
Exemplo n.º 24
0
def target(streamlines, target_mask, affine, include=True):
    """Filters streamlines based on whether or not they pass through an ROI.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines. Each streamline should be a (N, 3) array,
        where N is the length of the streamline.
    target_mask : array-like
        A mask used as a target. Non-zero values are considered to be within
        the target region.
    affine : array (4, 4)
        The affine transform from voxel indices to streamline points.
    include : bool, default True
        If True, streamlines passing through `target_mask` are kept. If False,
        the streamlines not passing through `target_mask` are kept.

    Returns
    -------
    streamlines : generator
        A sequence of streamlines that pass through `target_mask`.

    Raises
    ------
    ValueError
        When the points of the streamlines lie outside of the `target_mask`.

    See Also
    --------
    density_map

    """
    target_mask = np.array(target_mask, dtype=bool, copy=True)
    lin_T, offset = _mapping_to_voxel(affine, voxel_size=None)
    yield
    # End of initialization

    for sl in streamlines:
        try:
            ind = _to_voxel_coordinates(sl, lin_T, offset)
            i, j, k = ind.T
            state = target_mask[i, j, k]
        except IndexError:
            raise ValueError("streamlines points are outside of target_mask")
        if state.any() == include:
            yield sl
Exemplo n.º 25
0
def density_map(streamlines, vol_dims, affine=None):
    """Counts the number of unique streamlines that pass through each voxel.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines.

    vol_dims : 3 ints
        The shape of the volume to be returned containing the streamlines
        counts
    affine : array_like (4, 4)
        The mapping from voxel coordinates to streamline points.

    Returns
    -------
    image_volume : ndarray, shape=vol_dims
        The number of streamline points in each voxel of volume.

    Raises
    ------
    IndexError
        When the points of the streamlines lie outside of the return volume.

    Notes
    -----
    A streamline can pass through a voxel even if one of the points of the
    streamline does not lie in the voxel. For example a step from [0,0,0] to
    [0,0,2] passes through [0,0,1]. Consider subsegmenting the streamlines when
    the edges of the voxels are smaller than the steps of the streamlines.

    """
    if affine is None:
        affine = np.eye(4)

    lin_T, offset = _mapping_to_voxel(affine)
    counts = np.zeros(vol_dims, 'int')
    for sl in streamlines:
        inds = _to_voxel_coordinates(sl, lin_T, offset)
        i, j, k = inds.T
        # this takes advantage of the fact that numpy's += operator only
        # acts once even if there are repeats in inds
        counts[i, j, k] += 1
    return counts
Exemplo n.º 26
0
def test_create_density_map():
    """
    Test for create_density_map functionality
    """
    from pynets.dmri import track
    from dipy.tracking._utils import _mapping_to_voxel

    base_dir = str(Path(__file__).parent / "examples")
    dir_path = f"{base_dir}/BIDS/sub-0025427/ses-1/dwi"
    dwi_file = f"{base_dir}/BIDS/sub-0025427/ses-1/dwi/final_preprocessed_dwi.nii.gz"
    dwi_img = nib.load(dwi_file)

    # Load output from test_filter_streamlines: dictionary of streamline info
    streamlines_trk = f"{base_dir}/miscellaneous/streamlines_est-csd_nodetype-parc_samples-10000streams_tt-local_dg-prob_ml-0.trk"
    streamlines = nib.streamlines.load(streamlines_trk).streamlines

    # Remove streamlines with negative voxel indices
    lin_T, offset = _mapping_to_voxel(np.eye(4))
    streams_final_filt_final = []
    for sl in streamlines:
        inds = np.dot(sl, lin_T)
        inds += offset
        if not inds.min().round(decimals=6) < 0:
            streams_final_filt_final.append(sl)

    conn_model = 'csd'
    target_samples = 10000
    node_size = None
    curv_thr_list = [40, 30]
    step_list = [0.1, 0.2, 0.3, 0.4, 0.5]
    network = None
    roi = None
    directget = 'prob'
    max_length = 0

    [streams, dir_path, dm_path
     ] = track.create_density_map(dwi_img, dir_path, streams_final_filt_final,
                                  conn_model, target_samples, node_size,
                                  curv_thr_list, step_list, network, roi,
                                  directget, max_length)

    assert streams is not None
    assert dir_path is not None
    assert dm_path is not None
Exemplo n.º 27
0
def density_map(streamlines, vol_dims, voxel_size=None, affine=None):
    """Counts the number of unique streamlines that pass through each voxel.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines.

    vol_dims : 3 ints
        The shape of the volume to be returned containing the streamlines
        counts
    voxel_size :
        This argument is deprecated.
    affine : array_like (4, 4)
        The mapping from voxel coordinates to streamline points.

    Returns
    -------
    image_volume : ndarray, shape=vol_dims
        The number of streamline points in each voxel of volume.

    Raises
    ------
    IndexError
        When the points of the streamlines lie outside of the return volume.

    Notes
    -----
    A streamline can pass through a voxel even if one of the points of the
    streamline does not lie in the voxel. For example a step from [0,0,0] to
    [0,0,2] passes through [0,0,1]. Consider subsegmenting the streamlines when
    the edges of the voxels are smaller than the steps of the streamlines.

    """
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    counts = np.zeros(vol_dims, 'int')
    for sl in streamlines:
        inds = _to_voxel_coordinates(sl, lin_T, offset)
        i, j, k = inds.T
        # this takes advantage of the fact that numpy's += operator only
        # acts once even if there are repeats in inds
        counts[i, j, k] += 1
    return counts
Exemplo n.º 28
0
def rois_connectedvol_matinput(label_img,
                               N,
                               groupsl,
                               voxel_size=None,
                               affine=None):
    # input: label_img: image of labels, index from 0 - N
    #        N: # of ROIs
    #        groupsl: streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        voxel_size, affine: some parameters to transfore streamlines to voxel
    ROI_vol = roi_volume_extraction(label_img, N)
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)

    connectedvolratio_cm = np.zeros([N, N])
    connectedvol_cm = np.zeros([N, N])
    [N1, N2] = groupsl.shape

    for i in range(0, N1 - 1):  #starting from 0
        for j in range(i + 1, N2):
            tmp_streamlines = groupsl[i, j]

            Nfibers = 0
            if (len(tmp_streamlines) > 2):
                [tmp1, tmp2, Nfibers] = tmp_streamlines.shape

            tmpstartp = []
            tmpendp = []
            for n in range(0, Nfibers):
                tmp = tmp_streamlines[:, :, n]
                sl = tmp.transpose(
                )  #flip the matrix to get the right input for extracting fa;
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)
                ii, jj, kk = slpoints.T
                newlabel_img = label_img[ii, jj, kk]
                tmpstartp.append(ii[1] * 1000000 + jj[1] * 1000 + kk[1])
                tmpendp.append(ii[-1] * 1000000 + jj[-1] * 1000 + kk[-1])
            nstartp_ratio = len(list(set(tmpstartp))) / (ROI_vol[i])
            nendp_ratio = len(list(set(tmpendp))) / (ROI_vol[j])
            nstartp = len(list(set(tmpstartp)))
            nendp = len(list(set(tmpendp)))
            connectedvol_cm[i, j] = (nstartp + nendp)
            connectedvolratio_cm[i, j] = (nstartp_ratio + nendp_ratio) / 2

    return connectedvol_cm, connectedvolratio_cm
Exemplo n.º 29
0
def streamline_endpoints(streamlines,
                         label_volume,
                         voxel_size=None,
                         affine=None):
    # input: streamlines, input streamlines
    #        anaimg, input image
    endpointimg = np.zeros(label_volume.shape, dtype='int')

    # get the ending points of streamlines
    streamlines = list(streamlines)
    endpoints = [sl[0::len(sl) - 1] for sl in streamlines]

    # Map the streamlines coordinates to voxel coordinates
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    endpoints = _to_voxel_coordinates(endpoints, lin_T, offset)

    i, j, k = endpoints.T
    endpointimg[i, j, k] = 1

    return endpointimg
Exemplo n.º 30
0
def rois_connectedvol_cellinput(label_img,
                                N,
                                cell_streamlines,
                                cell_id,
                                voxel_size=None,
                                affine=None):
    # input: label_img: image of labels, index from 0 - N
    #        N: # of ROIs
    #        groupsl: streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        voxel_size, affine: some parameters to transfore streamlines to voxel
    ROI_vol = roi_volume_extraction_cellinput(label_img, N)
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)

    connectedvolratio_cm = np.zeros([N, N])
    connectedvol_cm = np.zeros([N, N])

    idx = 0
    for i in range(1, N):
        for j in range(i + 1, N):
            tmp_streamlines = cell_streamlines[idx]
            idx = idx + 1

            tmpstartp = []
            tmpendp = []
            for sl in tmp_streamlines:
                #sl = tmp.transpose() #flip the matrix to get the right input for extracting fa;
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)
                ii, jj, kk = slpoints.T
                newlabel_img = label_img[ii, jj, kk]
                tmpstartp.append(ii[1] * 1000000 + jj[1] * 1000 + kk[1])
                tmpendp.append(ii[-1] * 1000000 + jj[-1] * 1000 + kk[-1])
            nstartp_ratio = len(list(set(tmpstartp))) / (ROI_vol[i])
            nendp_ratio = len(list(set(tmpendp))) / (ROI_vol[j])
            nstartp = len(list(set(tmpstartp)))
            nendp = len(list(set(tmpendp)))
            connectedvol_cm[i, j] = (nstartp + nendp)
            connectedvolratio_cm[i, j] = (nstartp_ratio + nendp_ratio) / 2

    return connectedvol_cm, connectedvolratio_cm
Exemplo n.º 31
0
def fa_extraction_use_matinput(
    groupsl,
    fa_vol,
    N,
    voxel_size=None,
    affine=None,
):
    # input: groupsl, streamlines connecting ith and jth ROIs, groupsl[i,j]
    #        fa_vol, fa values in the image domain
    #        N, # of ROIs
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    fa_group = defaultdict(list)

    [N1, N2] = groupsl.shape

    for i in range(0, N1):
        for j in range(i + 1, N2):
            tmp_streamlines = groupsl[i, j]

            Nfibers = 0
            if (len(tmp_streamlines) > 2):
                [tmp1, tmp2, Nfibers] = tmp_streamlines.shape

            fa_streamlines = []
            for n in range(0, Nfibers):
                tmp = tmp_streamlines[:, :, n]
                sl = tmp.transpose(
                )  #flip the matrix to get the right input for extracting fa;
                slpoints = _to_voxel_coordinates(sl, lin_T, offset)

                #get FA for each streamlines
                ii, jj, kk = slpoints.T
                fa_value = fa_vol[ii, jj, kk]
                fa_streamlines.append(fa_value)
            fa_group[i, j].append(fa_streamlines)
    return fa_group
Exemplo n.º 32
0
def connectivity_matrix(streamlines, label_volume, voxel_size=None,
                        affine=None, symmetric=True, return_mapping=False,
                        mapping_as_streamlines=False):
    """Counts the streamlines that start and end at each label pair.

    Parameters
    ----------
    streamlines : sequence
        A sequence of streamlines.
    label_volume : ndarray
        An image volume with an integer data type, where the intensities in the
        volume map to anatomical structures.
    voxel_size :
        This argument is deprecated.
    affine : array_like (4, 4)
        The mapping from voxel coordinates to streamline coordinates.
    symmetric : bool, True by default
        Symmetric means we don't distinguish between start and end points. If
        symmetric is True, ``matrix[i, j] == matrix[j, i]``.
    return_mapping : bool, False by default
        If True, a mapping is returned which maps matrix indices to
        streamlines.
    mapping_as_streamlines : bool, False by default
        If True voxel indices map to lists of streamline objects. Otherwise
        voxel indices map to lists of integers.

    Returns
    -------
    matrix : ndarray
        The number of connection between each pair of regions in
        `label_volume`.
    mapping : defaultdict(list)
        ``mapping[i, j]`` returns all the streamlines that connect region `i`
        to region `j`. If `symmetric` is True mapping will only have one key
        for each start end pair such that if ``i < j`` mapping will have key
        ``(i, j)`` but not key ``(j, i)``.

    """
    # Error checking on label_volume
    kind = label_volume.dtype.kind
    labels_positive = ((kind == 'u') or
                       ((kind == 'i') and (label_volume.min() >= 0)))
    valid_label_volume = (labels_positive and label_volume.ndim == 3)
    if not valid_label_volume:
        raise ValueError("label_volume must be a 3d integer array with"
                         "non-negative label values")

    # If streamlines is an iterators
    if return_mapping and mapping_as_streamlines:
        streamlines = list(streamlines)
    # take the first and last point of each streamline
    endpoints = [sl[0::len(sl)-1] for sl in streamlines]

    # Map the streamlines coordinates to voxel coordinates
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    endpoints = _to_voxel_coordinates(endpoints, lin_T, offset)

    # get labels for label_volume
    i, j, k = endpoints.T
    endlabels = label_volume[i, j, k]
    if symmetric:
        endlabels.sort(0)
    mx = label_volume.max() + 1
    matrix = ndbincount(endlabels, shape=(mx, mx))
    if symmetric:
        matrix = np.maximum(matrix, matrix.T)

    if return_mapping:
        mapping = defaultdict(list)
        for i, (a, b) in enumerate(endlabels.T):
            mapping[a, b].append(i)

        # Replace each list of indices with the streamlines they index
        if mapping_as_streamlines:
            for key in mapping:
                mapping[key] = [streamlines[i] for i in mapping[key]]

        # Return the mapping matrix and the mapping
        return matrix, mapping
    else:
        return matrix
Exemplo n.º 33
0
def connectivity_matrix(streamlines, label_volume, voxel_size=None,
                        affine=None, symmetric=True, return_mapping=False,
                        mapping_as_streamlines=False):
    """Counts the streamlines that start and end at each label pair.

    Parameters
    ----------
    streamlines : sequence
        A sequence of streamlines.
    label_volume : ndarray
        An image volume with an integer data type, where the intensities in the
        volume map to anatomical structures.
    voxel_size :
        This argument is deprecated.
    affine : array_like (4, 4)
        The mapping from voxel coordinates to streamline coordinates.
    symmetric : bool, False by default
        Symmetric means we don't distinguish between start and end points. If
        symmetric is True, ``matrix[i, j] == matrix[j, i]``.
    return_mapping : bool, False by default
        If True, a mapping is returned which maps matrix indices to
        streamlines.
    mapping_as_streamlines : bool, False by default
        If True voxel indices map to lists of streamline objects. Otherwise
        voxel indices map to lists of integers.

    Returns
    -------
    matrix : ndarray
        The number of connection between each pair of regions in
        `label_volume`.
    mapping : defaultdict(list)
        ``mapping[i, j]`` returns all the streamlines that connect region `i`
        to region `j`. If `symmetric` is True mapping will only have one key
        for each start end pair such that if ``i < j`` mapping will have key
        ``(i, j)`` but not key ``(j, i)``.

    """
    # Error checking on label_volume
    kind = label_volume.dtype.kind
    labels_positive = ((kind == 'u') or
                       ((kind == 'i') and (label_volume.min() >= 0)))
    valid_label_volume = (labels_positive and label_volume.ndim == 3)
    if not valid_label_volume:
        raise ValueError("label_volume must be a 3d integer array with"
                         "non-negative label values")

    # If streamlines is an iterators
    if return_mapping and mapping_as_streamlines:
        streamlines = list(streamlines)
    # take the first and last point of each streamline
    endpoints = [sl[0::len(sl)-1] for sl in streamlines]

    # Map the streamlines coordinates to voxel coordinates
    lin_T, offset = _mapping_to_voxel(affine, voxel_size)
    endpoints = _to_voxel_coordinates(endpoints, lin_T, offset)

    # get labels for label_volume
    i, j, k = endpoints.T
    endlabels = label_volume[i, j, k]
    if symmetric:
        endlabels.sort(0)
    mx = label_volume.max() + 1
    matrix = ndbincount(endlabels, shape=(mx, mx))
    if symmetric:
        matrix = np.maximum(matrix, matrix.T)

    if return_mapping:
        mapping = defaultdict(list)
        for i, (a, b) in enumerate(endlabels.T):
            mapping[a, b].append(i)

        # Replace each list of indices with the streamlines they index
        if mapping_as_streamlines:
            for key in mapping:
                mapping[key] = [streamlines[i] for i in mapping[key]]

        # Return the mapping matrix and the mapping
        return matrix, mapping
    else:
        return matrix
	def _run_interface(self, runtime):
		# Loading the ROI file
	    from dipy.tracking import utils 
	    import nibabel as nib
	    import numpy as np
	    import os 
	    
	    img = nib.load(self.inputs.ROI_file)
	    data = img.get_data()
	    affine = img.get_affine()

	    # Getting ROI volumes if they haven't been generated
		if not os.path.isfile('/imaging/jb07/CALM/DWI/FA_connectome/Atlas_volumes.csv'):
			import nibabel as nib
			import numpy as np
			import os 
			import pandas as pd
			import subprocess

			atlas_file = ROI_file
			img = nib.load(atlas_file)
			data = img.get_data()
			affine = img.get_affine()
			volumes = pd.DataFrame()

			atlas_labels = np.unique(data)

			for atlas_label in atlas_labels:
				data = nib.load(atlas_file).get_data()
				data[data != atlas_label] = 0 
				data[data == atlas_label] = 1
				nib.save(nib.Nifti1Image(data, affine), 'temp.nii.gz')
				volumes.set_value(atlas_label, 'volume', subprocess.check_output(os.environ['FSLDIR'] + '/bin/fslstats temp.nii.gz -V', shell=True).split(' ')[0])

			os.remove('temp.nii.gz')
			volumes.to_csv('/imaging/jb07/CALM/DWI/FA_connectome/Atlas_volumes.csv')

		ROI_volumes = pd.read_csv('/home/jb07/CALM/DWI/FA_connectome/Atlas_volumes.csv')

		# Getting the FA file
		img = nib.load(self.inputs.FA_file)
		FA_data = img.get_data()
		FA_affine = img.get_affine()

		# Loading the streamlines
		from nibabel import trackvis
		streams, hdr = trackvis.read(self.inputs.trackfile,points_space='rasmm')
		streamlines = [s[0] for s in streams]
		streamlines_affine = trackvis.aff_from_hdr(hdr,atleast_v2=True)

		# Checking for negative values
		from dipy.tracking._utils import _mapping_to_voxel, _to_voxel_coordinates
		endpoints = [sl[0::len(sl)-1] for sl in streamlines]
		lin_T, offset = _mapping_to_voxel(affine, (1.,1.,1.))
		inds = np.dot(endpoints, lin_T)
		inds += offset
		negative_values = np.where(inds <0)[0]
		for negative_value in sorted(negative_values, reverse=True):
			del streamlines[negative_value]

		# Constructing the streamlines matrix
		matrix,mapping = utils.connectivity_matrix(streamlines=streamlines,label_volume=data,affine=streamlines_affine,symmetric=True,return_mapping=True,mapping_as_streamlines=True)
		matrix[matrix < 10] = 0

		# Constructing the FA matrix
		dimensions = matrix.shape
		FA_matrix = np.empty(shape=dimensions)
		density_matrix = np.empty(shape=dimensions)
		density_corrected_matrix = np.empty(shape=dimensions)

		for i in range(0,dimensions[0]):
		    for j in range(0,dimensions[1]):
		        if matrix[i,j]:
		            dm = utils.density_map(mapping[i,j], FA_data.shape, affine=streamlines_affine)
		            FA_matrix[i,j] = np.mean(FA_data[dm>0])
		            if np.sum(dm > 0) > 0:
		            	density_matrix[i,j] = np.sum(dm[dm > 0])
		            	density_corrected_matrix[i,j] = np.sum(dm[dm > 0])/np.sum([ROI_volumes.iloc[i].values.astype('int'), ROI_volumes.iloc[j].values.astype('int')])
		            else: 
		            	density_matrix[i,j] = 0
		            	density_corrected_matrix[i,j] = 0
		        else:
		            FA_matrix[i,j] = 0
		            density_matrix[i,j] = 0
		            density_corrected_matrix[i,j] = 0

		FA_matrix[np.tril_indices(n=len(FA_matrix))] = 0
		FA_matrix = FA_matrix.T + FA_matrix - np.diagonal(FA_matrix)

		density_matrix[np.tril_indices(n=len(density_matrix))] = 0
		density_matrix = density_matrix.T + density_matrix - np.diagonal(density_matrix)

		density_corrected_matrix[np.tril_indices(n=len(density_corrected_matrix))] = 0
		density_corrected_matrix = density_corrected_matrix.T + density_corrected_matrix - np.diagonal(density_corrected_matrix)

		from nipype.utils.filemanip import split_filename
		_, base, _ = split_filename(self.inputs.trackfile)
		np.savetxt(base + '_FA_matrix.txt',FA_matrix,delimiter='\t')
		np.savetxt(base + '_density_matrix.txt',density_matrix,delimiter='\t')
		np.savetxt(base + '_volume_corrected_density_matrix.txt',density_corrected_matrix,delimiter='\t')
Exemplo n.º 35
0
def direct_streamline_norm(
    streams,
    fa_path,
    ap_path,
    dir_path,
    track_type,
    target_samples,
    conn_model,
    network,
    node_size,
    dens_thresh,
    ID,
    roi,
    min_span_tree,
    disp_filt,
    parc,
    prune,
    atlas,
    labels_im_file,
    uatlas,
    labels,
    coords,
    norm,
    binary,
    atlas_mni,
    basedir_path,
    curv_thr_list,
    step_list,
    directget,
    min_length,
    error_margin,
    t1_aligned_mni
):
    """
    A Function to perform normalization of streamlines tracked in native
    diffusion space to an MNI-space template.

    Parameters
    ----------
    streams : str
        File path to save streamline array sequence in .trk format.
    fa_path : str
        File path to FA Nifti1Image.
    ap_path : str
        File path to the anisotropic power Nifti1Image.
    dir_path : str
        Path to directory containing subject derivative data for a given
        pynets run.
    track_type : str
        Tracking algorithm used (e.g. 'local' or 'particle').
    target_samples : int
        Total number of streamline samples specified to generate streams.
    conn_model : str
        Connectivity reconstruction method (e.g. 'csa', 'tensor', 'csd').
    network : str
        Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default')
        used to filter nodes in the study of brain subgraphs.
    node_size : int
        Spherical centroid node size in the case that coordinate-based
        centroids are used as ROI's for tracking.
    dens_thresh : bool
        Indicates whether a target graph density is to be used as the basis for
        thresholding.
    ID : str
        A subject id or other unique identifier.
    roi : str
        File path to binarized/boolean region-of-interest Nifti1Image file.
    min_span_tree : bool
        Indicates whether local thresholding from the Minimum Spanning Tree
        should be used.
    disp_filt : bool
        Indicates whether local thresholding using a disparity filter and
        'backbone network' should be used.
    parc : bool
        Indicates whether to use parcels instead of coordinates as ROI nodes.
    prune : bool
        Indicates whether to prune final graph of disconnected nodes/isolates.
    atlas : str
        Name of atlas parcellation used.
    labels_im_file : str
        File path to atlas parcellation Nifti1Image aligned to dwi space.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.
    labels : list
        List of string labels corresponding to graph nodes.
    coords : list
        List of (x, y, z) tuples corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    norm : int
        Indicates method of normalizing resulting graph.
    binary : bool
        Indicates whether to binarize resulting graph edges to form an
        unweighted graph.
    atlas_mni : str
        File path to atlas parcellation Nifti1Image in T1w-warped MNI space.
    basedir_path : str
        Path to directory to output direct-streamline normalized temp files
        and outputs.
    curv_thr_list : list
        List of integer curvature thresholds used to perform ensemble tracking.
    step_list : list
        List of float step-sizes used to perform ensemble tracking.
    directget : str
        The statistical approach to tracking. Options are: det (deterministic),
        closest (clos), boot (bootstrapped), and prob (probabilistic).
    min_length : int
        Minimum fiber length threshold in mm to restrict tracking.
    t1_aligned_mni : str
        File path to the T1w Nifti1Image in template MNI space.

    Returns
    -------
    streams_warp : str
        File path to normalized streamline array sequence in .trk format.
    dir_path : str
        Path to directory containing subject derivative data for a given
        pynets run.
    track_type : str
        Tracking algorithm used (e.g. 'local' or 'particle').
    target_samples : int
        Total number of streamline samples specified to generate streams.
    conn_model : str
        Connectivity reconstruction method (e.g. 'csa', 'tensor', 'csd').
    network : str
        Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default')
        used to filter nodes in the study of brain subgraphs.
    node_size : int
        Spherical centroid node size in the case that coordinate-based
        centroids are used as ROI's for tracking.
    dens_thresh : bool
        Indicates whether a target graph density is to be used as the basis for
        thresholding.
    ID : str
        A subject id or other unique identifier.
    roi : str
        File path to binarized/boolean region-of-interest Nifti1Image file.
    min_span_tree : bool
        Indicates whether local thresholding from the Minimum Spanning Tree
        should be used.
    disp_filt : bool
        Indicates whether local thresholding using a disparity filter and
        'backbone network' should be used.
    parc : bool
        Indicates whether to use parcels instead of coordinates as ROI nodes.
    prune : bool
        Indicates whether to prune final graph of disconnected nodes/isolates.
    atlas : str
        Name of atlas parcellation used.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.
    labels : list
        List of string labels corresponding to graph nodes.
    coords : list
        List of (x, y, z) tuples corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    norm : int
        Indicates method of normalizing resulting graph.
    binary : bool
        Indicates whether to binarize resulting graph edges to form an
        unweighted graph.
    atlas_mni : str
        File path to atlas parcellation Nifti1Image in T1w-warped MNI space.
    directget : str
        The statistical approach to tracking. Options are: det
        (deterministic), closest (clos), boot (bootstrapped),
        and prob (probabilistic).
    warped_fa : str
        File path to MNI-space warped FA Nifti1Image.
    min_length : int
        Minimum fiber length threshold in mm to restrict tracking.

    References
    ----------
    .. [1] Greene, C., Cieslak, M., & Grafton, S. T. (2017). Effect of
      different spatial normalization approaches on tractography and structural
      brain networks. Network Neuroscience, 1-19.
    """
    import sys
    import gc
    from dipy.tracking.streamline import transform_streamlines
    from pynets.registration import reg_utils as regutils
    # from pynets.plotting import plot_gen
    import pkg_resources
    import yaml
    import os.path as op
    from pynets.registration.reg_utils import vdc
    from nilearn.image import resample_to_img
    from dipy.io.streamline import load_tractogram
    from dipy.tracking import utils
    from dipy.tracking._utils import _mapping_to_voxel
    from dipy.io.stateful_tractogram import Space, StatefulTractogram, Origin
    from dipy.io.streamline import save_tractogram

    # from pynets.core.utils import missing_elements

    with open(
        pkg_resources.resource_filename("pynets", "runconfig.yaml"), "r"
    ) as stream:
        try:
            hardcoded_params = yaml.load(stream)
            run_dsn = hardcoded_params['tracking']["DSN"][0]
        except FileNotFoundError as e:
            import sys
            print(e, "Failed to parse runconfig.yaml")
            exit(1)

    stream.close()

    if run_dsn is True:
        dsn_dir = f"{basedir_path}/dmri_reg/DSN"
        if not op.isdir(dsn_dir):
            os.mkdir(dsn_dir)

        namer_dir = f"{dir_path}/tractography"
        if not op.isdir(namer_dir):
            os.mkdir(namer_dir)

        atlas_img = nib.load(labels_im_file)

        # Run SyN and normalize streamlines
        fa_img = nib.load(fa_path)
        vox_size = fa_img.header.get_zooms()[0]
        template_path = pkg_resources.resource_filename(
            "pynets", f"templates/FA_{int(vox_size)}mm.nii.gz"
        )

        if sys.platform.startswith('win') is False:
            try:
                template_img = nib.load(template_path)
            except indexed_gzip.ZranError as e:
                print(e,
                      f"\nCannot load FA template. Do you have git-lfs "
                      f"installed?")
                sys.exit(1)
        else:
            try:
                template_img = nib.load(template_path)
            except ImportError as e:
                print(e, f"\nCannot load FA template. Do you have git-lfs "
                      f"installed?")
                sys.exit(1)

        uatlas_mni_img = nib.load(atlas_mni)
        t1_aligned_mni_img = nib.load(t1_aligned_mni)
        brain_mask = np.asarray(t1_aligned_mni_img.dataobj).astype("bool")

        streams_mni = "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % (
            namer_dir,
            "/streamlines_mni_",
            "%s" % (network + "_" if network is not None else ""),
            "%s" % (op.basename(roi).split(".")[0] + "_" if roi is not None
                    else ""),
            conn_model,
            "_",
            target_samples,
            "%s"
            % (
                "%s%s" % ("_" + str(node_size), "mm_")
                if ((node_size != "parc") and (node_size is not None))
                else "_"
            ),
            "curv",
            str(curv_thr_list).replace(", ", "_"),
            "step",
            str(step_list).replace(", ", "_"),
            "tracktype-",
            track_type,
            "_directget-",
            directget,
            "_minlength-",
            min_length,
            "_tol-",
            error_margin,
            ".trk",
        )

        density_mni = "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % (
            namer_dir,
            "/density_map_mni_",
            "%s" % (network + "_" if network is not None else ""),
            "%s" % (op.basename(roi).split(".")[0] + "_" if roi is not None
                    else ""),
            conn_model,
            "_",
            target_samples,
            "%s"
            % (
                "%s%s" % ("_" + str(node_size), "mm_")
                if ((node_size != "parc") and (node_size is not None))
                else "_"
            ),
            "curv",
            str(curv_thr_list).replace(", ", "_"),
            "step",
            str(step_list).replace(", ", "_"),
            "tracktype-",
            track_type,
            "_directget-",
            directget,
            "_minlength-",
            min_length,
            "_tol-",
            error_margin,
            ".nii.gz",
        )

        # streams_warp_png = '/tmp/dsn.png'

        # SyN FA->Template
        [mapping, affine_map, warped_fa] = regutils.wm_syn(
            template_path, fa_path, t1_aligned_mni, ap_path, dsn_dir
        )

        tractogram = load_tractogram(
            streams,
            fa_img,
            to_origin=Origin.NIFTI,
            to_space=Space.VOXMM,
            bbox_valid_check=False,
        )

        fa_img.uncache()
        streamlines = tractogram.streamlines
        warped_fa_img = nib.load(warped_fa)
        warped_fa_affine = warped_fa_img.affine
        warped_fa_shape = warped_fa_img.shape

        streams_in_curr_grid = transform_streamlines(
            streamlines, warped_fa_affine)

        # Create isocenter mapping where we anchor the origin transformation
        # affine to the corner of the FOV by scaling x, y, z offsets according
        # to a multiplicative van der Corput sequence with a base value equal
        # to the voxel resolution
        [x_mul, y_mul, z_mul] = [vdc(i, vox_size) for i in range(1, 4)]

        ref_grid_aff = vox_size * np.eye(4)
        ref_grid_aff[3][3] = 1

        streams_final_filt = []
        i = 0
        # Test for various types of voxel-grid configurations
        combs = [(-x_mul, -y_mul, -z_mul), (-x_mul, -y_mul, z_mul),
                 (-x_mul, y_mul, -z_mul), (x_mul, -y_mul, -z_mul),
                 (x_mul, y_mul, z_mul)]
        while len(streams_final_filt)/len(streams_in_curr_grid) < 0.90:
            print(f"Warping streamlines to MNI space. Attempt {i}...")
            print(len(streams_final_filt)/len(streams_in_curr_grid))
            adjusted_affine = affine_map.affine.copy()
            if i > len(combs) - 1:
                raise ValueError('DSN failed. Header orientation '
                                 'information may be corrupted. '
                                 'Is your dataset oblique?')

            adjusted_affine[0][3] = adjusted_affine[0][3] * combs[i][0]
            adjusted_affine[1][3] = adjusted_affine[1][3] * combs[i][1]
            adjusted_affine[2][3] = adjusted_affine[2][3] * combs[i][2]

            streams_final_filt = regutils.warp_streamlines(adjusted_affine,
                                                           ref_grid_aff,
                                                           mapping,
                                                           warped_fa_img,
                                                           streams_in_curr_grid,
                                                           brain_mask)

            i += 1

        # Remove streamlines with negative voxel indices
        lin_T, offset = _mapping_to_voxel(np.eye(4))
        streams_final_filt_final = []
        for sl in streams_final_filt:
            inds = np.dot(sl, lin_T)
            inds += offset
            if not inds.min().round(decimals=6) < 0:
                streams_final_filt_final.append(sl)

        # Save streamlines
        stf = StatefulTractogram(
            streams_final_filt_final,
            reference=uatlas_mni_img,
            space=Space.VOXMM,
            origin=Origin.NIFTI,
        )
        stf.remove_invalid_streamlines()
        streams_final_filt_final = stf.streamlines
        save_tractogram(stf, streams_mni, bbox_valid_check=True)
        warped_fa_img.uncache()

        # DSN QC plotting
        # plot_gen.show_template_bundles(streams_final_filt_final, atlas_mni,
        # streams_warp_png) plot_gen.show_template_bundles(streamlines,
        # fa_path, streams_warp_png)

        # Create and save MNI density map
        nib.save(
            nib.Nifti1Image(
                utils.density_map(
                    streams_final_filt_final,
                    affine=np.eye(4),
                    vol_dims=warped_fa_shape),
                warped_fa_affine,
            ),
            density_mni,
        )

        # Map parcellation from native space back to MNI-space and create an
        # 'uncertainty-union' parcellation with original mni-space uatlas
        warped_uatlas = affine_map.transform_inverse(
            mapping.transform(
                np.asarray(atlas_img.dataobj).astype("int"),
                interpolation="nearestneighbour",
            ),
            interp="nearest",
        )
        atlas_img.uncache()
        warped_uatlas_img_res_data = np.asarray(
            resample_to_img(
                nib.Nifti1Image(warped_uatlas, affine=warped_fa_affine),
                uatlas_mni_img,
                interpolation="nearest",
                clip=False,
            ).dataobj
        )
        uatlas_mni_data = np.asarray(uatlas_mni_img.dataobj)
        uatlas_mni_img.uncache()
        overlap_mask = np.invert(
            warped_uatlas_img_res_data.astype("bool") *
            uatlas_mni_data.astype("bool"))
        os.makedirs(f"{dir_path}/parcellations", exist_ok=True)
        atlas_mni = f"{dir_path}/parcellations/" \
                    f"{op.basename(uatlas).split('.nii')[0]}_liberal.nii.gz"

        nib.save(
            nib.Nifti1Image(
                warped_uatlas_img_res_data * overlap_mask.astype("int")
                + uatlas_mni_data * overlap_mask.astype("int")
                + np.invert(overlap_mask).astype("int")
                * warped_uatlas_img_res_data.astype("int"),
                affine=uatlas_mni_img.affine,
            ),
            atlas_mni,
        )

        del (
            tractogram,
            streamlines,
            warped_uatlas_img_res_data,
            uatlas_mni_data,
            overlap_mask,
            stf,
            streams_final_filt_final,
            streams_final_filt,
            streams_in_curr_grid,
            brain_mask,
        )

        gc.collect()

        assert len(coords) == len(labels)

    else:
        print(
            "Skipping Direct Streamline Normalization (DSN). Will proceed to "
            "define fiber connectivity in native diffusion space...")
        streams_mni = streams
        warped_fa = fa_path
        atlas_mni = labels_im_file

    return (
        streams_mni,
        dir_path,
        track_type,
        target_samples,
        conn_model,
        network,
        node_size,
        dens_thresh,
        ID,
        roi,
        min_span_tree,
        disp_filt,
        parc,
        prune,
        atlas,
        uatlas,
        labels,
        coords,
        norm,
        binary,
        atlas_mni,
        directget,
        warped_fa,
        min_length,
        error_margin
    )
Exemplo n.º 36
0
def streams2graph(atlas_mni, streams, dir_path, track_type, target_samples,
                  conn_model, network, node_size, dens_thresh, ID, roi,
                  min_span_tree, disp_filt, parc, prune, atlas, uatlas, labels,
                  coords, norm, binary, directget, warped_fa, min_length,
                  error_margin):
    """
    Use tracked streamlines as a basis for estimating a structural connectome.

    Parameters
    ----------
    atlas_mni : str
        File path to atlas parcellation Nifti1Image in T1w-warped MNI space.
    streams : str
        File path to streamline array sequence in .trk format.
    dir_path : str
        Path to directory containing subject derivative data for a given
        pynets run.
    track_type : str
        Tracking algorithm used (e.g. 'local' or 'particle').
    target_samples : int
        Total number of streamline samples specified to generate streams.
    conn_model : str
        Connectivity reconstruction method (e.g. 'csa', 'tensor', 'csd').
    network : str
        Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default')
        used to filter nodes in the study of brain subgraphs.
    node_size : int
        Spherical centroid node size in the case that coordinate-based
        centroids are used as ROI's for tracking.
    dens_thresh : bool
        Indicates whether a target graph density is to be used as the basis for
        thresholding.
    ID : str
        A subject id or other unique identifier.
    roi : str
        File path to binarized/boolean region-of-interest Nifti1Image file.
    min_span_tree : bool
        Indicates whether local thresholding from the Minimum Spanning Tree
        should be used.
    disp_filt : bool
        Indicates whether local thresholding using a disparity filter and
        'backbone network' should be used.
    parc : bool
        Indicates whether to use parcels instead of coordinates as ROI nodes.
    prune : bool
        Indicates whether to prune final graph of disconnected nodes/isolates.
    atlas : str
        Name of atlas parcellation used.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.
    labels : list
        List of string labels corresponding to graph nodes.
    coords : list
        List of (x, y, z) tuples corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    norm : int
        Indicates method of normalizing resulting graph.
    binary : bool
        Indicates whether to binarize resulting graph edges to form an
        unweighted graph.
    directget : str
        The statistical approach to tracking. Options are:
        det (deterministic), closest (clos), boot (bootstrapped),
        and prob (probabilistic).
    warped_fa : str
        File path to MNI-space warped FA Nifti1Image.
    min_length : int
        Minimum fiber length threshold in mm to restrict tracking.
    error_margin : int
        Euclidean margin of error for classifying a streamline as a connection
         to an ROI. Default is 2 voxels.

    Returns
    -------
    atlas_mni : str
        File path to atlas parcellation Nifti1Image in T1w-warped MNI space.
    streams : str
        File path to streamline array sequence in .trk format.
    conn_matrix : array
        Adjacency matrix stored as an m x n array of nodes and edges.
    track_type : str
        Tracking algorithm used (e.g. 'local' or 'particle').
    target_samples : int
        Total number of streamline samples specified to generate streams.
    dir_path : str
        Path to directory containing subject derivative data for given run.
    conn_model : str
        Connectivity reconstruction method (e.g. 'csa', 'tensor', 'csd').
    network : str
        Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default')
        used to filter nodes in the study of brain subgraphs.
    node_size : int
        Spherical centroid node size in the case that coordinate-based
        centroids are used as ROI's for tracking.
    dens_thresh : bool
        Indicates whether a target graph density is to be used as the basis for
        thresholding.
    ID : str
        A subject id or other unique identifier.
    roi : str
        File path to binarized/boolean region-of-interest Nifti1Image file.
    min_span_tree : bool
        Indicates whether local thresholding from the Minimum Spanning Tree
        should be used.
    disp_filt : bool
        Indicates whether local thresholding using a disparity filter and
        'backbone network' should be used.
    parc : bool
        Indicates whether to use parcels instead of coordinates as ROI nodes.
    prune : bool
        Indicates whether to prune final graph of disconnected nodes/isolates.
    atlas : str
        Name of atlas parcellation used.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.
    labels : list
        List of string labels corresponding to graph nodes.
    coords : list
        List of (x, y, z) tuples corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    norm : int
        Indicates method of normalizing resulting graph.
    binary : bool
        Indicates whether to binarize resulting graph edges to form an
        unweighted graph.
    directget : str
        The statistical approach to tracking. Options are: det (deterministic),
        closest (clos), boot (bootstrapped), and prob (probabilistic).
    min_length : int
        Minimum fiber length threshold in mm to restrict tracking.
    error_margin : int
        Euclidean margin of error for classifying a streamline as a connection
         to an ROI. Default is 2 voxels.

    References
    ----------
    .. [1] Sporns, O., Tononi, G., & Kötter, R. (2005). The human connectome:
      A structural description of the human brain. PLoS Computational Biology.
      https://doi.org/10.1371/journal.pcbi.0010042
    .. [2] Sotiropoulos, S. N., & Zalesky, A. (2019). Building connectomes
      using diffusion MRI: why, how and but. NMR in Biomedicine.
      https://doi.org/10.1002/nbm.3752
    .. [3] Chung, M. K., Hanson, J. L., Adluru, N., Alexander, A. L., Davidson,
      R. J., & Pollak, S. D. (2017). Integrative Structural Brain Network
      Analysis in Diffusion Tensor Imaging. Brain Connectivity.
      https://doi.org/10.1089/brain.2016.0481
    """
    import gc
    import time
    import pkg_resources
    import sys
    import yaml
    from dipy.tracking.streamline import Streamlines, values_from_volume
    from dipy.tracking._utils import _mapping_to_voxel, _to_voxel_coordinates
    import networkx as nx
    from itertools import combinations
    from collections import defaultdict
    from pynets.core import utils, nodemaker
    from pynets.dmri.dmri_utils import generate_sl
    from dipy.io.streamline import load_tractogram
    from dipy.io.stateful_tractogram import Space, Origin

    with open(pkg_resources.resource_filename("pynets", "runconfig.yaml"),
              "r") as stream:
        hardcoded_params = yaml.load(stream)
        fa_wei = hardcoded_params["StructuralNetworkWeighting"][
            "fa_weighting"][0]
        fiber_density = hardcoded_params["StructuralNetworkWeighting"][
            "fiber_density"][0]
        overlap_thr = hardcoded_params["StructuralNetworkWeighting"][
            "overlap_thr"][0]
        roi_neighborhood_tol = \
        hardcoded_params['tracking']["roi_neighborhood_tol"][0]
    stream.close()

    start = time.time()

    if float(roi_neighborhood_tol) <= float(error_margin):
        try:
            raise ValueError('roi_neighborhood_tol preset cannot be less than '
                             'the value of the structural connectome error'
                             '_margin parameter.')
        except ValueError:
            import sys
            sys.exit(1)
    else:
        print(f"Using fiber-roi intersection tolerance: {error_margin}...")

    # Load FA
    fa_img = nib.load(warped_fa)

    # Load parcellation
    roi_img = nib.load(atlas_mni)
    atlas_data = np.around(np.asarray(roi_img.dataobj))
    roi_zooms = roi_img.header.get_zooms()
    roi_shape = roi_img.shape

    # Read Streamlines
    streamlines = [
        i.astype(np.float32) for i in Streamlines(
            load_tractogram(
                streams, fa_img, to_origin=Origin.NIFTI,
                to_space=Space.VOXMM).streamlines)
    ]

    # from fury import actor, window
    # renderer = window.Renderer()
    # template_actor = actor.contour_from_roi(roi_img.get_fdata(),
    #                                         color=(50, 50, 50), opacity=0.05)
    # renderer.add(template_actor)
    # lines_actor = actor.streamtube(streamlines, window.colors.orange,
    #                                linewidth=0.3)
    # renderer.add(lines_actor)
    # window.show(renderer)

    roi_img.uncache()

    if fa_wei is True:
        fa_weights = values_from_volume(
            np.asarray(fa_img.dataobj, dtype=np.float32), streamlines,
            np.eye(4))
        global_fa_weights = list(utils.flatten(fa_weights))
        min_global_fa_wei = min([i for i in global_fa_weights if i > 0])
        max_global_fa_wei = max(global_fa_weights)
        fa_weights_norm = []
        # Here we normalize by global FA
        for val_list in fa_weights:
            fa_weights_norm.append(
                np.nanmean((val_list - min_global_fa_wei) /
                           (max_global_fa_wei - min_global_fa_wei)))

    # Make streamlines into generators to keep memory at a minimum
    total_streamlines = len(streamlines)
    sl = [generate_sl(i) for i in streamlines]
    del streamlines

    # Instantiate empty networkX graph object & dictionary and create
    # voxel-affine mapping
    lin_T, offset = _mapping_to_voxel(np.eye(4))
    mx = len(np.unique(atlas_data.astype("uint16"))) - 1
    g = nx.Graph(ecount=0, vcount=mx)
    edge_dict = defaultdict(int)
    node_dict = dict(
        zip(np.unique(atlas_data.astype("uint16"))[1:],
            np.arange(mx) + 1))

    # Add empty vertices with label volume attributes
    for node in range(1, mx + 1):
        g.add_node(node,
                   roi_volume=np.sum(atlas_data.astype("uint16") == node))

    # Build graph
    pc = 0
    bad_idxs = []
    fiberlengths = {}
    fa_weights_dict = {}
    print(f"Quantifying fiber-ROI intersection for {atlas}:")
    for ix, s in enumerate(sl):
        # Percent counter
        pcN = int(round(100 * float(ix / total_streamlines)))
        if pcN % 10 == 0 and ix > 0 and pcN > pc:
            pc = pcN
            print(f"{pcN}%")

        # Map the streamlines coordinates to voxel coordinates and get labels
        # for label_volume
        vox_coords = _to_voxel_coordinates(Streamlines(s), lin_T, offset)

        lab_coords = [
            nodemaker.get_sphere(coord, error_margin, roi_zooms, roi_shape)
            for coord in vox_coords
        ]
        [i, j, k] = np.vstack(np.array(lab_coords)).T

        # get labels for label_volume
        lab_arr = atlas_data[i, j, k]
        # print(lab_arr)
        endlabels = []
        for jx, lab in enumerate(np.unique(lab_arr).astype("uint32")):
            if (lab > 0) and (np.sum(lab_arr == lab) >= overlap_thr):
                try:
                    endlabels.append(node_dict[lab])
                except BaseException:
                    bad_idxs.append(jx)
                    print(f"Label {lab} missing from parcellation. Check "
                          f"registration and ensure valid input parcellation "
                          f"file.")

        edges = combinations(endlabels, 2)
        for edge in edges:
            # Get fiber lengths along edge
            if fiber_density is True:
                if not (edge[0], edge[1]) in fiberlengths.keys():
                    fiberlengths[(edge[0], edge[1])] = [len(vox_coords)]
                else:
                    fiberlengths[(edge[0], edge[1])].append(len(vox_coords))

            # Get FA values along edge
            if fa_wei is True:
                if not (edge[0], edge[1]) in fa_weights_dict.keys():
                    fa_weights_dict[(edge[0], edge[1])] = [fa_weights_norm[ix]]
                else:
                    fa_weights_dict[(edge[0],
                                     edge[1])].append(fa_weights_norm[ix])

            lst = tuple([int(node) for node in edge])
            edge_dict[tuple(sorted(lst))] += 1

        edge_list = [(k[0], k[1], count) for k, count in edge_dict.items()]

        g.add_weighted_edges_from(edge_list)

        del lab_coords, lab_arr, endlabels, edges, edge_list

    gc.collect()

    # Add fiber density attributes for each edge
    # Adapted from the nnormalized fiber-density estimation routines of
    # Sebastian Tourbier.
    if fiber_density is True:
        print("Weighting edges by fiber density...")
        # Summarize total fibers and total label volumes
        total_fibers = 0
        total_volume = 0
        u_start = -1
        for u, v, d in g.edges(data=True):
            total_fibers += len(d)
            if u != u_start:
                total_volume += g.nodes[int(u)]['roi_volume']
            u_start = u

        ix = 0
        for u, v, d in g.edges(data=True):
            if d['weight'] > 0:
                edge_fiberlength_mean = np.nanmean(fiberlengths[(u, v)])
                fiber_density = (float(
                    ((float(d['weight']) / float(total_fibers)) /
                     float(edge_fiberlength_mean)) *
                    ((2.0 * float(total_volume)) /
                     (g.nodes[int(u)]['roi_volume'] +
                      g.nodes[int(v)]['roi_volume'])))) * 1000
            else:
                fiber_density = 0
            g.edges[u, v].update({"fiber_density": fiber_density})
            ix += 1

    if fa_wei is True:
        print("Weighting edges by FA...")
        # Add FA attributes for each edge
        ix = 0
        for u, v, d in g.edges(data=True):
            if d['weight'] > 0:
                edge_average_fa = np.nanmean(fa_weights_dict[(u, v)])
            else:
                edge_average_fa = np.nan
            g.edges[u, v].update({"fa_weight": edge_average_fa})
            ix += 1

    # Summarize weights
    if fa_wei is True and fiber_density is True:
        for u, v, d in g.edges(data=True):
            g.edges[u, v].update(
                {"final_weight": (d['fa_weight']) * d['fiber_density']})
    elif fiber_density is True and fa_wei is False:
        for u, v, d in g.edges(data=True):
            g.edges[u, v].update({"final_weight": d['fiber_density']})
    elif fa_wei is True and fiber_density is False:
        for u, v, d in g.edges(data=True):
            g.edges[u,
                    v].update({"final_weight": d['fa_weight'] * d['weight']})
    else:
        for u, v, d in g.edges(data=True):
            g.edges[u, v].update({"final_weight": d['weight']})

    # Convert weighted graph to numpy matrix
    conn_matrix_raw = nx.to_numpy_array(g, weight='final_weight')

    # Enforce symmetry
    conn_matrix = np.maximum(conn_matrix_raw, conn_matrix_raw.T)

    print("Structural graph completed:\n", str(time.time() - start))

    if len(bad_idxs) > 0:
        bad_idxs = sorted(list(set(bad_idxs)), reverse=True)
        for j in bad_idxs:
            del labels[j], coords[j]

    coords = np.array(coords)
    labels = np.array(labels)

    assert len(coords) == len(labels) == conn_matrix.shape[0]

    return (atlas_mni, streams, conn_matrix, track_type, target_samples,
            dir_path, conn_model, network, node_size, dens_thresh, ID, roi,
            min_span_tree, disp_filt, parc, prune, atlas, uatlas, labels,
            coords, norm, binary, directget, min_length, error_margin)
Exemplo n.º 37
0
def connectivity_matrix(streamlines,
                        affine,
                        label_volume,
                        inclusive=False,
                        symmetric=True,
                        return_mapping=False,
                        mapping_as_streamlines=False):
    """Counts the streamlines that start and end at each label pair.

    Parameters
    ----------
    streamlines : sequence
        A sequence of streamlines.
    affine : array_like (4, 4)
        The mapping from voxel coordinates to streamline coordinates.
        The voxel_to_rasmm matrix, typically from a NIFTI file.
    label_volume : ndarray
        An image volume with an integer data type, where the intensities in the
        volume map to anatomical structures.
    inclusive: bool
        Whether to analyze the entire streamline, as opposed to just the
        endpoints. Allowing this will increase calculation time and mapping
        size, especially if mapping_as_streamlines is True. False by default.
    symmetric : bool, True by default
        Symmetric means we don't distinguish between start and end points. If
        symmetric is True, ``matrix[i, j] == matrix[j, i]``.
    return_mapping : bool, False by default
        If True, a mapping is returned which maps matrix indices to
        streamlines.
    mapping_as_streamlines : bool, False by default
        If True voxel indices map to lists of streamline objects. Otherwise
        voxel indices map to lists of integers.

    Returns
    -------
    matrix : ndarray
        The number of connection between each pair of regions in
        `label_volume`.
    mapping : defaultdict(list)
        ``mapping[i, j]`` returns all the streamlines that connect region `i`
        to region `j`. If `symmetric` is True mapping will only have one key
        for each start end pair such that if ``i < j`` mapping will have key
        ``(i, j)`` but not key ``(j, i)``.

    """
    # Error checking on label_volume
    kind = label_volume.dtype.kind
    labels_positive = ((kind == 'u')
                       or ((kind == 'i') and (label_volume.min() >= 0)))
    valid_label_volume = (labels_positive and label_volume.ndim == 3)
    if not valid_label_volume:
        raise ValueError("label_volume must be a 3d integer array with"
                         "non-negative label values")

    # If streamlines is an iterator
    if return_mapping and mapping_as_streamlines:
        streamlines = list(streamlines)

    if inclusive:
        # Create ndarray to store streamline connections
        edges = np.ndarray(shape=(3, 0), dtype=int)
        lin_T, offset = _mapping_to_voxel(affine)
        for sl, _ in enumerate(streamlines):
            # Convert streamline to voxel coordinates
            entire = _to_voxel_coordinates(streamlines[sl], lin_T, offset)
            i, j, k = entire.T

            if symmetric:
                # Create list of all labels streamline passes through
                entirelabels = list(OrderedDict.fromkeys(label_volume[i, j,
                                                                      k]))
                # Append all connection combinations with streamline number
                for comb in combinations(entirelabels, 2):
                    edges = np.append(edges, [[comb[0]], [comb[1]], [sl]],
                                      axis=1)
            else:
                # Create list of all labels streamline passes through, keeping
                # order and whether a label was entered multiple times
                entirelabels = list(groupby(label_volume[i, j, k]))
                # Append connection combinations along with streamline number,
                # removing duplicates and connections from a label to itself
                combs = set(combinations([z[0] for z in entirelabels], 2))
                for comb in combs:
                    if comb[0] == comb[1]:
                        pass
                    else:
                        edges = np.append(edges, [[comb[0]], [comb[1]], [sl]],
                                          axis=1)
        if symmetric:
            edges[0:2].sort(0)
        mx = label_volume.max() + 1
        matrix = ndbincount(edges[0:2], shape=(mx, mx))

        if symmetric:
            matrix = np.maximum(matrix, matrix.T)
        if return_mapping:
            mapping = defaultdict(list)
            for i, (a, b, c) in enumerate(edges.T):
                mapping[a, b].append(c)
            # Replace each list of indices with the streamlines they index
            if mapping_as_streamlines:
                for key in mapping:
                    mapping[key] = [streamlines[i] for i in mapping[key]]

            return matrix, mapping

        return matrix
    else:
        # take the first and last point of each streamline
        endpoints = [sl[0::len(sl) - 1] for sl in streamlines]

        # Map the streamlines coordinates to voxel coordinates
        lin_T, offset = _mapping_to_voxel(affine)
        endpoints = _to_voxel_coordinates(endpoints, lin_T, offset)

        # get labels for label_volume
        i, j, k = endpoints.T
        endlabels = label_volume[i, j, k]
        if symmetric:
            endlabels.sort(0)
        mx = label_volume.max() + 1
        matrix = ndbincount(endlabels, shape=(mx, mx))
        if symmetric:
            matrix = np.maximum(matrix, matrix.T)

        if return_mapping:
            mapping = defaultdict(list)
            for i, (a, b) in enumerate(endlabels.T):
                mapping[a, b].append(i)

            # Replace each list of indices with the streamlines they index
            if mapping_as_streamlines:
                for key in mapping:
                    mapping[key] = [streamlines[i] for i in mapping[key]]

            # Return the mapping matrix and the mapping
            return matrix, mapping

        return matrix