def remove_loops_and_sharp_turns(streamlines, max_angle, use_qb=False, qb_threshold=15., qb_seed=0): """ Remove loops and sharp turns from a list of streamlines. Parameters ---------- streamlines: list of ndarray The list of streamlines from which to remove loops and sharp turns. max_angle: float Maximal winding angle a streamline can have before being classified as a loop. use_qb: bool Set to True if the additional QuickBundles pass is done. This will help remove sharp turns. Should only be used on bundled streamlines, not on whole-brain tractograms. qb_threshold: float Quickbundles distance threshold, only used if use_qb is True. qb_seed: int Seed to initialize randomness in QuickBundles Returns ------- list: the ids of clean streamlines Only the ids are returned so proper filtering can be done afterwards """ streamlines_clean = [] ids = [] for i, s in enumerate(streamlines): if tm.winding(s) < max_angle: ids.append(i) streamlines_clean.append(s) if use_qb: ids = [] if len(streamlines_clean) > 1: curvature = [] rng = np.random.RandomState(qb_seed) clusters = qbx_and_merge(streamlines_clean, [40, 30, 20, qb_threshold], rng=rng, verbose=False) for cc in clusters.centroids: curvature.append(tm.mean_curvature(cc)) mean_curvature = sum(curvature) / len(curvature) for i in range(len(clusters.centroids)): if tm.mean_curvature(clusters.centroids[i]) <= mean_curvature: ids.extend(clusters[i].indices) else: logging.debug("Impossible to use the use_qb option because " + "not more than one streamline left from the\n" + "input file.") return ids
def compute_mean_bundle_curvature(bundle, nb_points=200): """Compute the mean scalar curvature of a bundle using tm.mean(curvature). """ bundle_res = np.array( [set_number_of_points(st, nb_points=nb_points) for st in bundle]) mean_st_curvature = np.zeros(len(bundle_res)) for i, sa in enumerate(bundle_res): m = tm.mean_curvature(sa) mean_st_curvature[i] = m mean_bundle_curvature = np.mean(mean_st_curvature) return mean_bundle_curvature
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)
def compute_measures(filename_tuple): sft = load_tractogram(filename_tuple[0], filename_tuple[1]) _, dimensions, voxel_size, _ = sft.space_attributes nbr_streamlines = len(sft) if not nbr_streamlines: logging.warning('{} is empty'.format(filename_tuple[0])) return dict( zip([ 'volume', 'volume_endpoints', 'streamlines_count', 'avg_length', 'std_length', 'min_length', 'max_length', 'mean_curvature' ], [0, 0, 0, 0, 0, 0, 0, 0])) length_list = list(length(list(sft.streamlines))) length_avg = float(np.average(length_list)) length_std = float(np.std(length_list)) length_min = float(np.min(length_list)) length_max = float(np.max(length_list)) sft.to_vox() sft.to_corner() streamlines = sft.streamlines density = compute_tract_counts_map(streamlines, dimensions) endpoints_density = get_endpoints_density_map(streamlines, dimensions) curvature_list = np.zeros((nbr_streamlines, )) for i in range(nbr_streamlines): curvature_list[i] = mean_curvature(sft.streamlines[i]) return dict( zip([ 'volume', 'volume_endpoints', 'streamlines_count', 'avg_length', 'std_length', 'min_length', 'max_length', 'mean_curvature' ], [ np.count_nonzero(density) * np.product(voxel_size), np.count_nonzero(endpoints_density) * np.product(voxel_size), nbr_streamlines, length_avg, length_std, length_min, length_max, float(np.mean(curvature_list)) ]))
def remove_loops_and_sharp_turns(streamlines, max_angle, use_qb=False, qb_threshold=15., qb_seed=0): """ Remove loops and sharp turns from a list of streamlines. Parameters ---------- streamlines: list of ndarray The list of streamlines from which to remove loops and sharp turns. use_qb: bool Set to True if the additional QuickBundles pass is done. This will help remove sharp turns. Should only be used on bundled streamlines, not on whole-brain tractograms. max_angle: float Maximal winding angle a streamline can have before being classified as a loop. qb_threshold: float Quickbundles distance threshold, only used if use_qb is True. Returns ------- A tuple containing list of ndarray: the clean streamlines list of ndarray: the list of removed streamlines, if any """ loops = [] streamlines_clean = [] for s in streamlines: if tm.winding(s) >= max_angle: loops.append(s) else: streamlines_clean.append(s) if use_qb: if len(streamlines_clean) > 1: streamlines = streamlines_clean curvature = [] streamlines_clean = [] rng = np.random.RandomState(qb_seed) clusters = qbx_and_merge(streamlines, [40, 30, 20, qb_threshold], rng=rng, verbose=False) for cc in clusters.centroids: curvature.append(tm.mean_curvature(cc)) mean_curvature = sum(curvature)/len(curvature) for i in range(len(clusters.centroids)): if tm.mean_curvature(clusters.centroids[i]) > mean_curvature: for indice in clusters[i].indices: loops.append(streamlines[indice]) else: for indice in clusters[i].indices: streamlines_clean.append(streamlines[indice]) else: logging.debug("Impossible to use the use_qb option because " + "not more than one streamline left from the\n" + "input file.") return streamlines_clean, loops
def compute_measures(filename_tuple): sft = load_tractogram(filename_tuple[0], filename_tuple[1]) _, dimensions, voxel_size, _ = sft.space_attributes uniformize_bundle_sft(sft) nbr_streamlines = len(sft) if not nbr_streamlines: logging.warning('{} is empty'.format(filename_tuple[0])) return dict( zip([ 'volume', 'volume_endpoints', 'streamlines_count', 'avg_length', 'std_length', 'min_length', 'max_length', 'span', 'curl', 'diameter', 'elongation', 'surface_area', 'end_surface_area_head', 'end_surface_area_tail', 'radius_head', 'radius_tail', 'irregularity', 'irregularity_of_end_surface_head', 'irregularity_of_end_surface_tail', 'mean_curvature', 'fractal_dimension' ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])) streamline_cords = list(sft.streamlines) length_list = list(length(streamline_cords)) length_avg = float(np.average(length_list)) length_std = float(np.std(length_list)) length_min = float(np.min(length_list)) length_max = float(np.max(length_list)) sft.to_vox() sft.to_corner() streamlines = sft.streamlines density = compute_tract_counts_map(streamlines, dimensions) endpoints_density = get_endpoints_density_map(streamlines, dimensions) span_list = list(map(compute_span, streamline_cords)) span = float(np.average(span_list)) curl = length_avg / span volume = np.count_nonzero(density) * np.product(voxel_size) diameter = 2 * np.sqrt(volume / (np.pi * length_avg)) elon = length_avg / diameter roi = np.where(density != 0, 1, density) surf_area = approximate_surface_node(roi) * (voxel_size[0]**2) irregularity = surf_area / (np.pi * diameter * length_avg) endpoints_map_head, endpoints_map_tail = \ get_head_tail_density_maps(sft.streamlines, dimensions) endpoints_map_head_roi = \ np.where(endpoints_map_head != 0, 1, endpoints_map_head) endpoints_map_tail_roi = \ np.where(endpoints_map_tail != 0, 1, endpoints_map_tail) end_sur_area_head = \ approximate_surface_node(endpoints_map_head_roi) * (voxel_size[0] ** 2) end_sur_area_tail = \ approximate_surface_node(endpoints_map_tail_roi) * (voxel_size[0] ** 2) endpoints_coords_head = np.array(np.where(endpoints_map_head_roi)).T endpoints_coords_tail = np.array(np.where(endpoints_map_tail_roi)).T radius_head = 1.5 * np.average( np.sqrt(((endpoints_coords_head - np.average(endpoints_coords_head, axis=0))**2).sum(axis=1))) radius_tail = 1.5 * np.average( np.sqrt(((endpoints_coords_tail - np.average(endpoints_coords_tail, axis=0))**2).sum(axis=1))) end_irreg_head = (np.pi * radius_head**2) / end_sur_area_head end_irreg_tail = (np.pi * radius_tail**2) / end_sur_area_tail fractal_dimension = compute_fractal_dimension(density) curvature_list = np.zeros((nbr_streamlines, )) for i in range(nbr_streamlines): curvature_list[i] = mean_curvature(sft.streamlines[i]) return dict( zip([ 'volume', 'volume_endpoints', 'streamlines_count', 'avg_length', 'std_length', 'min_length', 'max_length', 'span', 'curl', 'diameter', 'elongation', 'surface_area', 'end_surface_area_head', 'end_surface_area_tail', 'radius_head', 'radius_tail', 'irregularity', 'irregularity_of_end_surface_head', 'irregularity_of_end_surface_tail', 'mean_curvature', 'fractal_dimension' ], [ volume, np.count_nonzero(endpoints_density) * np.product(voxel_size), nbr_streamlines, length_avg, length_std, length_min, length_max, span, curl, diameter, elon, surf_area, end_sur_area_head, end_sur_area_tail, radius_head, radius_tail, irregularity, end_irreg_head, end_irreg_tail, float(np.mean(curvature_list)), fractal_dimension ]))
def remove_loops_and_sharp_turns(streamlines, use_qb, max_angle, qb_threshold, logger=None): """ Remove loops and sharp turns from a list of streamlines. Parameters ---------- streamlines: list of ndarray The list of streamlines from which to remove loops and sharp turns. use_qb: bool Set to True if the additional QuickBundles pass is done. This will help remove sharp turns. Should only be used on bundled streamlines, not on whole-brain tractograms. max_angle: float Maximal winding angle a streamline can have before being classified as a loop. qb_threshold: float Quickbundles distance threshold, only used if use_qb is True. logger: logging object, optional Logger to use. Returns ------- A tuple containing list of ndarray: the clean streamlines list of ndarray: the list of removed streamlines, if any """ if logger is None: logger = logging.getLogger() loops = [] streamlines_clean = [] for s in streamlines: if tm.winding(s) >= max_angle: loops.append(s) else: streamlines_clean.append(s) if use_qb: if len(streamlines_clean) > 1: streamlines = streamlines_clean curvature = [] streamlines_clean = [] qb = QuickBundles(threshold=qb_threshold) clusters = qb.cluster(streamlines) for cc in clusters.centroids: curvature.append(tm.mean_curvature(cc)) mean_curvature = sum(curvature) / len(curvature) for i in xrange(len(clusters.centroids)): if tm.mean_curvature(clusters.centroids[i]) > mean_curvature: for indice in clusters[i].indices: loops.append(streamlines[indice]) else: for indice in clusters[i].indices: streamlines_clean.append(streamlines[indice]) else: logger.warning("Impossible to use the use_qb option because " + "not more than one streamline left from the\n" + "input file.") return streamlines_clean, loops
def get_mean_curvature(self): """Mean curvature of each streamline.""" mean_curvature = [dtm.mean_curvature(stream) for stream in self._data] return mean_curvature