Ejemplo n.º 1
0
    def segment_reco(self, tg=None):
        """
        Segment streamlines using the RecoBundles algorithm [Garyfallidis2017]
        Parameters
        ----------
        tg : StatefulTractogram class instance
            A whole-brain tractogram to be segmented.
        Returns
        -------
        fiber_groups : dict
            Keys are names of the bundles, values are Streamline objects.
            The streamlines in each object have all been oriented to have the
            same orientation (using `dts.orient_by_streamline`).
        """
        tg = self._read_tg(tg=tg)
        fiber_groups = {}

        self.move_streamlines(tg, self.reg_algo)
        # We generate our instance of RB with the moved streamlines:
        self.logger.info("Extracting Bundles")
        rb = RecoBundles(self.moved_sl, verbose=False, rng=self.rng)
        # Next we'll iterate over bundles, registering each one:
        bundle_list = list(self.bundle_dict.keys())
        bundle_list.remove('whole_brain')

        self.logger.info("Assigning Streamlines to Bundles")
        for bundle in bundle_list:
            model_sl = self.bundle_dict[bundle]['sl']
            _, rec_labels = rb.recognize(model_bundle=model_sl,
                                         model_clust_thr=self.model_clust_thr,
                                         reduction_thr=self.reduction_thr,
                                         reduction_distance='mdf',
                                         slr=True,
                                         slr_metric='asymmetric',
                                         pruning_distance='mdf')

            # Use the streamlines in the original space:
            recognized_sl = tg.streamlines[rec_labels]
            if self.refine and len(recognized_sl) > 0:
                _, rec_labels = rb.refine(model_sl,
                                          recognized_sl,
                                          self.model_clust_thr,
                                          reduction_thr=self.reduction_thr,
                                          pruning_thr=self.pruning_thr)
                recognized_sl = tg.streamlines[rec_labels]

            standard_sl = self.bundle_dict[bundle]['centroid']
            oriented_sl = dts.orient_by_streamline(recognized_sl, standard_sl)
            if self.return_idx:
                fiber_groups[bundle] = {}
                fiber_groups[bundle]['idx'] = rec_labels
                fiber_groups[bundle]['sl'] = StatefulTractogram(
                    oriented_sl, self.img, Space.RASMM)
            else:
                fiber_groups[bundle] = StatefulTractogram(
                    oriented_sl, self.img, Space.RASMM)
        self.fiber_groups = fiber_groups
        return fiber_groups
Ejemplo n.º 2
0
def recobundles(streamlines, bundle_dict):
    """
    Segment streamlines using the RecoBundles algorithm [Garyfallidis2017]

    Parameters
    ----------
    streamlines : list or Streamlines object.
        A whole-brain tractogram to be segmented.
    bundle_dict: dictionary
        Of the form:

            {'whole_brain': Streamlines,
            'CST_L': {'sl': Streamlines, 'centroid': array},
            'CST_R': {'sl': Streamlines, 'centroid': array},
            ...}

    Returns
    -------
    fiber_groups : dict
        Keys are names of the bundles, values are Streamline objects.
        The streamlines in each object have all been oriented to have the
        same orientation (using `dts.orient_by_streamline`).
    """
    fiber_groups = {}
    # We start with whole-brain SLR:
    atlas = bundle_dict['whole_brain']
    moved, transform, qb_centroids1, qb_centroids2 = whole_brain_slr(
        atlas, streamlines, x0='affine', verbose=False, progressive=True)

    # We generate our instance of RB with the moved streamlines:
    rb = RecoBundles(moved, verbose=False)

    # Next we'll iterate over bundles, registering each one:
    bundle_list = list(bundle_dict.keys())
    bundle_list.remove('whole_brain')

    for bundle in bundle_list:
        model_sl = bundle_dict[bundle]['sl']
        _, rec_labels = rb.recognize(model_bundle=model_sl,
                                     model_clust_thr=5.,
                                     reduction_thr=10,
                                     reduction_distance='mam',
                                     slr=True,
                                     slr_metric='asymmetric',
                                     pruning_distance='mam')

        # Use the streamlines in the original space:
        recognized_sl = streamlines[rec_labels]
        standard_sl = bundle_dict[bundle]['centroid']
        oriented_sl = dts.orient_by_streamline(recognized_sl, standard_sl)
        fiber_groups[bundle] = oriented_sl
    return fiber_groups
def get_tract_profile(bundle,
                      metric_img,
                      metric_affine,
                      use_weights=False,
                      flip=True,
                      num_points=100):
    '''
    This function reorients the streamlines and extracts the diffusion metrics 
    along the tract. It essentiall performs step 1. The default number of points
    along a tract is 100, which can be thought of as %-along a tract.

    The flip variable signals if you would like to flip the direction of the
    streamlines after reorientation. For example if after reorientation all the
    streamlines were motor cortex -> brainstem and you actually wanted 
    brainstem -> motor cortex, then you set flip to True. The default is True
    because generally we see reorientation result in motor cortex -> brainstem.
    For the honours project, we were looking for the opposite
    '''

    # Reorient all the streamlines so that they are follwing the same direction
    feature = ResampleFeature(nb_points=num_points)
    d_metric = AveragePointwiseEuclideanMetric(feature)
    qb = QuickBundles(np.inf, metric=d_metric)
    centroid_bundle = qb.cluster(bundle).centroids[0]
    oriented_bundle = orient_by_streamline(bundle, centroid_bundle)

    # Calculate weights for each streamline/node in a bundle, based on a
    # Mahalanobis distance from the core the bundle, at that node
    w_bundle = None
    if use_weights:
        w_bundle = gaussian_weights(oriented_bundle)

    # Sample the metric along the tract. The implementation of this function
    # is based off of work by Yeatman et al. in 2012
    profile_bundle = afq_profile(metric_img,
                                 oriented_bundle,
                                 metric_affine,
                                 weights=w_bundle)

    # Reverse the profile bundle if the direction is not desired
    if flip:
        profile_bundle = np.flip(profile_bundle)

    return profile_bundle
def extract_subtract_from_tractome(selection,classification,tractome):
    namesList,index=parse_mat_classification(classification)
    if isinstance(selection, str):
        #be sure to account for 0 indexing
        nameIndex=namesList.index(selection)+1
        indexBool=index==nameIndex
        streamIndexes=[i for i, x in enumerate(indexBool) if x]
        
    elif isinstance(selection, int):
        indexBool=index==selection
        streamIndexes=[i for i, x in enumerate(indexBool) if x]
        
    streamsObjIN=nib.streamlines.load(tractome)
    #this doesn't work
    reorientedStreams=dts.orient_by_streamline(streamsObjIN.tractogram.streamlines[streamIndexes],streamsObjIN.tractogram.streamlines[streamIndexes[0]])
    sub_tractogram=nib.streamlines.Tractogram(reorientedStreams)
    #is it getting the appropriate header info?
    #sub_tractogram_reoriented=dipy.tracking.streamline.orient_by_streamline(sub_tractogram,sub_tractogram.tractogram.streamlines[0])
    modded_tractogram=nib.streamlines.tck.TckFile(sub_tractogram, nib.streamlines.header)
    
    return modded_tractogram
Ejemplo n.º 5
0
def afq_profile(data, bundle, affine=None, n_points=100,
                orient_by=None, weights=None, **weights_kwarg):
    """
    Calculates a summarized profile of data for a bundle or tract
    along its length.

    Follows the approach outlined in [Yeatman2012]_.

    Parameters
    ----------
    data : 3D volume
        The statistic to sample with the streamlines.

    bundle : StreamLines class instance
        The collection of streamlines (possibly already resampled into an array
         for each to have the same length) with which we are resampling. See
         Note below about orienting the streamlines.

    affine: 4-by-4 array, optional.
        A transformation associated with the streamlines in the bundle.
        Default: identity.

    n_points: int, optional
        The number of points to sample along the bundle. Default: 100.

    orient_by: streamline, optional.
        A streamline to use as a standard to orient all of the streamlines in
        the bundle according to.

    weights : 1D array or 2D array or callable (optional)
        Weight each streamline (1D) or each node (2D) when calculating the
        tract-profiles. Must sum to 1 across streamlines (in each node if
        relevant). If callable, this is a function that calculates weights.

    weights_kwarg : key-word arguments
        Additional key-word arguments to pass to the weight-calculating
        function. Only to be used if weights is a callable.

    Returns
    -------
    ndarray : a 1D array with the profile of `data` along the length of
        `bundle`

    Note
    ----
    Before providing a bundle as input to this function, you will need to make
    sure that the streamlines in the bundle are all oriented in the same
    orientation relative to the bundle (use :func:`orient_by_streamline`).

    References
    ----------
    .. [Yeatman2012] Yeatman, Jason D., Robert F. Dougherty,
       Nathaniel J. Myall, Brian A. Wandell, and Heidi M. Feldman. 2012.
       "Tract Profiles of White Matter Properties: Automating Fiber-Tract
       Quantification" PloS One 7 (11): e49790.
    """
    if orient_by is not None:
        bundle = orient_by_streamline(bundle, orient_by, affine=affine)
    if len(bundle) == 0:
        raise ValueError("The bundle contains no streamlines")

    # Resample each streamline to the same number of points:
    fgarray = set_number_of_points(bundle, n_points)

    # Extract the values
    values = np.array(values_from_volume(data, fgarray, affine=affine))

    if weights is None:
        weights = np.ones(values.shape) / values.shape[0]
    elif callable(weights):
        weights = weights(bundle, **weights_kwarg)
    else:
        # We check that weights *always sum to 1 across streamlines*:
        if not np.allclose(np.sum(weights, 0), np.ones(n_points)):
            raise ValueError("The sum of weights across streamlines must ",
                             "be equal to 1")

    return np.sum(weights * values, 0)
Ejemplo n.º 6
0
def afq_profile(data,
                bundle,
                affine=None,
                n_points=100,
                orient_by=None,
                weights=None,
                **weights_kwarg):
    """
    Calculates a summarized profile of data for a bundle or tract
    along its length.

    Follows the approach outlined in [Yeatman2012]_.

    Parameters
    ----------
    data : 3D volume
        The statistic to sample with the streamlines.

    bundle : StreamLines class instance
        The collection of streamlines (possibly already resampled into an array
         for each to have the same length) with which we are resampling. See
         Note below about orienting the streamlines.

    affine: 4-by-4 array, optional.
        A transformation associated with the streamlines in the bundle.
        Default: identity.

    n_points: int, optional
        The number of points to sample along the bundle. Default: 100.

    orient_by: streamline, optional.
        A streamline to use as a standard to orient all of the streamlines in
        the bundle according to.

    weights : 1D array or 2D array or callable (optional)
        Weight each streamline (1D) or each node (2D) when calculating the
        tract-profiles. Must sum to 1 across streamlines (in each node if
        relevant). If callable, this is a function that calculates weights.

    weights_kwarg : key-word arguments
        Additional key-word arguments to pass to the weight-calculating
        function. Only to be used if weights is a callable.

    Returns
    -------
    ndarray : a 1D array with the profile of `data` along the length of
        `bundle`

    Note
    ----
    Before providing a bundle as input to this function, you will need to make
    sure that the streamlines in the bundle are all oriented in the same
    orientation relative to the bundle (use :func:`orient_by_streamline`).

    References
    ----------
    .. [Yeatman2012] Yeatman, Jason D., Robert F. Dougherty,
       Nathaniel J. Myall, Brian A. Wandell, and Heidi M. Feldman. 2012.
       "Tract Profiles of White Matter Properties: Automating Fiber-Tract
       Quantification" PloS One 7 (11): e49790.
    """
    if orient_by is not None:
        bundle = orient_by_streamline(bundle, orient_by, affine=affine)
    if len(bundle) == 0:
        raise ValueError("The bundle contains no streamlines")

    # Resample each streamline to the same number of points:
    fgarray = set_number_of_points(bundle, n_points)

    # Extract the values
    values = np.array(values_from_volume(data, fgarray, affine=affine))

    if weights is None:
        weights = np.ones(values.shape) / values.shape[0]
    elif callable(weights):
        weights = weights(bundle, **weights_kwarg)
    else:
        # We check that weights *always sum to 1 across streamlines*:
        if not np.allclose(np.sum(weights, 0), np.ones(n_points)):
            raise ValueError("The sum of weights across streamlines must ",
                             "be equal to 1")

    return np.sum(weights * values, 0)
Ejemplo n.º 7
0
standard_cst_l = cluster_cst_l.centroids[0]

cluster_af_l = qb.cluster(model_af_l)
standard_af_l = cluster_af_l.centroids[0]

"""
We use the centroid streamline for each atlas bundle as the standard to orient
all of the streamlines in each bundle from the individual subject. Here, the
affine used is the one from the transform between the atlas and individual
tractogram. This is so that the orienting is done relative to the space of the
individual, and not relative to the atlas space.
"""

import dipy.tracking.streamline as dts

oriented_cst_l = dts.orient_by_streamline(cst_l, standard_cst_l,
                                          affine=transform)
oriented_af_l = dts.orient_by_streamline(af_l, standard_af_l,
                                         affine=transform)


"""
Read volumetric data from an image corresponding to this subject.

For the purpose of this, we've extracted only the FA within the bundles in question,
but in real use, this is where you would add the FA map of your subject.
"""

files, folder = dpd.fetch_bundle_fa_hcp()

import nibabel as nib
img = nib.load(op.join(folder, "hcp_bundle_fa.nii.gz"))
Ejemplo n.º 8
0
    if code not in bundles_to_show:
        continue

    if code not in bundles:
        bundles[code] = []
    bundle = bundles[code]

    #limit the number of streamlines per bundle
    if len(bundle) < 2000:
        bundle.append(trk.streamlines[idx])

#reorient streamlines
from dipy.tracking.streamline import orient_by_streamline
for code in bundles:
    print("reorienting", code)
    orient_by_streamline(bundles[code], bundles[code][0], in_place=True)

#TODO merge streamlines that are near each other and update its thickness?
#for code in bundles:
#    streamlines = bundles[code]
#    print(streamlines[0])
#    sys.exit(1)


#TODO - should I move this to empty.blend?
def vecCircle(name):
    bpy.ops.mesh.primitive_circle_add(vertices=3, radius=0.010)
    obj = bpy.context.active_object
    obj.name = name
    bpy.ops.object.convert(target='CURVE', keep_original=False)
    return obj
Ejemplo n.º 9
0
qb = QuickBundles(np.inf, metric=metric)

cluster_cst_l = qb.cluster(model_cst_l)
standard_cst_l = cluster_cst_l.centroids[0]

cluster_af_l = qb.cluster(model_af_l)
standard_af_l = cluster_af_l.centroids[0]
"""
We use the centroid streamline for each atlas bundle as the standard to orient
all of the streamlines in each bundle from the individual subject. Here, the
affine used is the one from the transform between the atlas and individual
tractogram. This is so that the orienting is done relative to the space of the
individual, and not relative to the atlas space.
"""

oriented_cst_l = dts.orient_by_streamline(cst_l, standard_cst_l)
oriented_af_l = dts.orient_by_streamline(af_l, standard_af_l)
"""
Read volumetric data from an image corresponding to this subject.

For the purpose of this, we've extracted only the FA within the bundles in
question, but in real use, this is where you would add the FA map of your
subject.
"""

files, folder = dpd.fetch_bundle_fa_hcp()

fa, fa_affine = load_nifti(op.join(folder, "hcp_bundle_fa.nii.gz"))
"""
Calculate weights for each bundle:
"""
Ejemplo n.º 10
0
standard_cst_l = cluster_cst_l.centroids[0]

cluster_af_l = qb.cluster(model_af_l)
standard_af_l = cluster_af_l.centroids[0]

"""
We use the centroid streamline for each atlas bundle as the standard to orient
all of the streamlines in each bundle from the individual subject. Here, the
affine used is the one from the transform between the atlas and individual
tractogram. This is so that the orienting is done relative to the space of the
individual, and not relative to the atlas space.
"""

import dipy.tracking.streamline as dts

oriented_cst_l = dts.orient_by_streamline(cst_l, standard_cst_l,
                                          affine=transform)
oriented_af_l = dts.orient_by_streamline(af_l, standard_af_l,
                                         affine=transform)


"""
Read volumetric data from an image corresponding to this subject.

For the purpose of this, we've extracted only the FA within the bundles in question,
but in real use, this is where you would add the FA map of your subject.
"""

files, folder = dpd.fetch_bundle_fa_hcp()

import nibabel as nib
img = nib.load(op.join(folder, "hcp_bundle_fa.nii.gz"))