Beispiel #1
0
def assignment_map(target_bundle, model_bundle, no_disks):
    """
    Calculates assignment maps of the target bundle with reference to
    model bundle centroids.

    Parameters
    ----------
    target_bundle : streamlines
        target bundle extracted from subject data in common space
    model_bundle : streamlines
        atlas bundle used as reference
    no_disks : integer, optional
        Number of disks used for dividing bundle into disks. (Default 100)

    References
    ----------
    .. [Chandio19] Chandio, B.Q., S. Koudoro, D. Reagan, J. Harezlak,
    E. Garyfallidis, Bundle Analytics: a computational and statistical
    analyses framework for tractometric studies, Proceedings of:
    International Society of Magnetic Resonance in Medicine (ISMRM),
    Montreal, Canada, 2019.
    """

    mbundle_streamlines = set_number_of_points(model_bundle,
                                               nb_points=no_disks)

    metric = AveragePointwiseEuclideanMetric()
    qb = QuickBundles(threshold=85., metric=metric)
    clusters = qb.cluster(mbundle_streamlines)
    centroids = Streamlines(clusters.centroids)

    _, indx = cKDTree(centroids.data, 1,
                      copy_data=True).query(target_bundle.data, k=1)

    return indx
def test_quickbundles_with_python_metric():

    class MDFpy(dipymetric.Metric):
        def are_compatible(self, shape1, shape2):
            return shape1 == shape2

        def dist(self, features1, features2):
            dist = np.sqrt(np.sum((features1 - features2)**2, axis=1))
            dist = np.sum(dist / len(features1))
            return dist

    rdata = streamline_utils.set_number_of_points(data, 10)
    qb = QuickBundles(threshold=2 * threshold, metric=MDFpy())

    clusters = qb.cluster(rdata)

    # By default `refdata` refers to data being clustered.
    assert_equal(clusters.refdata, rdata)
    # Set `refdata` to return indices instead of actual data points.
    clusters.refdata = None
    assert_array_equal(list(itertools.chain(*clusters)),
                       list(itertools.chain(*clusters_truth)))

    # Cluster read-only data
    for datum in rdata:
        datum.setflags(write=False)

    # Cluster data with different dtype (should be converted into float32)
    for datatype in [np.float64, np.int32, np.int64]:
        newdata = [datum.astype(datatype) for datum in rdata]
        clusters = qb.cluster(newdata)
        assert_equal(clusters.centroids[0].dtype, np.float32)
Beispiel #3
0
def find_centroids(streamlines,th,max_clus, folder_name='', vol_weighted = True, weight_by = '1.5_2_AxPasi5'):
    from dipy.segment.clustering import QuickBundles
    ''' parameters:
        streamlines: ArraySequence of streamlines
        th: float for max dist from a streamline to the centroids.
            Above this value a new centroid is created as long as the number of centroids < max clus.
        max_clus: int of max number of clusters

        :return:
        centroids: a list of streamilnes centroid representation
        s_list: a list of lists. 
            Each inner list is the group of streamlines cooresponds to a single centroid.
    '''
    qb = QuickBundles(th,max_nb_clusters=max_clus)
    qbmap = qb.cluster(streamlines)
    centroids = qbmap.centroids
    s_list = []
    for i in qbmap.clusters:
        s_list.append(list(i))

    if vol_weighted:
        bvec_file = load_dwi_files(folder_name)[6]
        vec_vols = weight_clus_by_vol_img(weight_by,s_list, folder_name, bvec_file)
        return centroids, s_list, vec_vols

    else:
        return centroids, s_list
Beispiel #4
0
def read_hcp_atlas_16_bundles():
    """
    XXX
    """
    bundle_dict = {}
    _, folder = fetch_hcp_atlas_16_bundles()
    whole_brain = load_tractogram(op.join(folder,
                                          'Atlas_in_MNI_Space_16_bundles',
                                          'whole_brain',
                                          'whole_brain_MNI.trk'),
                                  'same',
                                  bbox_valid_check=False).streamlines
    bundle_dict['whole_brain'] = whole_brain
    bundle_files = glob(
        op.join(folder, "Atlas_in_MNI_Space_16_bundles", "bundles", "*.trk"))
    for bundle_file in bundle_files:
        bundle = op.splitext(op.split(bundle_file)[-1])[0]
        bundle_dict[bundle] = {}
        bundle_dict[bundle]['sl'] = load_tractogram(bundle_file,
                                                    'same',
                                                    bbox_valid_check=False)\
            .streamlines

        feature = ResampleFeature(nb_points=100)
        metric = AveragePointwiseEuclideanMetric(feature)
        qb = QuickBundles(np.inf, metric=metric)
        cluster = qb.cluster(bundle_dict[bundle]['sl'])
        bundle_dict[bundle]['centroid'] = cluster.centroids[0]

    # For some reason, this file-name has a 0 in it, instead of an O:
    bundle_dict["IFOF_R"] = bundle_dict["IF0F_R"]
    del bundle_dict["IF0F_R"]
    return bundle_dict
Beispiel #5
0
def test_quickbundles_with_python_metric():
    class MDFpy(dipymetric.Metric):
        def are_compatible(self, shape1, shape2):
            return shape1 == shape2

        def dist(self, features1, features2):
            dist = np.sqrt(np.sum((features1 - features2)**2, axis=1))
            dist = np.sum(dist / len(features1))
            return dist

    rdata = streamline_utils.set_number_of_points(data, 10)
    qb = QuickBundles(threshold=2 * threshold, metric=MDFpy())

    clusters = qb.cluster(rdata)

    # By default `refdata` refers to data being clustered.
    assert_equal(clusters.refdata, rdata)
    # Set `refdata` to return indices instead of actual data points.
    clusters.refdata = None
    assert_array_equal(list(itertools.chain(*clusters)),
                       list(itertools.chain(*clusters_truth)))

    # Cluster read-only data
    for datum in rdata:
        datum.setflags(write=False)

    # Cluster data with different dtype (should be converted into float32)
    for datatype in [np.float64, np.int32, np.int64]:
        newdata = [datum.astype(datatype) for datum in rdata]
        clusters = qb.cluster(newdata)
        assert_equal(clusters.centroids[0].dtype, np.float32)
Beispiel #6
0
def produce_Clusters(truth_list, thresh):
    
    feature = ResampleFeature(nb_points=24)
    metric = AveragePointwiseEuclideanMetric(feature=feature) 
    qb = QuickBundles(threshold = thresh, metric = metric)
    clusters = qb.cluster(truth_list)
    
    return qb, clusters
Beispiel #7
0
def get_centroid_streamline(streamlines, nb_points):
    resample_feature = ResampleFeature(nb_points=nb_points)
    quick_bundle = QuickBundles(
        threshold=np.inf,
        metric=AveragePointwiseEuclideanMetric(resample_feature))
    clusters = quick_bundle.cluster(streamlines)
    centroid_streamlines = clusters.centroids

    return centroid_streamlines
def test_quickbundles_memory_leaks():
    qb = QuickBundles(threshold=2*threshold)

    type_name_pattern = "memoryview"
    initial_types_refcount = get_type_refcount(type_name_pattern)

    qb.cluster(data)
    # At this point, all memoryviews created during clustering should be freed.
    assert_equal(get_type_refcount(type_name_pattern), initial_types_refcount)
Beispiel #9
0
def test_quickbundles_memory_leaks():
    qb = QuickBundles(threshold=2 * threshold)

    type_name_pattern = "memoryview"
    initial_types_refcount = get_type_refcount(type_name_pattern)

    qb.cluster(data)
    # At this point, all memoryviews created during clustering should be freed.
    assert_equal(get_type_refcount(type_name_pattern), initial_types_refcount)
def main():
    parser = buildArgsParser()
    args = parser.parse_args()

    full_tfile = nib.streamlines.load(args.full_tfile)
    model_tfile = nib.streamlines.load(args.model_tfile)
    model_mask = nib.load(args.model_mask)

    # Bring streamlines to voxel space and where coordinate (0,0,0) represents the corner of a voxel.
    model_tfile.tractogram.apply_affine(np.linalg.inv(model_mask.affine))
    model_tfile.streamlines._data += 0.5  # Shift of half a voxel
    full_tfile.tractogram.apply_affine(np.linalg.inv(model_mask.affine))
    full_tfile.streamlines._data += 0.5  # Shift of half a voxel

    assert(model_mask.get_data().sum() == create_binary_map(model_tfile.streamlines, model_mask).sum())

    # Resample streamlines
    full_streamlines = set_number_of_points(full_tfile.streamlines, args.nb_points_resampling)
    model_streamlines = set_number_of_points(model_tfile.streamlines, args.nb_points_resampling)

    # Segment model
    rng = np.random.RandomState(42)
    indices = np.arange(len(model_streamlines))
    rng.shuffle(indices)
    qb = QuickBundles(args.qb_threshold)
    clusters = qb.cluster(model_streamlines, ordering=indices)

    # Try to find optimal assignment threshold
    best_threshold = None
    best_f1_score = -np.inf
    thresholds = np.arange(-2, 10, 0.2) + args.qb_threshold
    for threshold in thresholds:
        indices = qb.find_closest(clusters, full_streamlines, threshold=threshold)
        nb_assignments = np.sum(indices != -1)

        mask = create_binary_map(full_tfile.streamlines[indices != -1], model_mask)

        overlap_per_bundle = _compute_overlap(model_mask.get_data(), mask)
        overreach_per_bundle = _compute_overreach(model_mask.get_data(), mask)
        # overreach_norm_gt_per_bundle = _compute_overreach_normalize_gt(model_mask.get_data(), mask)
        f1_score = _compute_f1_score(overlap_per_bundle, overreach_per_bundle)
        if best_f1_score < f1_score:
            best_threshold = threshold
            best_f1_score = f1_score

        print("{}:\t {}/{} ({:.1%}) {:.1%}/{:.1%} ({:.1%}) {}/{}".format(
            threshold,
            nb_assignments, len(model_streamlines), nb_assignments/len(model_streamlines),
            overlap_per_bundle, overreach_per_bundle, f1_score,
            mask.sum(), model_mask.get_data().sum()))

        if overlap_per_bundle >= 1:
            break


    print("Best threshold: {} with F1-Score of {}".format(best_threshold, best_f1_score))
Beispiel #11
0
def bench_quickbundles():
    dtype = "float32"
    repeat = 10
    nb_points = 18

    streams, hdr = nib.trackvis.read(get_data('fornix'))
    fornix = [s[0].astype(dtype) for s in streams]
    fornix = streamline_utils.set_number_of_points(fornix, nb_points)

    # Create eight copies of the fornix to be clustered (one in each octant).
    streamlines = []
    streamlines += [s + np.array([100, 100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([100, -100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([100, 100, -100], dtype) for s in fornix]
    streamlines += [s + np.array([100, -100, -100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, 100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, -100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, 100, -100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, -100, -100], dtype) for s in fornix]

    # The expected number of clusters of the fornix using threshold=10 is 4.
    threshold = 10.
    expected_nb_clusters = 4 * 8

    print("Timing QuickBundles 1.0 vs. 2.0")

    qb = QB_Old(streamlines, threshold, pts=None)
    qb1_time = measure("QB_Old(streamlines, threshold, nb_points)", repeat)
    print("QuickBundles time: {0:.4}sec".format(qb1_time))
    assert_equal(qb.total_clusters, expected_nb_clusters)
    sizes1 = [qb.partitions()[i]['N'] for i in range(qb.total_clusters)]
    indices1 = [
        qb.partitions()[i]['indices'] for i in range(qb.total_clusters)
    ]

    qb2 = QB_New(threshold)
    qb2_time = measure("clusters = qb2.cluster(streamlines)", repeat)
    print("QuickBundles2 time: {0:.4}sec".format(qb2_time))
    print("Speed up of {0}x".format(qb1_time / qb2_time))
    clusters = qb2.cluster(streamlines)
    sizes2 = map(len, clusters)
    indices2 = map(lambda c: c.indices, clusters)
    assert_equal(len(clusters), expected_nb_clusters)
    assert_array_equal(sizes2, sizes1)
    assert_arrays_equal(indices2, indices1)

    qb = QB_New(threshold, metric=MDFpy())
    qb3_time = measure("clusters = qb.cluster(streamlines)", repeat)
    print("QuickBundles2_python time: {0:.4}sec".format(qb3_time))
    print("Speed up of {0}x".format(qb1_time / qb3_time))
    clusters = qb.cluster(streamlines)
    sizes3 = map(len, clusters)
    indices3 = map(lambda c: c.indices, clusters)
    assert_equal(len(clusters), expected_nb_clusters)
    assert_array_equal(sizes3, sizes1)
    assert_arrays_equal(indices3, indices1)
def test_quickbundles_with_not_order_invariant_metric():
    metric = dipymetric.AveragePointwiseEuclideanMetric()
    qb = QuickBundles(threshold=np.inf, metric=metric)

    streamline = np.arange(10*3, dtype=dtype).reshape((-1, 3))
    streamlines = [streamline, streamline[::-1]]

    clusters = qb.cluster(streamlines)
    assert_equal(len(clusters), 1)
    assert_array_equal(clusters[0].centroid, streamline)
Beispiel #13
0
def test_quickbundles_with_not_order_invariant_metric():
    metric = dipymetric.AveragePointwiseEuclideanMetric()
    qb = QuickBundles(threshold=np.inf, metric=metric)

    streamline = np.arange(10 * 3, dtype=dtype).reshape((-1, 3))
    streamlines = [streamline, streamline[::-1]]

    clusters = qb.cluster(streamlines)
    assert_equal(len(clusters), 1)
    assert_array_equal(clusters[0].centroid, streamline)
def bench_quickbundles():
    dtype = "float32"
    repeat = 10
    nb_points = 12

    streams, hdr = nib.trackvis.read(get_fnames('fornix'))
    fornix = [s[0].astype(dtype) for s in streams]
    fornix = streamline_utils.set_number_of_points(fornix, nb_points)

    # Create eight copies of the fornix to be clustered (one in each octant).
    streamlines = []
    streamlines += [s + np.array([100, 100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([100, -100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([100, 100, -100], dtype) for s in fornix]
    streamlines += [s + np.array([100, -100, -100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, 100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, -100, 100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, 100, -100], dtype) for s in fornix]
    streamlines += [s + np.array([-100, -100, -100], dtype) for s in fornix]

    # The expected number of clusters of the fornix using threshold=10 is 4.
    threshold = 10.
    expected_nb_clusters = 4 * 8

    print("Timing QuickBundles 1.0 vs. 2.0")

    qb = QB_Old(streamlines, threshold, pts=None)
    qb1_time = measure("QB_Old(streamlines, threshold, nb_points)", repeat)
    print("QuickBundles time: {0:.4}sec".format(qb1_time))
    assert_equal(qb.total_clusters, expected_nb_clusters)
    sizes1 = [qb.partitions()[i]['N'] for i in range(qb.total_clusters)]
    indices1 = [qb.partitions()[i]['indices']
                for i in range(qb.total_clusters)]

    qb2 = QB_New(threshold)
    qb2_time = measure("clusters = qb2.cluster(streamlines)", repeat)
    print("QuickBundles2 time: {0:.4}sec".format(qb2_time))
    print("Speed up of {0}x".format(qb1_time / qb2_time))
    clusters = qb2.cluster(streamlines)
    sizes2 = map(len, clusters)
    indices2 = map(lambda c: c.indices, clusters)
    assert_equal(len(clusters), expected_nb_clusters)
    assert_array_equal(list(sizes2), sizes1)
    assert_arrays_equal(indices2, indices1)

    qb = QB_New(threshold, metric=MDFpy())
    qb3_time = measure("clusters = qb.cluster(streamlines)", repeat)
    print("QuickBundles2_python time: {0:.4}sec".format(qb3_time))
    print("Speed up of {0}x".format(qb1_time / qb3_time))
    clusters = qb.cluster(streamlines)
    sizes3 = map(len, clusters)
    indices3 = map(lambda c: c.indices, clusters)
    assert_equal(len(clusters), expected_nb_clusters)
    assert_array_equal(list(sizes3), sizes1)
    assert_arrays_equal(indices3, indices1)
def make_kesh_template(bundle_list,
                       keystone_boi,
                       qb_thresh=5.,
                       Nsubsamp=20,
                       clsz_thresh=5,
                       keystone2MNI_xfm=None,
                       verbose=False):
    '''
    bundle_list: list of independent bundles (lists) not assumed to be in the same space
    keystone_boi: bundle (list) of streamlines that will be the anchor bundle all
                  others are registered to for the template
    qb_thresh: threshold for quickbundle (determines how finely each bundle is clustered)
    Nsubsamp: subsampling for quickbundles and SLR
    clsz_thresh: how many streamlines a cluster must have to be included in the template*
    keystone2MNI_SLR: streamlinear registration between the whole brain keystone and MNI**
    verbose: if you want to print info about each bundle as it runs set this to True


    *qb_thresh adn clsz_thresh are related. If you have a fine parcellation
    (low qb_thresh) then the clsz_threshold should be quite low since clusters
    will be small.

    **PROVIDE THIS IF (and only if) YOU WANT THE RESULT TO BE IN MNI SPACE OTHERWISE
    IT WILL BE IN KEYSTONE SPACE
    '''

    kesh_template_sls = []
    rejected_sls = []
    boi_sls_subsamp = set_number_of_points(keystone_boi, Nsubsamp)
    for i, sls in enumerate(bundle_list):
        print(len(bundle_list) - i)
        sls_subsamp = set_number_of_points(sls, Nsubsamp)
        qb = QuickBundles(threshold=qb_thresh)
        clusters = qb.cluster(sls)
        cluster_sizes = [len(cl) for cl in clusters]
        # enforce that clusters smaller than a threshold are not in template
        centroids = clusters.centroids
        slr = StreamlineLinearRegistration()
        srm = slr.optimize(static=boi_sls_subsamp, moving=sls_subsamp)
        xfmd_centroids = srm.transform(centroids)
        # NOTE: we actually want to upsample the centroids so the template has
        # better properties... what's the most efficient way to do that?
        for j, b in enumerate(xfmd_centroids):
            if cluster_sizes[j] < clsz_thresh:
                rejected_sls.append(xfmd_centroids.pop(j))
        kesh_template_sls += xfmd_centroids
        if verbose:
            print('Bundle %i' % i)
            print('N centroids: %i' % len(centroids))
            print('kept %i rejected %i total %i' %
                  (len(kesh_template_sls), len(rejected_sls), len(clusters)))
    if keystone2MNI_xfm:
        print('MNI YAY!')
    return kesh_template_sls, rejected_sls
Beispiel #16
0
def outliers_removal_using_hierarchical_quickbundles(streamlines,
                                                     min_threshold=0.5,
                                                     nb_samplings_max=30,
                                                     sampling_seed=1234):
    if nb_samplings_max < 2:
        raise ValueError("'nb_samplings_max' must be >= 2")

    rng = np.random.RandomState(sampling_seed)
    metric = "MDF_12points"

    box_min, box_max = get_streamlines_bounding_box(streamlines)
    initial_threshold = np.min(np.abs(box_max - box_min)) / 2.

    # Quickbundle's threshold is divided by 1.2 between hierarchical level.
    thresholds = list(takewhile(
        lambda t: t >= min_threshold,
        (initial_threshold / 1.2**i for i in count())))

    ordering = np.arange(len(streamlines))
    path_lengths_per_streamline = 0

    streamlines_path = np.ones((len(streamlines), len(thresholds),
                                nb_samplings_max), dtype=int) * -1

    for i in range(nb_samplings_max):
        rng.shuffle(ordering)

        cluster_orderings = [ordering]
        for j, threshold in enumerate(thresholds):
            id_cluster = 0

            next_cluster_orderings = []
            qb = QuickBundles(metric=metric, threshold=threshold)
            for cluster_ordering in cluster_orderings:
                clusters = qb.cluster(streamlines, ordering=cluster_ordering)

                for k, cluster in enumerate(clusters):
                    streamlines_path[cluster.indices, j, i] = id_cluster
                    id_cluster += 1
                    if len(cluster) > 10:
                        next_cluster_orderings.append(cluster.indices)

            cluster_orderings = next_cluster_orderings

        if i <= 1:  # Needs at least two orderings to compute stderror.
            continue

    path_lengths_per_streamline = np.sum((streamlines_path != -1),
                                         axis=1)[:, :i]

    summary = np.mean(path_lengths_per_streamline,
                      axis=1) / np.max(path_lengths_per_streamline)
    return summary
Beispiel #17
0
def get_centroid_streamline(tractogram, nb_points, distance_threshold):
    streamlines = tractogram.streamlines
    resample_feature = ResampleFeature(nb_points=nb_points)
    quick_bundle = QuickBundles(
        threshold=distance_threshold,
        metric=AveragePointwiseEuclideanMetric(resample_feature))
    clusters = quick_bundle.cluster(streamlines)
    centroid_streamlines = clusters.centroids

    if len(centroid_streamlines) > 1:
        raise Exception('Multiple centroids found')

    return Tractogram(centroid_streamlines, affine_to_rasmm=np.eye(4))
def auto_extract(model_cluster_map, rstreamlines,
                 number_pts_per_str=NB_POINTS_RESAMPLE,
                 close_centroids_thr=20,
                 clean_thr=7.,
                 disp=False, verbose=False,
                 ordering=None):

    if ordering is None:
        ordering = np.arange(len(rstreamlines))

    qb = QuickBundles(threshold=REF_BUNDLES_THRESHOLD, metric=AveragePointwiseEuclideanMetric())
    closest_bundles = qb.find_closest(model_cluster_map, rstreamlines, clean_thr, ordering=ordering)
    return ordering[np.where(closest_bundles >= 0)[0]]
Beispiel #19
0
def computeQuickBundles(streamlines, threshold):  #1.
    from dipy.segment.clustering import QuickBundles

    qb = QuickBundles(threshold)
    clusters = qb.cluster(streamlines)

    print("Nb. clusters:", len(clusters))
    #print("Cluster sizes:", map(len, clusters))
    print("Nb. small clusters:", sum(clusters < 10))
    #print("Streamlines indices of the first cluster:\n", clusters[0].indices)
    #print("Centroid of the last cluster:\n", clusters[-1].centroid)

    return clusters
Beispiel #20
0
def computeQuickBundles(streamlines, threshold): #1.
    from dipy.segment.clustering import QuickBundles

    qb = QuickBundles(threshold)
    clusters = qb.cluster(streamlines)

    print("Nb. clusters:", len(clusters))
    #print("Cluster sizes:", map(len, clusters))
    print("Nb. small clusters:", sum(clusters < 10))
    #print("Streamlines indices of the first cluster:\n", clusters[0].indices)
    #print("Centroid of the last cluster:\n", clusters[-1].centroid)

    return clusters
    def quickbundles(self, streamlines):
        """Segment tract with QuickBundles."""

        # TODO: implement other metrics
        try:
            from dipy.segment.clustering import QuickBundles
            from dipy.segment.metric import ResampleFeature
            from dipy.segment.metric import AveragePointwiseEuclideanMetric
        except ImportError:
            return None
        else:

            feature = ResampleFeature(nb_points=self.qb_points)
            metric = AveragePointwiseEuclideanMetric(feature=feature)
            qb = QuickBundles(threshold=self.qb_threshold, metric=metric)
            clusters = qb.cluster(streamlines)

        return clusters
Beispiel #22
0
def qb_metrics_features(streamlines,
                        threshold=10.0,
                        metric=None,
                        max_nb_clusters=np.iinfo('i4').max):
    """
    Enhancing QuickBundles with different metrics and features
    metric: 'IF', 'RF', 'CoMF', 'MF', 'AF', 'VBEF', None
    """
    if metric == 'IF':
        feature = IdentityFeature()
        metric = AveragePointwiseEuclideanMetric(feature=feature)
    elif metric == 'RF':
        feature = ResampleFeature(nb_point=24)
        metric = AveragePointwiseEuclideanMetric(feature=feature)
    elif metric == 'CoMF':
        feature = CenterOfMassFeature()
        metric = EuclideanMetric(feature)
    elif metric == 'MF':
        feature = MidpointFeature()
        metric = EuclideanMetric(feature)
    elif metric == 'AF':
        feature = ArcLengthFeature()
        metric = EuclideanMetric(feature)
    elif metric == 'VBEF':
        feature = VectorOfEndpointsFeature()
        metric = CosineMetric(feature)
    else:
        metric = "MDF_12points"

    qb = QuickBundles(threshold=threshold,
                      metric=metric,
                      max_nb_clusters=max_nb_clusters)
    clusters = qb.cluster(streamlines)

    labels = np.array(len(streamlines) * [None])
    N_list = []
    for i in range(len(clusters)):
        N_list.append(clusters[i]['N'])
    data_clusters = []
    for i in range(len(clusters)):
        labels[clusters[i]['indices']] = i + 1
        data_clusters.append(streamlines[clusters[i]['indices']])

    return labels, data_clusters, N_list
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 auto_extract(model_cluster_map,
                 rstreamlines,
                 number_pts_per_str=NB_POINTS_RESAMPLE,
                 close_centroids_thr=20,
                 clean_thr=7.,
                 disp=False,
                 verbose=False,
                 ordering=None):

    if ordering is None:
        ordering = np.arange(len(rstreamlines))

    qb = QuickBundles(threshold=REF_BUNDLES_THRESHOLD,
                      metric=AveragePointwiseEuclideanMetric())
    closest_bundles = qb.find_closest(model_cluster_map,
                                      rstreamlines,
                                      clean_thr,
                                      ordering=ordering)
    return ordering[np.where(closest_bundles >= 0)[0]]
Beispiel #25
0
def _prepare_gt_bundles_info(bundles_dir, bundles_masks_dir,
                             gt_bundles_attribs, ref_anat_fname):
    # Ref bundles will contain {'name': 'name_of_the_bundle',
    #                           'threshold': thres_value,
    #                           'streamlines': list_of_streamlines}

    dummy_attribs = {'orientation': 'LPS'}
    qb = QuickBundles(20, metric=AveragePointwiseEuclideanMetric())

    ref_bundles = []

    for bundle_idx, bundle_f in enumerate(sorted(os.listdir(bundles_dir))):
        bundle_name = os.path.splitext(os.path.basename(bundle_f))[0]

        bundle_attribs = gt_bundles_attribs.get(os.path.basename(bundle_f))
        if bundle_attribs is None:
            raise ValueError(
                "Missing basic bundle attribs for {0}".format(bundle_f))

        # Already resample to avoid doing it for each iteration of chunking
        orig_strl = [
            s for s in get_tracts_voxel_space_for_dipy(
                os.path.join(bundles_dir, bundle_f), ref_anat_fname,
                dummy_attribs)
        ]

        resamp_bundle = set_number_of_points(orig_strl, NB_POINTS_RESAMPLE)
        resamp_bundle = [s.astype('f4') for s in resamp_bundle]

        bundle_cluster_map = qb.cluster(resamp_bundle)
        bundle_cluster_map.refdata = resamp_bundle

        bundle_mask = nib.load(
            os.path.join(bundles_masks_dir, bundle_name + '.nii.gz'))

        ref_bundles.append({
            'name': bundle_name,
            'threshold': bundle_attribs['cluster_threshold'],
            'cluster_map': bundle_cluster_map,
            'mask': bundle_mask
        })

    return ref_bundles
Beispiel #26
0
def neuro_cluster(infile, outfile, m, threshold):
    with open(infile, 'rb') as infile:
        df_metric = pickle.load(infile)

    streams = []
    for i in range(df_metric.iloc[-1]["route_num"] + 1):
        df_temp = df_metric[df_metric["route_num"] == i]
        del df_temp["route_num"]
        if (not (df_temp.empty)):
            streams.append(np.array(df_temp.values.tolist()))

    #metric = GPSDistanceTuto()
    #qb = QuickBundles(threshold=threshold, metric=metric)

    qb = QuickBundles(threshold=threshold, metric=m)
    streams = np.array(streams)
    clusters = qb.cluster(streams)
    print(len(clusters))
    '''with open(outfile, 'wb') as outfile:
Beispiel #27
0
def test_quickbundles_shape_uncompatibility():
    # QuickBundles' old default metric (AveragePointwiseEuclideanMetric, aka MDF)
    # requires that all streamlines have the same number of points.
    metric = dipymetric.AveragePointwiseEuclideanMetric()
    qb = QuickBundles(threshold=20., metric=metric)
    assert_raises(ValueError, qb.cluster, data)

    # QuickBundles' new default metric (AveragePointwiseEuclideanMetric, aka MDF
    #  combined with ResampleFeature) will automatically resample streamlines so
    #  they all have 18 points.
    qb = QuickBundles(threshold=20.)
    clusters1 = qb.cluster(data)

    feature = dipymetric.ResampleFeature(nb_points=18)
    metric = dipymetric.AveragePointwiseEuclideanMetric(feature)
    qb = QuickBundles(threshold=20., metric=metric)
    clusters2 = qb.cluster(data)

    assert_array_equal(list(itertools.chain(*clusters1)), list(itertools.chain(*clusters2)))
def computeStats(subjectID,reference,streamlines,classification,outdir):

	avg_length = []
	avg_curv = []
	stream_count = []
	mean_x = []
	mean_y = []
	mean_z = []
	num_vox = []

	tract_index_labels = np.trim_zeros(np.unique(classification['index'].tolist()))

	qb = QuickBundles(np.inf)

	for i in tract_index_labels:
		indices = [ t for t in range(len(classification['index'].tolist())) if classification['index'].tolist()[int(t)] == i ]
		avg_length.append(np.mean(length(streamlines[indices])))
		
		clusters = qb.cluster(streamlines[indices])
		avg_curv.append(mean_curvature(clusters.centroids[0]))
		orientation = mean_orientation(clusters.centroids[0])
		mean_x.append(orientation[0])
		mean_y.append(orientation[1])
		mean_z.append(orientation[2])
		stream_count.append(len(indices))
		denmap = density_map(streamlines[indices],reference.affine,reference.shape)
		num_vox.append(len(denmap[denmap>0]))

	df = pd.DataFrame([],dtype=object)
	df['subjectID'] = [ subjectID for f in range(len(classification['names'].tolist())) ]
	df['structureID'] = [ f for f in classification['names'].tolist() ]
	df['nodeID'] = [ 1 for f in range(len(df['structureID'])) ]
	df['streamline_count'] = stream_count
	df['average_length'] = avg_length
	df['average_curvature'] = avg_curv
	df['voxel_count'] = num_vox
	df['centroid_x'] = mean_x
	df['centroid_y'] = mean_y
	df['centroid_z'] = mean_z

	df.to_csv('%s/output_FiberStats.csv' %outdir,index=False)
Beispiel #29
0
def test_quickbundles_streamlines():
    rdata = streamline_utils.set_number_of_points(data, 10)
    qb = QuickBundles(threshold=2*threshold)

    clusters = qb.cluster(rdata)
    # By default `refdata` refers to data being clustered.
    assert_equal(clusters.refdata, rdata)
    # Set `refdata` to return indices instead of actual data points.
    clusters.refdata = None
    assert_array_equal(list(itertools.chain(*clusters)),
                       list(itertools.chain(*clusters_truth)))

    # Cluster read-only data
    for datum in rdata:
        datum.setflags(write=False)

    # Cluster data with different dtype (should be converted into float32)
    for datatype in [np.float64, np.int32, np.int64]:
        newdata = [datum.astype(datatype) for datum in rdata]
        clusters = qb.cluster(newdata)
        assert_equal(clusters.centroids[0].dtype, np.float32)
Beispiel #30
0
def test_quickbundles_streamlines():
    rdata = streamline_utils.set_number_of_points(data, 10)
    qb = QuickBundles(threshold=2 * threshold)

    clusters = qb.cluster(rdata)
    # By default `refdata` refers to data being clustered.
    assert_equal(clusters.refdata, rdata)
    # Set `refdata` to return indices instead of actual data points.
    clusters.refdata = None
    assert_array_equal(list(itertools.chain(*clusters)),
                       list(itertools.chain(*clusters_truth)))

    # Cluster read-only data
    for datum in rdata:
        datum.setflags(write=False)

    # Cluster data with different dtype (should be converted into float32)
    for datatype in [np.float64, np.int32, np.int64]:
        newdata = [datum.astype(datatype) for datum in rdata]
        clusters = qb.cluster(newdata)
        assert_equal(clusters.centroids[0].dtype, np.float32)
Beispiel #31
0
    def _cluster(self, threshold):
        qb = QuickBundles(metric=metric, threshold=threshold)
        self.last_threshold = threshold

        self.clusters = qb.cluster(self.streamlines)
        self.clusters_colors = [
            color for c, color in zip(
                self.clusters,
                distinguishable_colormap(bg=(0, 0, 0), exclude=darkcolors))
        ]

        if threshold < np.inf:
            print("{} clusters with QB threshold of {}mm".format(
                len(self.clusters), threshold))

        # Keep a flag telling there have been changes.
        self.has_changed = True

        if len(self.clusters) == 1:
            # Keep initial color
            self.clusters_colors = [self.color
                                    ] if self.color is not None else [(0, 0,
                                                                       1)]
            vtk_colors = utils.numpy_to_vtk_colors(255 * self.original_colors)
            vtk_colors.SetName("Colors")
            self.actor.GetMapper().GetInput().GetPointData().SetScalars(
                vtk_colors)
            return

        for cluster, color in zip(self.clusters, self.clusters_colors):
            self.streamlines_colors[cluster.indices] = color

        self.colors = []
        for color, streamline in zip(self.streamlines_colors,
                                     self.streamlines):
            self.colors += [color] * len(streamline)

        vtk_colors = utils.numpy_to_vtk_colors(255 * np.array(self.colors))
        vtk_colors.SetName("Colors")
        self.actor.GetMapper().GetInput().GetPointData().SetScalars(vtk_colors)
def quickClean(streamlines, number_bundles):

    # set up counter for n_clusters and start threshold distance at 1mm.
    n_clusters = 0
    thrs = 1

    # loop through clustering until number_bundles of bundles segmented
    while n_clusters != number_bundles:
        qb = QuickBundles(threshold=thrs)
        clusters = qb.cluster(streamlines)
        n_clusters = len(clusters)
        thrs = thrs + 1
        if n_clusters == (number_bundles - 1):
            thrs = thrs - 2
            for i in np.linspace(thrs, thrs + 1, num=1000):
                print(i)
                qb = QuickBundles(threshold=i)
                clusters = qb.cluster(streamlines)
                n_clusters = len(clusters)
                if n_clusters == number_bundles:
                    break

    print(thrs)

    return clusters
Beispiel #33
0
def _prepare_gt_bundles_info(bundles_dir, bundles_masks_dir,
                             gt_bundles_attribs, ref_anat_fname):
    # Ref bundles will contain {'name': 'name_of_the_bundle',
    #                           'threshold': thres_value,
    #                           'streamlines': list_of_streamlines}

    dummy_attribs = {'orientation': 'LPS'}
    qb = QuickBundles(20, metric=AveragePointwiseEuclideanMetric())

    ref_bundles = []

    for bundle_idx, bundle_f in enumerate(sorted(os.listdir(bundles_dir))):
        bundle_name = os.path.splitext(os.path.basename(bundle_f))[0]

        bundle_attribs = gt_bundles_attribs.get(os.path.basename(bundle_f))
        if bundle_attribs is None:
            raise ValueError(
                "Missing basic bundle attribs for {0}".format(bundle_f))

        # Already resample to avoid doing it for each iteration of chunking
        orig_strl = [s for s in get_tracts_voxel_space_for_dipy(
                        os.path.join(bundles_dir, bundle_f),
                        ref_anat_fname, dummy_attribs)]

        resamp_bundle = set_number_of_points(orig_strl, NB_POINTS_RESAMPLE)
        resamp_bundle = [s.astype('f4') for s in resamp_bundle]

        bundle_cluster_map = qb.cluster(resamp_bundle)
        bundle_cluster_map.refdata = resamp_bundle

        bundle_mask = nib.load(os.path.join(bundles_masks_dir,
                                            bundle_name + '.nii.gz'))

        ref_bundles.append({'name': bundle_name,
                            'threshold': bundle_attribs['cluster_threshold'],
                            'cluster_map': bundle_cluster_map,
                            'mask': bundle_mask})

    return ref_bundles
Beispiel #34
0
def get_streamlines_centroid(streamlines, nb_points):
    """
    Compute centroid from streamlines using QuickBundles.

    Parameters
    ----------
    streamlines: list of ndarray
        The list of streamlines from which we compute the centroid.
    nb_points: int
        Number of points defining the centroid streamline.

    Returns
    -------
    List of length one, containing a np.ndarray of shape (nb_points, 3)
    """
    resample_feature = ResampleFeature(nb_points=nb_points)
    quick_bundle = QuickBundles(
        threshold=np.inf,
        metric=AveragePointwiseEuclideanMetric(resample_feature))
    clusters = quick_bundle.cluster(streamlines)
    centroid_streamlines = clusters.centroids

    return centroid_streamlines
Beispiel #35
0
def assignment_map(target_bundle, model_bundle, no_disks):
    """
    Calculates assignment maps of the target bundle with reference to
    model bundle centroids.

    Parameters
    ----------
    target_bundle : streamlines
        target bundle extracted from subject data in common space
    model_bundle : streamlines
        atlas bundle used as reference
    no_disks : integer, optional
        Number of disks used for dividing bundle into disks. (Default 100)

    References
    ----------
    .. [Chandio2020] Chandio, B.Q., Risacher, S.L., Pestilli, F., Bullock, D.,
    Yeh, FC., Koudoro, S., Rokem, A., Harezlak, J., and Garyfallidis, E.
    Bundle analytics, a computational framework for investigating the
    shapes and profiles of brain pathways across populations.
    Sci Rep 10, 17149 (2020)

    """

    mbundle_streamlines = set_number_of_points(model_bundle,
                                               nb_points=no_disks)

    metric = AveragePointwiseEuclideanMetric()
    qb = QuickBundles(threshold=85., metric=metric)
    clusters = qb.cluster(mbundle_streamlines)
    centroids = Streamlines(clusters.centroids)

    _, indx = cKDTree(centroids.get_data(), 1,
                      copy_data=True).query(target_bundle.get_data(), k=1)

    return indx
Beispiel #36
0
def tractograms_slr(moving_tractogram, static_tractogram):

    subjID = ntpath.basename(static_tractogram)[0:6]
    exID = ntpath.basename(moving_tractogram)[0:6]

    aff_dir = '/N/dc2/projects/lifebid/giulia/data/HCP3-IU-Giulia/derivatives/slr_transformations'
    affine_path = '%s/affine_m%s_s%s.npy' % (aff_dir, exID, subjID)
    affine_fname = './affine_m%s_s%s.npy' % (exID, subjID)

    if isfile(affine_path):
        print("Affine already computed. Retrieving past results.")
        copyfile(affine_path, affine_fname)

    else:
        print("Loading tractograms...")
        moving_tractogram = nib.streamlines.load(moving_tractogram)
        moving_tractogram = moving_tractogram.streamlines
        static_tractogram = nib.streamlines.load(static_tractogram)
        static_tractogram = static_tractogram.streamlines

        print("Set parameters as in Garyfallidis et al. 2015.")
        threshold_length = 40.0  # 50mm / 1.25
        qb_threshold = 16.0  # 20mm / 1.25
        nb_res_points = 20

        print("Performing QuickBundles of static tractogram and resampling...")
        st = np.array(
            [s for s in static_tractogram if len(s) > threshold_length],
            dtype=np.object)
        qb = QuickBundles(threshold=qb_threshold)
        st_clusters = [cluster.centroid for cluster in qb.cluster(st)]
        st_clusters = set_number_of_points(st_clusters, nb_res_points)

        print("Performing QuickBundles of moving tractogram and resampling...")
        mt = np.array(
            [s for s in moving_tractogram if len(s) > threshold_length],
            dtype=np.object)
        qb = QuickBundles(threshold=qb_threshold)
        mt_clusters = [cluster.centroid for cluster in qb.cluster(mt)]
        mt_clusters = set_number_of_points(mt_clusters, nb_res_points)

        print("Performing Linear Registration...")
        srr = StreamlineLinearRegistration()
        srm = srr.optimize(static=st_clusters, moving=mt_clusters)

        print(
            "Affine transformation matrix with Streamline Linear Registration:"
        )
        affine = srm.matrix
        print('%s' % affine)

        np.save('affine_m%s_s%s.npy' % (exID, subjID), affine)
        print("Affine for example %s and target %s saved." % (exID, subjID))
Beispiel #37
0
def test_quickbundles_shape_uncompatibility():
    # QuickBundles' old default metric (AveragePointwiseEuclideanMetric,
    #  aka MDF) requires that all streamlines have the same number of points.
    metric = dipymetric.AveragePointwiseEuclideanMetric()
    qb = QuickBundles(threshold=20., metric=metric)
    assert_raises(ValueError, qb.cluster, data)

    # QuickBundles' new default metric (AveragePointwiseEuclideanMetric,
    # aka MDF combined with ResampleFeature) will automatically resample
    # streamlines so they all have 18 points.
    qb = QuickBundles(threshold=20.)
    clusters1 = qb.cluster(data)

    feature = dipymetric.ResampleFeature(nb_points=18)
    metric = dipymetric.AveragePointwiseEuclideanMetric(feature)
    qb = QuickBundles(threshold=20., metric=metric)
    clusters2 = qb.cluster(data)

    assert_array_equal(list(itertools.chain(*clusters1)),
                       list(itertools.chain(*clusters2)))
def tractograms_slr(moving_tractogram, static_tractogram):

    subjID = ntpath.basename(static_tractogram)[0:6]
    exID = ntpath.basename(moving_tractogram)[0:6]

    print("Loading tractograms...")
    moving_tractogram = nib.streamlines.load(moving_tractogram)
    moving_tractogram = moving_tractogram.streamlines
    static_tractogram = nib.streamlines.load(static_tractogram)
    static_tractogram = static_tractogram.streamlines

    print("Set parameters as in Garyfallidis et al. 2015.")
    threshold_length = 40.0  # 50mm / 1.25
    qb_threshold = 16.0  # 20mm / 1.25
    nb_res_points = 20

    print("Performing QuickBundles of static tractogram and resampling...")
    st = np.array([s for s in static_tractogram if len(s) > threshold_length],
                  dtype=np.object)
    qb = QuickBundles(threshold=qb_threshold)
    st_clusters = [cluster.centroid for cluster in qb.cluster(st)]
    st_clusters = set_number_of_points(st_clusters, nb_res_points)

    print("Performing QuickBundles of moving tractogram and resampling...")
    mt = np.array([s for s in moving_tractogram if len(s) > threshold_length],
                  dtype=np.object)
    qb = QuickBundles(threshold=qb_threshold)
    mt_clusters = [cluster.centroid for cluster in qb.cluster(mt)]
    mt_clusters = set_number_of_points(mt_clusters, nb_res_points)

    print("Performing Linear Registration...")
    srr = StreamlineLinearRegistration()
    srm = srr.optimize(static=st_clusters, moving=mt_clusters)

    print("Affine transformation matrix with Streamline Linear Registration:")
    affine = srm.matrix
    print('%s' % affine)

    np.save('affine_m%s_s%s.npy' % (exID, subjID), affine)
    print("Affine for example %s and target %s saved." % (exID, subjID))
Beispiel #39
0
def bundle_analysis(model_bundle_folder, bundle_folder, orig_bundle_folder,
                    metric_folder, group, subject, no_disks=100,
                    out_dir=''):
    """
    Applies statistical analysis on bundles and saves the results
    in a directory specified by ``out_dir``.

    Parameters
    ----------
    model_bundle_folder : string
        Path to the input model bundle files. This path may contain
        wildcards to process multiple inputs at once.
    bundle_folder : string
        Path to the input bundle files in common space. This path may
        contain wildcards to process multiple inputs at once.
    orig_folder : string
        Path to the input bundle files in native space. This path may
        contain wildcards to process multiple inputs at once.
    metric_folder : string
        Path to the input dti metric or/and peak files. It will be used as
        metric for statistical analysis of bundles.
    group : string
        what group subject belongs to e.g. control or patient
    subject : string
        subject id e.g. 10001
    no_disks : integer, optional
        Number of disks used for dividing bundle into disks. (Default 100)
    out_dir : string, optional
        Output directory (default input file directory)

    References
    ----------
    .. [Chandio19] Chandio, B.Q., S. Koudoro, D. Reagan, J. Harezlak,
    E. Garyfallidis, Bundle Analytics: a computational and statistical
    analyses framework for tractometric studies, Proceedings of:
    International Society of Magnetic Resonance in Medicine (ISMRM),
    Montreal, Canada, 2019.

    """

    dt = dict()

    mb = os.listdir(model_bundle_folder)
    mb.sort()
    bd = os.listdir(bundle_folder)
    bd.sort()
    org_bd = os.listdir(orig_bundle_folder)
    org_bd.sort()
    n = len(org_bd)

    for io in range(n):
        mbundles, _ = load_trk(os.path.join(model_bundle_folder, mb[io]))
        bundles, _ = load_trk(os.path.join(bundle_folder, bd[io]))
        orig_bundles, _ = load_trk(os.path.join(orig_bundle_folder,
                                   org_bd[io]))

        mbundle_streamlines = set_number_of_points(mbundles,
                                                   nb_points=no_disks)

        metric = AveragePointwiseEuclideanMetric()
        qb = QuickBundles(threshold=25., metric=metric)
        clusters = qb.cluster(mbundle_streamlines)
        centroids = Streamlines(clusters.centroids)

        print('Number of centroids ', len(centroids.data))
        print('Model bundle ', mb[io])
        print('Number of streamlines in bundle in common space ',
              len(bundles))
        print('Number of streamlines in bundle in original space ',
              len(orig_bundles))

        _, indx = cKDTree(centroids.data, 1,
                          copy_data=True).query(bundles.data, k=1)

        metric_files_names = os.listdir(metric_folder)
        _, affine = load_nifti(os.path.join(metric_folder, "fa.nii.gz"))

        affine_r = np.linalg.inv(affine)
        transformed_orig_bundles = transform_streamlines(orig_bundles,
                                                         affine_r)

        for mn in range(0, len(metric_files_names)):

            ind = np.array(indx)
            fm = metric_files_names[mn][:2]
            bm = mb[io][:-4]
            dt = dict()
            metric_name = os.path.join(metric_folder,
                                       metric_files_names[mn])

            if metric_files_names[mn][2:] == '.nii.gz':
                metric, _ = load_nifti(metric_name)

                dti_measures(transformed_orig_bundles, metric, dt, fm,
                             bm, subject, group, ind, out_dir)

            else:
                fm = metric_files_names[mn][:3]
                metric = load_peaks(metric_name)
                peak_values(bundles, metric, dt, fm, bm, subject, group,
                            ind, out_dir)
Beispiel #40
0
from dipy.segment.clustering import QuickBundles
from dipy.segment.metric import IdentityFeature
from dipy.segment.metric import AveragePointwiseEuclideanMetric

# Get some streamlines.
streamlines = get_streamlines()  # Previously defined.

# Make sure our streamlines have the same number of points.
from dipy.tracking.streamline import set_number_of_points
streamlines = set_number_of_points(streamlines, nb_points=12)

# Create an instance of `IdentityFeature` and tell metric to use it.
feature = IdentityFeature()
metric = AveragePointwiseEuclideanMetric(feature=feature)
qb = QuickBundles(threshold=10., metric=metric)
clusters = qb.cluster(streamlines)

print("Nb. clusters:", len(clusters))
print("Cluster sizes:", list(map(len, clusters)))
"""

::

    Nb. clusters: 4

    Cluster sizes: [64, 191, 47, 1]


.. _clustering-examples-ResampleFeature:
tractogram_fn = args[1]
output_dir = args[2]
subject = args[3]
tract_name = args[4]
max_num_centroids = int(args[5])
points_per_sl = int(args[6])

# Open the file and extract streamlines
streams, header = trackvis.read(tractogram_fn)
streamlines = [sl[0] for sl in streams]

# Run quickbundles with chosen parameters
feature = ResampleFeature(nb_points=points_per_sl)
metric = AveragePointwiseEuclideanMetric(feature)
qb = QuickBundles(threshold=10.,
                  max_nb_clusters=max_num_centroids,
                  metric=metric)
clusters = qb.cluster(streamlines)

# Extract the centroids
centroids = [cluster.centroid for cluster in clusters]

# If not enough generated, fill with empty streamlines
diff = max_num_centroids - len(centroids)
if diff > 0:
    print(
        "Not enough centroids generated, so generating empty streamlines for padding."
    )
    empty_sl = np.zeros((points_per_sl, 3), dtype=np.float32)
    for num in range(diff):
        centroids.append(empty_sl)
"""

streams, hdr = tv.read(fname)

streamlines = [i[0] for i in streams]

"""
Perform QuickBundles clustering using the MDF metric and a 10mm distance
threshold. Keep in mind that since the MDF metric requires streamlines to have
the same number of points, the clustering algorithm will internally use a
representation of streamlines that have been automatically downsampled/upsampled
so they have only 12 points (To set manually the number of points,
see :ref:`clustering-examples-ResampleFeature`).
"""

qb = QuickBundles(threshold=10.)
clusters = qb.cluster(streamlines)

"""
`clusters` is a `ClusterMap` object which contains attributes that
provide information about the clustering result.
"""

print("Nb. clusters:", len(clusters))
print("Cluster sizes:", map(len, clusters))
print("Small clusters:", clusters < 10)
print("Streamlines indices of the first cluster:\n", clusters[0].indices)
print("Centroid of the last cluster:\n", clusters[-1].centroid)

"""
Beispiel #43
0

"""
Fiber clustering
----------------

Based on an agglomerative clustering, and a geometric distance.
"""

clustering_outdir = os.path.join(outdir, "clustering")
cluster_file = os.path.join(clustering_outdir, "clusters.json")
if not os.path.isdir(clustering_outdir):
    os.mkdir(clustering_outdir)
if not os.path.isfile(cluster_file):
    fibers_18 = [resample(track, nb_pol=18) for track in fibers]
    qb = QuickBundles(threshold=10.)
    clusters_ = qb.cluster(fibers_18)
    clusters = {}
    for cnt, cluster in enumerate(clusters_):
        clusters[str(cnt)] = {"indices": cluster.indices}
    with open(cluster_file, "w") as open_file:
        json.dump(clusters, open_file, indent=4)
else:
    with open(cluster_file) as open_file:
        clusters = json.load(open_file)

if 1: #use_vtk:
    ren = pvtk.ren()
    colors = numpy.ones((len(fibers),))
    nb_clusters = len(clusters)
    for clusterid, item in clusters.items():
def auto_extract_VCs(streamlines, ref_bundles):
    # Streamlines = list of all streamlines

    VC = 0
    VC_idx = set()

    found_vbs_info = {}
    for bundle in ref_bundles:
        found_vbs_info[bundle['name']] = {'nb_streamlines': 0,
                                          'streamlines_indices': set()}

    # Need to bookkeep because we chunk for big datasets
    processed_strl_count = 0
    chunk_size = 5000
    chunk_it = 0

    nb_bundles = len(ref_bundles)
    bundles_found = [False] * nb_bundles

    logging.debug("Starting scoring VCs")

    qb = QuickBundles(threshold=20, metric=AveragePointwiseEuclideanMetric())

    # Start loop here for big datasets
    while processed_strl_count < len(streamlines):
        logging.debug("Starting chunk: {0}".format(chunk_it))

        strl_chunk = streamlines[chunk_it * chunk_size:
                                 (chunk_it + 1) * chunk_size]

        processed_strl_count += len(strl_chunk)
        cur_chunk_VC_idx, cur_chunk_IC_idx, cur_chunk_VCWP_idx = set(), set(), set()

        # Already resample and run quickbundles on the submission chunk,
        # to avoid doing it at every call of auto_extract
        rstreamlines = set_number_of_points(strl_chunk, NB_POINTS_RESAMPLE)

        # qb.cluster had problem with f8
        rstreamlines = [s.astype('f4') for s in rstreamlines]

        chunk_cluster_map = qb.cluster(rstreamlines)
        chunk_cluster_map.refdata = strl_chunk

        logging.debug("Starting VC identification through auto_extract")

        for bundle_idx, ref_bundle in enumerate(ref_bundles):
            # The selected indices are from [0, len(strl_chunk)]
            selected_streamlines_indices = auto_extract(ref_bundle['cluster_map'],
                                                        chunk_cluster_map,
                                                        clean_thr=ref_bundle['threshold'])

            # Remove duplicates, when streamlines are assigned to multiple VBs.
            selected_streamlines_indices = set(selected_streamlines_indices) - \
                                           cur_chunk_VC_idx
            cur_chunk_VC_idx |= selected_streamlines_indices

            nb_selected_streamlines = len(selected_streamlines_indices)

            if nb_selected_streamlines:
                bundles_found[bundle_idx] = True
                VC += nb_selected_streamlines

                # Shift indices to match the real number of streamlines
                global_select_strl_indices = set([v + chunk_it * chunk_size
                                                 for v in selected_streamlines_indices])
                vb_info = found_vbs_info.get(ref_bundle['name'])
                vb_info['nb_streamlines'] += nb_selected_streamlines
                vb_info['streamlines_indices'] |= global_select_strl_indices

                VC_idx |= global_select_strl_indices
            else:
                global_select_strl_indices = set()

        chunk_it += 1

    # Compute bundle overlap, overreach and f1_scores and update found_vbs_info
    for bundle_idx, ref_bundle in enumerate(ref_bundles):
        bundle_name = ref_bundle["name"]
        bundle_mask = ref_bundle["mask"]

        vb_info = found_vbs_info[bundle_name]

        # Streamlines are in voxel space since that's how they were
        # loaded in the scoring function.
        tractogram = Tractogram(streamlines=(streamlines[i] for i in vb_info['streamlines_indices']),
                                affine_to_rasmm=bundle_mask.affine)

        scores = {}
        if len(tractogram) > 0:
            scores = compute_bundle_coverage_scores(tractogram, bundle_mask)

        vb_info['overlap'] = scores.get("OL", 0)
        vb_info['overreach'] = scores.get("OR", 0)
        vb_info['overreach_norm'] = scores.get("ORn", 0)
        vb_info['f1_score'] = scores.get("F1", 0)

    return VC_idx, found_vbs_info
def score_from_files(filename, masks_dir, bundles_dir,
                     tracts_attribs, basic_bundles_attribs,
                     save_segmented=False, save_IBs=False,
                     save_VBs=False, save_VCWPs=False,
                     segmented_out_dir='', segmented_base_name='',
                     verbose=False):
    """
    Computes all metrics in order to score a tractogram.

    Given a ``tck`` file of streamlines and a folder containing masks,
    compute the percent of: Valid Connections (VC), Invalid Connections (IC),
    Valid Connections but Wrong Path (VCWP), No Connections (NC),
    Average Bundle Coverage (ABC), Average ROIs Coverage (ARC),
    coverage per bundles and coverage per ROIs. It also provides the number of:
    Valid Bundles (VB), Invalid Bundles (IB) and streamlines per bundles.


    Parameters
    ------------
    filename : str
       name of a tracts file
    masks_dir : str
       name of the directory containing the masks
    save_segmented : bool
        if true, saves the segmented VC, IC, VCWP and NC

    Returns
    ---------
    scores : dict
        dictionnary containing a score for each metric
    indices : dict
        dictionnary containing the indices of streamlines composing VC, IC,
        VCWP and NC

    """
    if verbose:
        logging.basicConfig(level=logging.DEBUG)

    rois_dir = masks_dir + "rois/"
    bundles_masks_dir = masks_dir + "bundles/"
    wm_file = masks_dir + "wm.nii.gz"
    wm = nib.load(wm_file)

    streamlines = load_streamlines(filename, wm_file, tracts_attribs)

    ROIs = [nib.load(rois_dir + f) for f in sorted(os.listdir(rois_dir))]
    bundles_masks = [nib.load(bundles_masks_dir + f) for f in sorted(os.listdir(bundles_masks_dir))]
    ref_bundles = []

    # Ref bundles will contain {'name': 'name_of_the_bundle', 'threshold': thres_value,
    #                           'streamlines': list_of_streamlines}
    dummy_attribs = {'orientation': 'LPS'}
    qb = QuickBundles(threshold=REF_BUNDLES_THRESHOLD, metric=AveragePointwiseEuclideanMetric())

    out_centroids_dir = os.path.join(segmented_out_dir, os.path.pardir, "centroids")
    if not os.path.isdir(out_centroids_dir):
        os.mkdir(out_centroids_dir)

    rng = np.random.RandomState(42)

    for bundle_idx, bundle_f in enumerate(sorted(os.listdir(bundles_dir))):
        bundle_attribs = basic_bundles_attribs.get(os.path.basename(bundle_f))
        if bundle_attribs is None:
            raise ValueError("Missing basic bundle attribs for {0}".format(bundle_f))

        # # Already resample to avoid doing it for each iteration of chunking
        # orig_strl = [s for s in get_tracts_voxel_space_for_dipy(
        #                         os.path.join(bundles_dir, bundle_f),
        #                         wm_file, dummy_attribs)]
        orig_strl = load_streamlines(os.path.join(bundles_dir, bundle_f), wm_file, dummy_attribs)
        resamp_bundle = set_number_of_points(orig_strl, NB_POINTS_RESAMPLE)
        # resamp_bundle = [s.astype('f4') for s in resamp_bundle]

        indices = np.arange(len(resamp_bundle))
        rng.shuffle(indices)
        bundle_cluster_map = qb.cluster(resamp_bundle, ordering=indices)

        # bundle_cluster_map.refdata = resamp_bundle

        bundle_mask_inv = nib.Nifti1Image((1 - bundles_masks[bundle_idx].get_data()) * wm.get_data(),
                                          bundles_masks[bundle_idx].get_affine())

        ref_bundles.append({'name': os.path.basename(bundle_f).replace('.fib', '').replace('.tck', ''),
                            'threshold': bundle_attribs['cluster_threshold'],
                            'cluster_map': bundle_cluster_map,
                            'mask': bundles_masks[bundle_idx],
                            'mask_inv': bundle_mask_inv})

        logging.debug("{}: {} centroids".format(ref_bundles[-1]['name'], len(bundle_cluster_map)))
        nib.streamlines.save(nib.streamlines.Tractogram(bundle_cluster_map.centroids, affine_to_rasmm=np.eye(4)),
                             os.path.join(out_centroids_dir, ref_bundles[-1]['name'] + ".tck"))

    score_func = score_auto_extract_auto_IBs

    return score_func(streamlines, bundles_masks, ref_bundles, ROIs, wm,
                      save_segmented=save_segmented, save_IBs=save_IBs,
                      save_VBs=save_VBs, save_VCWPs=save_VCWPs,
                      out_segmented_strl_dir=segmented_out_dir,
                      base_out_segmented_strl=segmented_base_name,
                      ref_anat_fname=wm_file)
def _auto_extract_VCs(streamlines, ref_bundles):
    # Streamlines = list of all streamlines

    # TODO check what is neede
    # VC = 0
    VC_idx = set()

    found_vbs_info = {}
    for bundle in ref_bundles:
        found_vbs_info[bundle['name']] = {'nb_streamlines': 0,
                                          'streamlines_indices': set()}

    # TODO probably not needed
    # already_assigned_streamlines_idx = set()

    # Need to bookkeep because we chunk for big datasets
    processed_strl_count = 0
    chunk_size = len(streamlines)
    chunk_it = 0

    # nb_bundles = len(ref_bundles)
    # bundles_found = [False] * nb_bundles
    #bundles_potential_VCWP = [set()] * nb_bundles

    logging.debug("Starting scoring VCs")

    # Start loop here for big datasets
    while processed_strl_count < len(streamlines):
        if processed_strl_count > 0:
            raise NotImplementedError("Not supposed to have more than one chunk!")

        logging.debug("Starting chunk: {0}".format(chunk_it))

        strl_chunk = streamlines[chunk_it * chunk_size: (chunk_it + 1) * chunk_size]

        processed_strl_count += len(strl_chunk)

        # Already resample and run quickbundles on the submission chunk,
        # to avoid doing it at every call of auto_extract
        rstreamlines = set_number_of_points(nib.streamlines.ArraySequence(strl_chunk), NB_POINTS_RESAMPLE)

        # qb.cluster had problem with f8
        # rstreamlines = [s.astype('f4') for s in rstreamlines]

        # chunk_cluster_map = qb.cluster(rstreamlines)
        # chunk_cluster_map.refdata = strl_chunk

        # # Merge clusters
        # all_bundles = ClusterMapCentroid()
        # cluster_id_to_bundle_id = []
        # for bundle_idx, ref_bundle in enumerate(ref_bundles):
        #     clusters = ref_bundle["cluster_map"]
        #     cluster_id_to_bundle_id.extend([bundle_idx] * len(clusters))
        #     all_bundles.add_cluster(*clusters)

        # logging.debug("Starting VC identification through auto_extract")
        # qb = QuickBundles(threshold=10, metric=AveragePointwiseEuclideanMetric())
        # closest_bundles = qb.find_closest(all_bundles, rstreamlines, threshold=7)

        # print("Unassigned streamlines: {}".format(np.sum(closest_bundles == -1)))

        # for cluster_id, bundle_id in enumerate(cluster_id_to_bundle_id):
        #     indices = np.where(closest_bundles == cluster_id)[0]
        #     print("{}/{} ({}) Found {}".format(cluster_id, len(cluster_id_to_bundle_id), ref_bundles[bundle_id]['name'], len(indices)))
        #     if len(indices) == 0:
        #         continue

        #     vb_info = found_vbs_info.get(ref_bundles[bundle_id]['name'])
        #     indices = set(indices)
        #     vb_info['nb_streamlines'] += len(indices)
        #     vb_info['streamlines_indices'] |= indices
        #     VC_idx |= indices

        qb = QuickBundles(threshold=10, metric=AveragePointwiseEuclideanMetric())
        ordering = np.arange(len(rstreamlines))
        logging.debug("Starting VC identification through auto_extract")
        for bundle_idx, ref_bundle in enumerate(ref_bundles):
            print(ref_bundle['name'], ref_bundle['threshold'], len(ref_bundle['cluster_map']))
            # The selected indices are from [0, len(strl_chunk)]
            # selected_streamlines_indices = auto_extract(ref_bundle['cluster_map'],
            #                                             rstreamlines,
            #                                             clean_thr=ref_bundle['threshold'],
            #                                             ordering=ordering)

            closest_bundles = qb.find_closest(ref_bundle['cluster_map'], rstreamlines[ordering], ref_bundle['threshold'])
            selected_streamlines_indices = ordering[closest_bundles >= 0]
            ordering = ordering[closest_bundles == -1]

            # Remove duplicates, when streamlines are assigned to multiple VBs.
            # TODO better handling of this case
            # selected_streamlines_indices = set(selected_streamlines_indices) - cur_chunk_VC_idx
            # cur_chunk_VC_idx |= selected_streamlines_indices

            nb_selected_streamlines = len(selected_streamlines_indices)
            print("{} assigned".format(nb_selected_streamlines))

            if nb_selected_streamlines:
                # bundles_found[bundle_idx] = True
                # VC += nb_selected_streamlines

                # Shift indices to match the real number of streamlines
                global_select_strl_indices = set([v + chunk_it * chunk_size
                                                 for v in selected_streamlines_indices])
                vb_info = found_vbs_info.get(ref_bundle['name'])
                vb_info['nb_streamlines'] += nb_selected_streamlines
                vb_info['streamlines_indices'] |= global_select_strl_indices

                VC_idx |= global_select_strl_indices
                # already_assigned_streamlines_idx |= global_select_strl_indices

        chunk_it += 1

    return VC_idx, found_vbs_info

from dipy.segment.metric import (AveragePointwiseEuclideanMetric,
                                 ResampleFeature)
from dipy.segment.clustering import QuickBundles

feature = ResampleFeature(nb_points=100)
metric = AveragePointwiseEuclideanMetric(feature)

"""
Since we are going to include all of the streamlines in the single cluster
from the streamlines, we set the threshold to `np.inf`. We pull out the
centroid as the standard.
"""

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.
"""
Beispiel #48
0
def slr_with_qb(static, moving,
                x0='affine',
                rm_small_clusters=50,
                maxiter=100,
                select_random=None,
                verbose=False,
                greater_than=50,
                less_than=250,
                qb_thr=15,
                nb_pts=20,
                progressive=True, num_threads=None):
    """ Utility function for registering large tractograms.

    For efficiency we apply the registration on cluster centroids and remove
    small clusters.

    Parameters
    ----------
    static : Streamlines
    moving : Streamlines
    x0 : str
        rigid, similarity or affine transformation model (default affine)

    rm_small_clusters : int
        Remove clusters that have less than `rm_small_clusters` (default 50)

    verbose : bool,
        If True then information about the optimization is shown.

    select_random : int
        If not None select a random number of streamlines to apply clustering
        Default None.

    options : None or dict,
        Extra options to be used with the selected method.

    num_threads : int
        Number of threads. If None (default) then all available threads
        will be used. Only metrics using OpenMP will use this variable.

    Notes
    -----
    The order of operations is the following. First short or long streamlines
    are removed. Second the tractogram or a random selection of the tractogram
    is clustered with QuickBundles. Then SLR [Garyfallidis15]_ is applied.

    References
    ----------
    .. [Garyfallidis15] Garyfallidis et al. "Robust and efficient linear
            registration of white-matter fascicles in the space of streamlines"
            , NeuroImage, 117, 124--140, 2015
    .. [Garyfallidis14] Garyfallidis et al., "Direct native-space fiber
            bundle alignment for group comparisons", ISMRM, 2014.
    .. [Garyfallidis17] Garyfallidis et al. Recognition of white matter
            bundles using local and global streamline-based registration and
            clustering, Neuroimage, 2017.
    """
    if verbose:
        print('Static streamlines size {}'.format(len(static)))
        print('Moving streamlines size {}'.format(len(moving)))

    def check_range(streamline, gt=greater_than, lt=less_than):

        if (length(streamline) > gt) & (length(streamline) < lt):
            return True
        else:
            return False

    # TODO change this to the new Streamlines API
    streamlines1 = [s for s in static if check_range(s)]
    streamlines2 = [s for s in moving if check_range(s)]

    if verbose:

        print('Static streamlines after length reduction {}'
              .format(len(streamlines1)))
        print('Moving streamlines after length reduction {}'
              .format(len(streamlines2)))

    if select_random is not None:
        rstreamlines1 = select_random_set_of_streamlines(streamlines1,
                                                         select_random)
    else:
        rstreamlines1 = streamlines1

    rstreamlines1 = set_number_of_points(rstreamlines1, nb_pts)
    qb1 = QuickBundles(threshold=qb_thr)
    rstreamlines1 = [s.astype('f4') for s in rstreamlines1]
    cluster_map1 = qb1.cluster(rstreamlines1)
    clusters1 = remove_clusters_by_size(cluster_map1, rm_small_clusters)
    qb_centroids1 = [cluster.centroid for cluster in clusters1]

    if select_random is not None:
        rstreamlines2 = select_random_set_of_streamlines(streamlines2,
                                                         select_random)
    else:
        rstreamlines2 = streamlines2

    rstreamlines2 = set_number_of_points(rstreamlines2, nb_pts)
    qb2 = QuickBundles(threshold=qb_thr)
    rstreamlines2 = [s.astype('f4') for s in rstreamlines2]
    cluster_map2 = qb2.cluster(rstreamlines2)
    clusters2 = remove_clusters_by_size(cluster_map2, rm_small_clusters)
    qb_centroids2 = [cluster.centroid for cluster in clusters2]

    if verbose:
        t = time()

    if not progressive:
        slr = StreamlineLinearRegistration(x0=x0,
                                           options={'maxiter': maxiter},
                                           num_threads=num_threads)
        slm = slr.optimize(qb_centroids1, qb_centroids2)
    else:
        bounds = DEFAULT_BOUNDS

        slm = progressive_slr(qb_centroids1, qb_centroids2,
                              x0=x0, metric=None,
                              bounds=bounds, num_threads=num_threads)

    if verbose:
        print('QB static centroids size %d' % len(qb_centroids1,))
        print('QB moving centroids size %d' % len(qb_centroids2,))
        duration = time() - t
        print('SLR finished in  %0.3f seconds.' % (duration,))
        if slm.iterations is not None:
            print('SLR iterations: %d ' % (slm.iterations,))

    moved = slm.transform(moving)

    return moved, slm.matrix, qb_centroids1, qb_centroids2