def test_bundles_distances_mdf(): xyz1A = np.array([[0,0,0],[1,0,0],[2,0,0]],dtype='float32') xyz2A = np.array([[0,1,1],[1,0,1],[2,3,-2]],dtype='float32') xyz1B = np.array([[-1,0,0],[2,0,0],[2,3,0]],dtype='float32') tracksA = [xyz1A,xyz2A] tracksB = [xyz1B, xyz1A, xyz2A] DM2 = pf.bundles_distances_mdf(tracksA, tracksB)
def count_close_tracks(sla, slb, dist_thr=20): cnt_a_close = np.zeros(len(slb)) for ta in sla: dta = bundles_distances_mdf([ta], slb)[0] # dta = bundles_distances_mam([ta],slb)[0] cnt_a_close += binarise(dta, dist_thr) return cnt_a_close
def show_coverage(C1,C2): vs1,ls1,tot1=bring_virtuals(C1) vs2,ls2,tot2=bring_virtuals(C2) d12=bundles_distances_mdf(vs1,vs2) nfa,nfb = nearest_fraction(d12,4.) cfa,cfb = cover_fraction(d12,ls1,ls2,4.,1,1) print "nf %6.1f %6.1f cf %6.1f %6.1f" % (100*nfa,100*nfb,100*cfa,100*cfb) return d12
def _reduce_search_space(self, model_centroids, reduction_thr=20, reduction_distance='mdf'): if self.verbose: t = time() print('# Reduce search space') print(' Reduction threshold %0.3f' % (reduction_thr,)) print(' Reduction distance {}'.format(reduction_distance)) if reduction_distance.lower() == 'mdf': if self.verbose: print(' Using MDF') centroid_matrix = bundles_distances_mdf(model_centroids, self.centroids) elif reduction_distance.lower() == 'mam': if self.verbose: print(' Using MAM') centroid_matrix = bundles_distances_mdf(model_centroids, self.centroids) else: raise ValueError('Given reduction distance not known') centroid_matrix[centroid_matrix > reduction_thr] = np.inf mins = np.min(centroid_matrix, axis=0) close_clusters_indices = list(np.where(mins != np.inf)[0]) close_clusters = self.cluster_map[close_clusters_indices] neighb_indices = [cluster.indices for cluster in close_clusters] neighb_streamlines = Streamlines(chain(*close_clusters)) nb_neighb_streamlines = len(neighb_streamlines) if nb_neighb_streamlines == 0: print(' You have no neighbor streamlines... No bundle recognition') return Streamlines([]), [] if self.verbose: print(' Number of neighbor streamlines %d' % (nb_neighb_streamlines,)) print(' Duration %0.3f sec. \n' % (time() - t,)) return neighb_streamlines, neighb_indices
def auto_extract(model_cluster_map, submission_cluster_map, number_pts_per_str=NB_POINTS_RESAMPLE, close_centroids_thr=20, clean_thr=7.): model_centroids = model_cluster_map.centroids centroid_matrix = bundles_distances_mdf(model_centroids, submission_cluster_map.centroids) centroid_matrix[centroid_matrix > close_centroids_thr] = np.inf mins = np.min(centroid_matrix, axis=0) close_clusters = [submission_cluster_map[i] for i in np.where(mins != np.inf)[0]] close_indices_inter = [submission_cluster_map[i].indices for i in np.where(mins != np.inf)[0]] close_indices = list(chain.from_iterable(close_indices_inter)) close_streamlines = list(chain(*close_clusters)) closer_streamlines = close_streamlines rcloser_streamlines = set_number_of_points(closer_streamlines, number_pts_per_str) clean_matrix = bundles_distances_mdf(model_cluster_map.refdata, rcloser_streamlines) clean_matrix[clean_matrix > clean_thr] = np.inf mins = np.min(clean_matrix, axis=0) clean_indices = [i for i in np.where(mins != np.inf)[0]] # Clean indices refer to the streamlines in closer_streamlines, # which are the same as the close_streamlines. Each close_streamline # has a related element in close_indices, for which the value # is the index of the original streamline in the moved_streamlines. final_selected_indices = [close_indices[idx] for idx in clean_indices] return final_selected_indices
def test_bundles_distances_mdf(): xyz1A = np.array([[0,0,0],[1,0,0],[2,0,0]],dtype='float32') xyz2A = np.array([[0,1,1],[1,0,1],[2,3,-2]],dtype='float32') xyz3A = np.array([[0,0,0],[1,0,0],[3,0,0]],dtype='float32') xyz1B = np.array([[-1,0,0],[2,0,0],[2,3,0]],dtype='float32') tracksA = [xyz1A,xyz2A] tracksB = [xyz1B, xyz1A, xyz2A] DM2 = pf.bundles_distances_mdf(tracksA, tracksB) tracksA = [xyz1A,xyz1A] tracksB = [xyz1A,xyz1A] DM2 = pf.bundles_distances_mdf(tracksA, tracksB) assert_array_almost_equal(DM2,np.zeros((2,2))) tracksA = [xyz1A,xyz3A] tracksB = [xyz2A] DM2 = pf.bundles_distances_mdf(tracksA, tracksB) print(DM2) #assert_array_almost_equal(DM2,np.zeros((2,2))) DM=np.zeros(DM2.shape) for (a,ta) in enumerate(tracksA): for (b,tb) in enumerate(tracksB): md=np.sum(np.sqrt(np.sum((ta-tb)**2,axis=1)))/3. md2=np.sum(np.sqrt(np.sum((ta-tb[::-1])**2,axis=1)))/3. DM[a,b]=np.min((md,md2)) print(DM) print('--------------') for t in tracksA: print(t) print('--------------') for t in tracksB: print(t) assert_array_almost_equal(DM,DM2,4)
def exemplars(self,tracks=None): if self.exemps==None: self.exemps=[] self.exempsi=[] C=self.clustering if tracks==None: tracks=self.tracksd for c in C: cluster=[tracks[i] for i in C[c]['indices']] D=bundles_distances_mdf([C[c]['hidden']/float(C[c]['N'])],cluster) D=D.ravel() si=np.argmin(D) self.exempsi.append(si) self.exemps.append(cluster[si]) return self.exemps, self.exempsi
def find_matches(): fsolid='/home/ian/Data/LSC_stability/solid_1M.npy' T=np.load(fsolid) samplesize = 10**3 lscdist = 4. labels1 = np.arange(0*samplesize,1*samplesize) T1=T[labels1] C1=local_skeleton_clustering(T1,lscdist) labels2 = np.arange(1*samplesize,2*samplesize) T2=T[labels2] C2=local_skeleton_clustering(T2,lscdist) v1,l1,tot1 = bring_virtuals(C1) v2,l2,tot2 = bring_virtuals(C2) d12 = bundles_distances_mdf(v1,v2) mv21 = np.argmin(d12,axis=0) print mv21[0], C2[0]['indices'], C1[mv21[0]]['indices']
def bundle_adjacency(dtracks0, dtracks1, threshold): """ Find bundle adjacency between two given tracks/bundles Parameters ---------- dtracks0 : Streamlines dtracks1 : Streamlines threshold: float References ---------- .. [Garyfallidis12] Garyfallidis E. et al., QuickBundles a method for tractography simplification, Frontiers in Neuroscience, vol 6, no 175, 2012. """ d01 = bundles_distances_mdf(dtracks0, dtracks1) pair12 = [] for i in range(len(dtracks0)): if np.min(d01[i, :]) < threshold: j = np.argmin(d01[i, :]) pair12.append((i, j)) pair12 = np.array(pair12) pair21 = [] # solo2 = [] for i in range(len(dtracks1)): if np.min(d01[:, i]) < threshold: j = np.argmin(d01[:, i]) pair21.append((i, j)) pair21 = np.array(pair21) A = len(pair12) / np.float(len(dtracks0)) B = len(pair21) / np.float(len(dtracks1)) res = 0.5 * (A + B) return res
def _prune_what_not_in_model(self, model_centroids, transf_streamlines, neighb_indices, mdf_thr=5, pruning_thr=10, pruning_distance='mdf'): if pruning_thr < 0: print('Pruning_thr has to be greater or equal to 0') if self.verbose: print('# Prune streamlines using the MDF distance') print(' Pruning threshold %0.3f' % (pruning_thr,)) print(' Pruning distance {}'.format(pruning_distance)) t = time() thresholds = [40, 30, 20, 10, mdf_thr] rtransf_cluster_map = qbx_and_merge(transf_streamlines, thresholds, nb_pts=20, select_randomly=500000, rng=self.rng, verbose=self.verbose) if self.verbose: print(' QB Duration %0.3f sec. \n' % (time() - t, )) rtransf_centroids = rtransf_cluster_map.centroids if pruning_distance.lower() == 'mdf': if self.verbose: print(' Using MDF') dist_matrix = bundles_distances_mdf(model_centroids, rtransf_centroids) elif pruning_distance.lower() == 'mam': if self.verbose: print(' Using MAM') dist_matrix = bundles_distances_mam(model_centroids, rtransf_centroids) else: raise ValueError('Given pruning distance is not available') dist_matrix[np.isnan(dist_matrix)] = np.inf dist_matrix[dist_matrix > pruning_thr] = np.inf pruning_matrix = dist_matrix.copy() if self.verbose: print(' Pruning matrix size is (%d, %d)' % pruning_matrix.shape) mins = np.min(pruning_matrix, axis=0) pruned_indices = [rtransf_cluster_map[i].indices for i in np.where(mins != np.inf)[0]] pruned_indices = list(chain(*pruned_indices)) pruned_streamlines = transf_streamlines[np.array(pruned_indices)] initial_indices = list(chain(*neighb_indices)) final_indices = [initial_indices[i] for i in pruned_indices] labels = final_indices if self.verbose: msg = ' Number of centroids: %d' print(msg % (len(rtransf_centroids),)) msg = ' Number of streamlines after pruning: %d' print(msg % (len(pruned_streamlines),)) if len(pruned_streamlines) == 0: print(' You have removed all streamlines') return Streamlines([]), [] if self.verbose: print(' Duration %0.3f sec. \n' % (time() - t, )) return pruned_streamlines, labels
def _prune_what_not_in_model(self, model_centroids, transf_streamlines, neighb_indices, mdf_thr=5, pruning_thr=10, pruning_distance='mdf'): if self.verbose: if pruning_thr < 0: logger.info('Pruning_thr has to be greater or equal to 0') logger.info('# Prune streamlines using the MDF distance') logger.info(' Pruning threshold %0.3f' % (pruning_thr, )) logger.info(' Pruning distance {}'.format(pruning_distance)) t = time() thresholds = [40, 30, 20, 10, mdf_thr] rtransf_cluster_map = qbx_and_merge(transf_streamlines, thresholds, nb_pts=20, select_randomly=500000, rng=self.rng) if self.verbose: logger.info(' QB Duration %0.3f sec. \n' % (time() - t, )) rtransf_centroids = rtransf_cluster_map.centroids if pruning_distance.lower() == 'mdf': if self.verbose: logger.info(' Using MDF') dist_matrix = bundles_distances_mdf(model_centroids, rtransf_centroids) elif pruning_distance.lower() == 'mam': if self.verbose: logger.info(' Using MAM') dist_matrix = bundles_distances_mam(model_centroids, rtransf_centroids) else: raise ValueError('Given pruning distance is not available') dist_matrix[np.isnan(dist_matrix)] = np.inf dist_matrix[dist_matrix > pruning_thr] = np.inf pruning_matrix = dist_matrix.copy() if self.verbose: logger.info(' Pruning matrix size is (%d, %d)' % pruning_matrix.shape) mins = np.min(pruning_matrix, axis=0) pruned_indices = [ rtransf_cluster_map[i].indices for i in np.where(mins != np.inf)[0] ] pruned_indices = list(chain(*pruned_indices)) idx = np.array(pruned_indices) if len(idx) == 0: if self.verbose: logger.info(' You have removed all streamlines') return Streamlines([]), [] pruned_streamlines = transf_streamlines[idx] initial_indices = list(chain(*neighb_indices)) final_indices = [initial_indices[i] for i in pruned_indices] labels = final_indices if self.verbose: msg = ' Number of centroids: %d' logger.info(msg % (len(rtransf_centroids), )) msg = ' Number of streamlines after pruning: %d' logger.info(msg % (len(pruned_streamlines), )) logger.info(' Duration %0.3f sec. \n' % (time() - t, )) return pruned_streamlines, labels
def cluster_confidence(streamlines, max_mdf=5, subsample=12, power=1, override=False): """ Computes the cluster confidence index (cci), which is an estimation of the support a set of streamlines gives to a particular pathway. Ex: A single streamline with no others in the dataset following a similar pathway has a low cci. A streamline in a bundle of 100 streamlines that follow similar pathways has a high cci. See: Jordan et al. 2017 (Based on streamline MDF distance from Garyfallidis et al. 2012) Parameters ---------- streamlines : list of 2D (N, 3) arrays A sequence of streamlines of length N (# streamlines) max_mdf : int The maximum MDF distance (mm) that will be considered a "supporting" streamline and included in cci calculation subsample: int The number of points that are considered for each streamline in the calculation. To save on calculation time, each streamline is subsampled to subsampleN points. power: int The power to which the MDF distance for each streamline will be raised to determine how much it contributes to the cci. High values of power make the contribution value degrade much faster. E.g., a streamline with 5mm MDF similarity contributes 1/5 to the cci if power is 1, but only contributes 1/5^2 = 1/25 if power is 2. override: bool, False by default override means that the cci calculation will still occur even though there are short streamlines in the dataset that may alter expected behaviour. Returns ------- Returns an array of CCI scores References ---------- [Jordan17] Jordan K. Et al., Cluster Confidence Index: A Streamline-Wise Pathway Reproducibility Metric for Diffusion-Weighted MRI Tractography, Journal of Neuroimaging, vol 28, no 1, 2017. [Garyfallidis12] Garyfallidis E. et al., QuickBundles a method for tractography simplification, Frontiers in Neuroscience, vol 6, no 175, 2012. """ # error if any streamlines are shorter than 20mm lengths = list(length(streamlines)) if min(lengths) < 20 and not override: raise ValueError('Short streamlines found. We recommend removing them.' ' To continue without removing short streamlines set' ' override=True') # calculate the pairwise MDF distance between all streamlines in dataset subsamp_sls = set_number_of_points(streamlines, subsample) cci_score_mtrx = np.zeros([len(subsamp_sls)]) for i, sl in enumerate(subsamp_sls): mdf_mx = bundles_distances_mdf([subsamp_sls[i]], subsamp_sls) if (mdf_mx == 0).sum() > 1: raise ValueError('Identical streamlines. CCI calculation invalid') mdf_mx_oi = (mdf_mx > 0) & (mdf_mx < max_mdf) & ~np.isnan(mdf_mx) mdf_mx_oi_only = mdf_mx[mdf_mx_oi] cci_score = np.sum(np.divide(1, np.power(mdf_mx_oi_only, power))) cci_score_mtrx[i] = cci_score return cci_score_mtrx
def compute_terminal_points_matrix(S_A, S_B): from dipy.tracking.streamline import set_number_of_points S_A_res = np.array([set_number_of_points(s, nb_points=2) for s in S_A]) S_B_res = np.array([set_number_of_points(s, nb_points=2) for s in S_B]) return 2.0 * bundles_distances_mdf(S_A_res, S_B_res)
def cluster_confidence(streamlines, max_mdf=5, subsample=12, power=1, override=False): """ Computes the cluster confidence index (cci), which is an estimation of the support a set of streamlines gives to a particular pathway. Ex: A single streamline with no others in the dataset following a similar pathway has a low cci. A streamline in a bundle of 100 streamlines that follow similar pathways has a high cci. See: Jordan et al. 2017 (Based on streamline MDF distance from Garyfallidis et al. 2012) Parameters ---------- streamlines : list of 2D (N, 3) arrays A sequence of streamlines of length N (# streamlines) max_mdf : int The maximum MDF distance (mm) that will be considered a "supporting" streamline and included in cci calculation subsample: int The number of points that are considered for each streamline in the calculation. To save on calculation time, each streamline is subsampled to subsampleN points. power: int The power to which the MDF distance for each streamline will be raised to determine how much it contributes to the cci. High values of power make the contribution value degrade much faster. Example: a streamline with 5mm MDF similarity contributes 1/5 to the cci if power is 1, but only contributes 1/5^2 = 1/25 if power is 2. override: bool, False by default override means that the cci calculation will still occur even though there are short streamlines in the dataset that may alter expected behaviour. Returns ------- Returns an array of CCI scores References ---------- [Jordan17] Jordan K. Et al., Cluster Confidence Index: A Streamline-Wise Pathway Reproducibility Metric for Diffusion-Weighted MRI Tractography, Journal of Neuroimaging, vol 28, no 1, 2017. [Garyfallidis12] Garyfallidis E. et al., QuickBundles a method for tractography simplification, Frontiers in Neuroscience, vol 6, no 175, 2012. """ # error if any streamlines are shorter than 20mm lengths = list(length(streamlines)) if min(lengths) < 20 and not override: raise ValueError('Short streamlines found. We recommend removing them.' ' To continue without removing short streamlines set' ' override=True') # calculate the pairwise MDF distance between all streamlines in dataset subsamp_sls = set_number_of_points(streamlines, subsample) cci_score_mtrx = np.zeros([len(subsamp_sls)]) for i, sl in enumerate(subsamp_sls): mdf_mx = bundles_distances_mdf([subsamp_sls[i]], subsamp_sls) if (mdf_mx == 0).sum() > 1: raise ValueError('Identical streamlines. CCI calculation invalid') mdf_mx_oi = (mdf_mx > 0) & (mdf_mx < max_mdf) & ~ np.isnan(mdf_mx) mdf_mx_oi_only = mdf_mx[mdf_mx_oi] cci_score = np.sum(np.divide(1, np.power(mdf_mx_oi_only, power))) cci_score_mtrx[i] = cci_score return cci_score_mtrx
def compute_bundle_adjacency_streamlines(bundle_1, bundle_2, non_overlap=False, centroids_1=None, centroids_2=None): """ Compute the distance in millimeters between two bundles. Uses centroids to limit computation time. Each centroid of the first bundle is matched to the nearest centroid of the second bundle and vice-versa. Distance between matched paired is averaged for the final results. References ---------- .. [Garyfallidis15] Garyfallidis et al. Robust and efficient linear registration of white-matter fascicles in the space of streamlines, Neuroimage, 2015. Parameters ---------- bundle_1: list of ndarray First set of streamlines. bundle_2: list of ndarray Second set of streamlines. non_overlap: bool Exclude overlapping streamlines from the computation. centroids_1: list of ndarray Pre-computed centroids for the first bundle. centroids_2: list of ndarray Pre-computed centroids for the second bundle. Returns ------- float: Distance in millimeters between both bundles. """ if not bundle_1 or not bundle_2: return -1 thresholds = [32, 24, 12, 6] # Intialize the clusters if centroids_1 is None: centroids_1 = qbx_and_merge(bundle_1, thresholds, rng=RandomState(0), verbose=False).centroids if centroids_2 is None: centroids_2 = qbx_and_merge(bundle_2, thresholds, rng=RandomState(0), verbose=False).centroids if non_overlap: non_overlap_1, _ = perform_streamlines_operation(difference, [bundle_1, bundle_2], precision=0) non_overlap_2, _ = perform_streamlines_operation(difference, [bundle_2, bundle_1], precision=0) if non_overlap_1: non_overlap_centroids_1 = qbx_and_merge(non_overlap_1, thresholds, rng=RandomState(0), verbose=False).centroids distance_matrix_1 = bundles_distances_mdf(non_overlap_centroids_1, centroids_2) min_b1 = np.min(distance_matrix_1, axis=0) distance_b1 = np.average(min_b1) else: distance_b1 = 0 if non_overlap_2: non_overlap_centroids_2 = qbx_and_merge(non_overlap_2, thresholds, rng=RandomState(0), verbose=False).centroids distance_matrix_2 = bundles_distances_mdf(centroids_1, non_overlap_centroids_2) min_b2 = np.min(distance_matrix_2, axis=1) distance_b2 = np.average(min_b2) else: distance_b2 = 0 else: distance_matrix = bundles_distances_mdf(centroids_1, centroids_2) min_b1 = np.min(distance_matrix, axis=0) min_b2 = np.min(distance_matrix, axis=1) distance_b1 = np.average(min_b1) distance_b2 = np.average(min_b2) return (distance_b1 + distance_b2) / 2.0
def save_distances(vs1,vs2,filename='d12.npy'): print 'making distances ...' d12 = bundles_distances_mdf(vs1,vs2) #save_pickle('d12.skl',d12) np.save(filename,d12) print 'distances pickled ...' return d12