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
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
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)
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"))
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
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: """