def bundle_sum_distance(t, static, moving, num_threads=None): """ MDF distance optimization function (SUM) We minimize the distance between moving streamlines as they align with the static streamlines. Parameters ----------- t : ndarray t is a vector of affine transformation parameters with size at least 6. If the size is 6, t is interpreted as translation + rotation. If the size is 7, t is interpreted as translation + rotation + isotropic scaling. If size is 12, t is interpreted as translation + rotation + scaling + shearing. static : list Static streamlines moving : list Moving streamlines. These will be transformed to align with the static streamlines Returns ------- cost: float """ aff = compose_matrix44(t) moving = transform_streamlines(moving, aff) d01 = distance_matrix_mdf(static, moving) return np.sum(d01)
def bundle_sum_distance(t, static, moving, num_threads=None): """ MDF distance optimization function (SUM) We minimize the distance between moving streamlines as they align with the static streamlines. Parameters ----------- t : ndarray t is a vector of of affine transformation parameters with size at least 6. If size is 6, t is interpreted as translation + rotation. If size is 7, t is interpreted as translation + rotation + isotropic scaling. If size is 12, t is interpreted as translation + rotation + scaling + shearing. static : list Static streamlines moving : list Moving streamlines. These will be transform to align with the static streamlines Returns ------- cost: float """ aff = compose_matrix44(t) moving = transform_streamlines(moving, aff) d01 = distance_matrix_mdf(static, moving) return np.sum(d01)
def bundle_min_distance(t, static, moving): """ MDF-based pairwise distance optimization function (MIN). We minimize the distance between moving streamlines as they align with the static streamlines. Parameters ---------- t : ndarray t is a vector of affine transformation parameters with size at least 6. If size is 6, t is interpreted as translation + rotation. If size is 7, t is interpreted as translation + rotation + isotropic scaling. If size is 12, t is interpreted as translation + rotation + scaling + shearing. static : list Static streamlines moving : list Moving streamlines. Returns ------- cost: float """ aff = compose_matrix44(t) moving = transform_streamlines(moving, aff) d01 = distance_matrix_mdf(static, moving) rows, cols = d01.shape return 0.25 * (np.sum(np.min(d01, axis=0)) / float(cols) + np.sum(np.min(d01, axis=1)) / float(rows))**2
def bundle_min_distance(t, static, moving): """ MDF-based pairwise distance optimization function (MIN) We minimize the distance between moving streamlines as they align with the static streamlines. Parameters ----------- t : ndarray t is a vector of of affine transformation parameters with size at least 6. If size is 6, t is interpreted as translation + rotation. If size is 7, t is interpreted as translation + rotation + isotropic scaling. If size is 12, t is interpreted as translation + rotation + scaling + shearing. static : list Static streamlines moving : list Moving streamlines. Returns ------- cost: float """ aff = compose_matrix44(t) moving = transform_streamlines(moving, aff) d01 = distance_matrix_mdf(static, moving) rows, cols = d01.shape return 0.25 * (np.sum(np.min(d01, axis=0)) / float(cols) + np.sum(np.min(d01, axis=1)) / float(rows)) ** 2
def bundles_distances_endpoints_fastest(S_A, S_B): """Distance between lists/arrays or streamlines, based on endpoints. Returns the distance matrix between the related groups streamlines. Fastest implementation based on distance_matrix_mdf(). """ tmp_S_A = np.array([[s_A[0], s_A[-1]] for s_A in S_A]) tmp_S_B = np.array([[s_B[0], s_B[-1]] for s_B in S_B]) return 2.0 * distance_matrix_mdf(tmp_S_A, tmp_S_B)
def remove_similar_streamlines(streamlines, threshold=5): """ Remove similar streamlines, shuffling streamlines will impact the results. Only provide a small set of streamlines (below 2000 if possible). Parameters ---------- streamlines : list of numpy.ndarray Input streamlines to remove duplicates from. threshold : float Distance threshold to consider two streamlines similar, in mm. Returns ------- streamlines : list of numpy.ndarray """ if len(streamlines) == 1: return streamlines sample_20_streamlines = set_number_of_points(streamlines, 20) distance_matrix = distance_matrix_mdf(sample_20_streamlines, sample_20_streamlines) current_indice = 0 while True: sim_indices = np.where(distance_matrix[current_indice] < threshold)[0] pop_count = 0 # Every streamlines similar to yourself (excluding yourself) # should be deleted from the set of desired streamlines for ind in sim_indices: if not current_indice == ind: streamlines.pop(ind - pop_count) distance_matrix = np.delete(distance_matrix, ind - pop_count, axis=0) distance_matrix = np.delete(distance_matrix, ind - pop_count, axis=1) pop_count += 1 current_indice += 1 # Once you reach the end of the remaining streamlines if current_indice >= len(distance_matrix): break return streamlines
def remove_similar_streamlines(streamlines, removal_distance=2.): """ Computes a distance matrix using all streamlines, then removes streamlines closer than `removal_distance`. Parameters ----------- streamlines : `ArraySequence` object or list of 3D arrays Streamlines to downsample removal_distance : float Distance for which streamlines are considered 'similar' and should be removed Returns ------- `ArraySequence` object Downsampled streamlines """ # Simple trick to make it faster than using 40-60 points sample_10_streamlines = set_number_of_points(streamlines, 10) distance_matrix = distance_matrix_mdf(sample_10_streamlines, sample_10_streamlines) current_id = 0 while True: indices = np.where(distance_matrix[current_id] < removal_distance)[0] it = 0 if len(indices) > 1: for k in indices: # Every streamlines similar to yourself (excluding yourself) # should be deleted from the set of desired streamlines if not current_id == k: streamlines.pop(k - it) distance_matrix = np.delete(distance_matrix, k - it, axis=0) distance_matrix = np.delete(distance_matrix, k - it, axis=1) it += 1 current_id += 1 # Once you reach the end of the remaining streamlines if current_id >= len(streamlines): break return streamlines
def test_efficient_bmd(): a = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]]) streamlines = [a, a + 2, a + 4] points, offsets = unlist_streamlines(streamlines) points = points.astype(np.double) points2 = points.copy() D = np.zeros((len(offsets), len(offsets)), dtype='f8') _bundle_minimum_distance_matrix(points, points2, len(offsets), len(offsets), a.shape[0], D) assert_equal(np.sum(np.diag(D)), 0) points2 += 2 _bundle_minimum_distance_matrix(points, points2, len(offsets), len(offsets), a.shape[0], D) streamlines2 = relist_streamlines(points2, offsets) D2 = distance_matrix_mdf(streamlines, streamlines2) assert_array_almost_equal(D, D2) cols = D2.shape[1] rows = D2.shape[0] dist = 0.25 * (np.sum(np.min(D2, axis=0)) / float(cols) + np.sum(np.min(D2, axis=1)) / float(rows)) ** 2 dist2 = _bundle_minimum_distance(points, points2, len(offsets), len(offsets), a.shape[0]) assert_almost_equal(dist, dist2)
def remove_similar_streamlines(streamlines, threshold=5, do_avg=False): """ Remove similar streamlines, shuffling streamlines will impact the results. Only provide a small set of streamlines (below 2000 if possible). Parameters ---------- streamlines : list of numpy.ndarray Input streamlines to remove duplicates from. threshold : float Distance threshold to consider two streamlines similar, in mm. do_avg : bool Instead of removing similar streamlines, average all similar streamlines as a single smoother streamline. Returns ------- streamlines : list of numpy.ndarray """ if len(streamlines) == 1: return streamlines sample_20_streamlines = set_number_of_points(streamlines, 20) distance_matrix = distance_matrix_mdf(sample_20_streamlines, sample_20_streamlines) current_indice = 0 avg_streamlines = [] while True: sim_indices = np.where(distance_matrix[current_indice] < threshold)[0] pop_count = 0 if do_avg: avg_streamline_list = [] # Every streamlines similar to yourself (excluding yourself) # should be deleted from the set of desired streamlines for ind in sim_indices: if not current_indice == ind: streamlines.pop(ind-pop_count) distance_matrix = np.delete(distance_matrix, ind-pop_count, axis=0) distance_matrix = np.delete(distance_matrix, ind-pop_count, axis=1) pop_count += 1 if do_avg: kicked_out = sample_20_streamlines[ind] avg_streamline_list.append(kicked_out) if do_avg: if len(avg_streamline_list) > 1: metric = AveragePointwiseEuclideanMetric() qb = QuickBundles(threshold=100, metric=metric) clusters = qb.cluster(avg_streamline_list) avg_streamlines.append(clusters.centroids[0]) else: avg_streamlines.append(avg_streamline_list[0]) current_indice += 1 # Once you reach the end of the remaining streamlines if current_indice >= len(distance_matrix): break if do_avg: return avg_streamlines else: return streamlines