def _register_neighb_to_model(self, model_bundle, neighb_streamlines, metric=None, x0=None, bounds=None, select_model=400, select_target=600, method='L-BFGS-B', nb_pts=20, num_threads=None): if self.verbose: print('# Local SLR of neighb_streamlines to model') t = time() if metric is None or metric == 'symmetric': metric = BundleMinDistanceMetric(num_threads=num_threads) if metric == 'asymmetric': metric = BundleMinDistanceAsymmetricMetric() if metric == 'diagonal': metric = BundleSumDistanceMatrixMetric() if x0 is None: x0 = 'similarity' if bounds is None: bounds = [(-30, 30), (-30, 30), (-30, 30), (-45, 45), (-45, 45), (-45, 45), (0.8, 1.2)] # TODO this can be speeded up by using directly the centroids static = select_random_set_of_streamlines(model_bundle, select_model, rng=self.rng) moving = select_random_set_of_streamlines(neighb_streamlines, select_target, rng=self.rng) static = set_number_of_points(static, nb_pts) moving = set_number_of_points(moving, nb_pts) slr = StreamlineLinearRegistration(metric=metric, x0=x0, bounds=bounds, method=method) slm = slr.optimize(static, moving) transf_streamlines = neighb_streamlines.copy() transf_streamlines._data = apply_affine( slm.matrix, transf_streamlines._data) transf_matrix = slm.matrix slr_bmd = slm.fopt slr_iterations = slm.iterations if self.verbose: print(' Square-root of BMD is %.3f' % (np.sqrt(slr_bmd),)) if slr_iterations is not None: print(' Number of iterations %d' % (slr_iterations,)) print(' Matrix size {}'.format(slm.matrix.shape)) original = np.get_printoptions() np.set_printoptions(3, suppress=True) print(transf_matrix) print(slm.xopt) np.set_printoptions(**original) print(' Duration %0.3f sec. \n' % (time() - t,)) return transf_streamlines, slr_bmd
def test_select_random_streamlines(): streamlines = [np.random.rand(10, 3), np.random.rand(20, 3), np.random.rand(5, 3)] new_streamlines = select_random_set_of_streamlines(streamlines, 2) assert_equal(len(new_streamlines), 2) new_streamlines = select_random_set_of_streamlines(streamlines, 4) assert_equal(len(new_streamlines), 3)
def test_select_random_streamlines(): streamlines = [np.random.rand(10, 3), np.random.rand(20, 3), np.random.rand(5, 3)] new_streamlines = select_random_set_of_streamlines(streamlines, 2) assert_equal(len(new_streamlines), 2) new_streamlines = select_random_set_of_streamlines(streamlines, 4) assert_equal(len(new_streamlines), 3)
def evaluate_results(self, model_bundle, pruned_streamlines, slr_select): """ Compare the similiarity between two given bundles, model bundle, and extracted bundle. Parameters ---------- model_bundle : Streamlines pruned_streamlines : Streamlines slr_select : tuple Select the number of streamlines from model to neirborhood of model to perform the local SLR. Returns ------- ba_value : float bundle adjacency value between model bundle and pruned bundle bmd_value : float bundle minimum distance value between model bundle and pruned bundle """ spruned_streamlines = Streamlines(pruned_streamlines) recog_centroids = self._cluster_model_bundle( spruned_streamlines, model_clust_thr=1.25) mod_centroids = self._cluster_model_bundle( model_bundle, model_clust_thr=1.25) recog_centroids = Streamlines(recog_centroids) model_centroids = Streamlines(mod_centroids) ba_value = bundle_adjacency(set_number_of_points(recog_centroids, 20), set_number_of_points(model_centroids, 20), threshold=10) BMD = BundleMinDistanceMetric() static = select_random_set_of_streamlines(model_bundle, slr_select[0]) moving = select_random_set_of_streamlines(pruned_streamlines, slr_select[1]) nb_pts = 20 static = set_number_of_points(static, nb_pts) moving = set_number_of_points(moving, nb_pts) BMD.setup(static, moving) x0 = np.array([0, 0, 0, 0, 0, 0, 1., 1., 1, 0, 0, 0]) # affine bmd_value = BMD.distance(x0.tolist()) return ba_value, bmd_value
def get_data(in_fn, out_fn): # Load volume tom = nib.load(in_fn).get_data() # 144 x 144 x 144 x 3 #tom = np.sum(tom, axis=0) #tom = cv2.resize(tom, (256, 256)) # Preprocess input tom = (tom - np.min(tom)) / (np.max(tom) - np.min(tom)) # normalise into range [0,1] tom = torch.from_numpy(tom) tom = tom.permute(3, 0, 1, 2) # channels first for pytorch # Load the tractogram tractogram = load_trk(out_fn, 'same', bbox_valid_check=False) streamlines = tractogram.streamlines # Preprocess the streamlines streamlines = select_random_set_of_streamlines(streamlines, 1024) streamlines = set_number_of_points(streamlines, 100) streamlines = np.array(streamlines) if len(streamlines) < 1024: temp_streamlines = np.zeros((1024, 100, 3)) temp_streamlines[:streamlines.shape[0],:streamlines.shape[1], :streamlines.shape[2]] = streamlines streamlines = np.float32(temp_streamlines) streamlines = np.reshape(streamlines, (32, 32, 300)) #tractogram = (tractogram - np.min(tractogram)) / (np.max(tractogram) - np.min(tractogram)) tractogram = torch.from_numpy(streamlines) tractogram = tractogram.permute(2, 0, 1) # channels first for pytorch return [tom, tractogram]
def evaluate_results(self, model_bundle, pruned_streamlines, slr_select): """ Comapare the similiarity between two given bundles, model bundle, and extracted bundle. Parameters ---------- model_bundle : Streamlines pruned_streamlines : Streamlines slr_select : tuple Select the number of streamlines from model to neirborhood of model to perform the local SLR. Returns ------- ba_value : float bundle analytics value between model bundle and pruned bundle bmd_value : float bundle minimum distance value between model bundle and pruned bundle """ spruned_streamlines = Streamlines(pruned_streamlines) recog_centroids = self._cluster_model_bundle( spruned_streamlines, model_clust_thr=1.25) mod_centroids = self._cluster_model_bundle( model_bundle, model_clust_thr=1.25) recog_centroids = Streamlines(recog_centroids) model_centroids = Streamlines(mod_centroids) ba_value = ba_analysis(recog_centroids, model_centroids, threshold=10) BMD = BundleMinDistanceMetric() static = select_random_set_of_streamlines(model_bundle, slr_select[0]) moving = select_random_set_of_streamlines(pruned_streamlines, slr_select[1]) nb_pts = 20 static = set_number_of_points(static, nb_pts) moving = set_number_of_points(moving, nb_pts) BMD.setup(static, moving) x0 = np.array([0, 0, 0, 0, 0, 0, 1., 1., 1, 0, 0, 0]) # affine bmd_value = BMD.distance(x0.tolist()) return ba_value, bmd_value
def _read_tg(self, tg=None): if tg is None: tg = self.tg else: self.tg = tg self._tg_orig_space = self.tg.space if self.nb_streamlines and len(self.tg) > self.nb_streamlines: self.tg = StatefulTractogram.from_sft( dts.select_random_set_of_streamlines(self.tg.streamlines, self.nb_streamlines), self.tg) return tg
def density_map(tractogram, n_sls=None, to_vox=False, normalize=False): """ Create a streamline density map. based on: https://dipy.org/documentation/1.1.1./examples_built/streamline_formats/ Parameters ---------- tractogram : StatefulTractogram Stateful tractogram whose streamlines are used to make the density map. n_sls : int or None, optional n_sls to randomly select to make the density map. If None, all streamlines are used. Default: None to_vox : bool, optional Whether to put the stateful tractogram in VOX space before making the density map. Default: False normalize : bool, optional Whether to normalize maximum values to 1. Default: False Returns ------- Nifti1Image containing the density map. """ if to_vox: tractogram.to_vox() sls = tractogram.streamlines if n_sls is not None: sls = select_random_set_of_streamlines(sls, n_sls) affine, vol_dims, voxel_sizes, voxel_order = get_reference_info(tractogram) tractogram_density = dtu.density_map(sls, np.eye(4), vol_dims) if normalize: tractogram_density = tractogram_density / tractogram_density.max() nifti_header = create_nifti_header(affine, vol_dims, voxel_sizes) density_map_img = nib.Nifti1Image(tractogram_density, affine, nifti_header) return density_map_img
def get_data(in_fn, out_fn, mean, sdev): # Load volume tom = nib.load(in_fn).get_data() # 144 x 144 x 144 x 3 #tom = np.sum(tom, axis=0) #tom = cv2.resize(tom, (256, 256)) # Preprocess input tom = (tom - mean) / sdev # normalise based on dataset mean/stdev """ do_flip_X = False if random.randint(0,1) == 0 else True do_flip_Y = False if random.randint(0,1) == 0 else True do_flip_Z = False if random.randint(0,1) == 0 else True if do_flip_X: tom = tom[::-1,:,:] if do_flip_Y: tom = tom[:,::-1,:] if do_flip_Z: tom = tom[:,:,::-1] """ tom = torch.from_numpy(np.float32(tom)) tom = tom.permute(3, 0, 1, 2) # channels first for pytorch # Load the tractogram tractogram = load_trk(out_fn, 'same', bbox_valid_check=False) streamlines = tractogram.streamlines # Preprocess the streamlines streamlines = select_random_set_of_streamlines(streamlines, num_streamlines) streamlines = set_number_of_points(streamlines, num_points) streamlines = np.array(streamlines) if len(streamlines) < num_streamlines: temp_streamlines = np.zeros((num_streamlines, num_points, 3)) temp_streamlines[:streamlines.shape[0],:streamlines.shape[1], :streamlines.shape[2]] = streamlines streamlines = np.float32(temp_streamlines) streamlines = np.reshape(streamlines, (int(num_streamlines**(1/2)), int(num_streamlines**(1/2)), num_points*3)) #tractogram = (tractogram - np.min(tractogram)) / (np.max(tractogram) - np.min(tractogram)) tractogram = torch.from_numpy(streamlines) tractogram = tractogram.permute(2, 0, 1) # channels first for pytorch return [tom, tractogram]
def _register_model_to_neighb(self, slr_num_thread=1, select_model=1000, select_target=1000, slr_transform_type='scaling'): """ Parameters ---------- slr_num_thread : int Number of threads for SLR. Should remain 1 for nearly all use-case. select_model : int Maximum number of clusters to select from the model. select_target : int Maximum number of clusters to select from the neighborhood. slr_transform_type : str Define the transformation for the local SLR. [translation, rigid, similarity, scaling]. Returns ------- transf_neighbor : list The neighborhood clusters transformed into model space. """ possible_slr_transform_type = { 'translation': 0, 'rigid': 1, 'similarity': 2, 'scaling': 3 } static = select_random_set_of_streamlines(self.model_centroids, select_model, self.rng) moving = select_random_set_of_streamlines(self.neighb_centroids, select_target, self.rng) # Tuple 0,1,2 are the min & max bound in x,y,z for translation # Tuple 3,4,5 are the min & max bound in x,y,z for rotation # Tuple 6,7,8 are the min & max bound in x,y,z for scaling # For uniform scaling (similarity), tuple #6 is enough bounds_dof = [(-20, 20), (-20, 20), (-20, 20), (-10, 10), (-10, 10), (-10, 10), (0.8, 1.2), (0.8, 1.2), (0.8, 1.2)] metric = BundleMinDistanceMetric(num_threads=slr_num_thread) slr_transform_type_id = possible_slr_transform_type[slr_transform_type] if slr_transform_type_id >= 0: init_transfo_dof = np.zeros(3) slr = StreamlineLinearRegistration(metric=metric, method="Powell", x0=init_transfo_dof, bounds=bounds_dof[:3], num_threads=slr_num_thread) slm = slr.optimize(static, moving) if slr_transform_type_id >= 1: init_transfo_dof = np.zeros(6) init_transfo_dof[:3] = slm.xopt slr = StreamlineLinearRegistration(metric=metric, x0=init_transfo_dof, bounds=bounds_dof[:6], num_threads=slr_num_thread) slm = slr.optimize(static, moving) if slr_transform_type_id >= 2: if slr_transform_type_id == 2: init_transfo_dof = np.zeros(7) init_transfo_dof[:6] = slm.xopt init_transfo_dof[6] = 1. slr = StreamlineLinearRegistration(metric=metric, x0=init_transfo_dof, bounds=bounds_dof[:7], num_threads=slr_num_thread) slm = slr.optimize(static, moving) else: init_transfo_dof = np.zeros(9) init_transfo_dof[:6] = slm.xopt[:6] init_transfo_dof[6:] = np.array((slm.xopt[6], ) * 3) slr = StreamlineLinearRegistration(metric=metric, x0=init_transfo_dof, bounds=bounds_dof[:9], num_threads=slr_num_thread) slm = slr.optimize(static, moving) self.model_centroids = transform_streamlines(self.model_centroids, np.linalg.inv(slm.matrix))
def lesspoints(lines): #line_out= [approx_polygon_track(line,0.06) for line in lines] if len(lines) > 1000: return select_random_set_of_streamlines(lines, 1000) else: return lines
print('Loading from' + npath) #load native and unfolded strealines nlines = lesspoints(load_vtk_streamlines(npath + 'native_streamlines.vtk')) ulines = lesspoints( load_vtk_streamlines(npath + 'from_unfold_streamlines.vtk')) print('Filtering...') nlines_tang = nicelines(npath, nlines) ulines_tang = nicelines(npath, ulines) print(len(nlines)) print('Getting native voxels') # #get the voxel inds Nrand = 200 if len(nlines_tang) > Nrand: nlines = select_random_set_of_streamlines(nlines_tang, Nrand) ulines = select_random_set_of_streamlines(ulines_tang, Nrand) ninds = [] nginds = [] for line in nlines: ninds.append(unfoldTracking.connectedInds(line, mask_nii)) print('Getting unfold voxels') uinds = [] uginds = [] for line in ulines: uinds.append(unfoldTracking.connectedInds(line, mask_nii)) print('Getting true tact instance') # #truetracts class instance tt = trueTracts(radtang_nii, U_nii, V_nii, 2, phi, phiInv)
t1_data = t1.get_data() t1_aff = t1.affine color = cmap.line_colors(streamlines) # Enables/disables interactive visualization interactive = False """ To speed up visualization, we will select a random sub-set of streamlines to display. This is particularly important, if you track from seeds throughout the entire white matter, generating many streamlines. In this case, for demonstration purposes, we subselect 900 streamlines. """ from dipy.tracking.streamline import select_random_set_of_streamlines plot_streamlines = select_random_set_of_streamlines(streamlines, 900) streamlines_actor = actor.streamtube( list(move_streamlines(plot_streamlines, inv(t1_aff))), cmap.line_colors(streamlines), linewidth=0.1) vol_actor = actor.slicer(t1_data) vol_actor.display(40, None, None) vol_actor2 = vol_actor.copy() vol_actor2.display(None, None, 35) ren = window.Renderer() ren.add(streamlines_actor) ren.add(vol_actor) ren.add(vol_actor2)
function 'to_vox()' and 'to_corner()' """ cc_sft.to_vox() laf_sft.to_vox() raf_sft.to_vox() lpt_sft.to_vox() rpt_sft.to_vox() cc_sft.to_corner() laf_sft.to_corner() raf_sft.to_corner() lpt_sft.to_corner() rpt_sft.to_corner() cc_streamlines_vox = select_random_set_of_streamlines(cc_sft.streamlines, 1000) laf_streamlines_vox = select_random_set_of_streamlines(laf_sft.streamlines, 1000) raf_streamlines_vox = select_random_set_of_streamlines(raf_sft.streamlines, 1000) lpt_streamlines_vox = select_random_set_of_streamlines(lpt_sft.streamlines, 1000) rpt_streamlines_vox = select_random_set_of_streamlines(rpt_sft.streamlines, 1000) # Same dimensions for every stateful tractogram, can be re-use affine, dimensions, voxel_sizes, voxel_order = cc_sft.space_attributes cc_density = density_map(cc_streamlines_vox, np.eye(4), dimensions) laf_density = density_map(laf_streamlines_vox, np.eye(4), dimensions) raf_density = density_map(raf_streamlines_vox, np.eye(4), dimensions) lpt_density = density_map(lpt_streamlines_vox, np.eye(4), dimensions)
def slr_with_qbx(static, moving, x0='affine', rm_small_clusters=50, maxiter=100, select_random=None, verbose=False, greater_than=50, less_than=250, qbx_thr=[40, 30, 20, 15], nb_pts=20, progressive=True, rng=None, 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, optional. rigid, similarity or affine transformation model (default affine) rm_small_clusters : int, optional Remove clusters that have less than `rm_small_clusters` (default 50) select_random : int, optional. If not, None selects a random number of streamlines to apply clustering Default None. verbose : bool, optional If True, logs information about optimization. Default: False greater_than : int, optional Keep streamlines that have length greater than this value (default 50) less_than : int, optional Keep streamlines have length less than this value (default 250) qbx_thr : variable int Thresholds for QuickBundlesX (default [40, 30, 20, 15]) np_pts : int, optional Number of points for discretizing each streamline (default 20) progressive : boolean, optional (default True) rng : RandomState If None creates RandomState in function. 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 rng is None: rng = np.random.RandomState() if verbose: logger.info('Static streamlines size {}'.format(len(static))) logger.info('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 streamlines1 = Streamlines(static[np.array( [check_range(s) for s in static])]) streamlines2 = Streamlines(moving[np.array( [check_range(s) for s in moving])]) if verbose: logger.info('Static streamlines after length reduction {}'.format( len(streamlines1))) logger.info('Moving streamlines after length reduction {}'.format( len(streamlines2))) if select_random is not None: rstreamlines1 = select_random_set_of_streamlines(streamlines1, select_random, rng=rng) else: rstreamlines1 = streamlines1 rstreamlines1 = set_number_of_points(rstreamlines1, nb_pts) rstreamlines1._data.astype('f4') cluster_map1 = qbx_and_merge(rstreamlines1, thresholds=qbx_thr, rng=rng) qb_centroids1 = remove_clusters_by_size(cluster_map1, rm_small_clusters) if select_random is not None: rstreamlines2 = select_random_set_of_streamlines(streamlines2, select_random, rng=rng) else: rstreamlines2 = streamlines2 rstreamlines2 = set_number_of_points(rstreamlines2, nb_pts) rstreamlines2._data.astype('f4') cluster_map2 = qbx_and_merge(rstreamlines2, thresholds=qbx_thr, rng=rng) qb_centroids2 = remove_clusters_by_size(cluster_map2, rm_small_clusters) 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: logger.info('QB static centroids size %d' % len(qb_centroids1, )) logger.info('QB moving centroids size %d' % len(qb_centroids2, )) duration = time() - t logger.info('SLR finished in %0.3f seconds.' % (duration, )) if slm.iterations is not None: logger.info('SLR iterations: %d ' % (slm.iterations, )) moved = slm.transform(moving) return moved, slm.matrix, qb_centroids1, qb_centroids2
def slr_with_qbx(static, moving, x0='affine', rm_small_clusters=50, maxiter=100, select_random=None, verbose=False, greater_than=50, less_than=250, qbx_thr=[40, 30, 20, 15], nb_pts=20, progressive=True, rng=None, 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) select_random : int If not None select a random number of streamlines to apply clustering Default None. verbose : bool, If True then information about the optimization is shown. greater_than : int, optional Keep streamlines that have length greater than this value (default 50) less_than : int, optional Keep streamlines have length less than this value (default 250) qbx_thr : variable int Thresholds for QuickBundlesX (default [40, 30, 20, 15]) np_pts : int, optional Number of points for discretizing each streamline (default 20) progressive : boolean, optional (default True) rng : RandomState If None creates RandomState in function. 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 rng is None: rng = np.random.RandomState() 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 streamlines1 = Streamlines(static[np.array([check_range(s) for s in static])]) streamlines2 = Streamlines(moving[np.array([check_range(s) for s in moving])]) 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, rng=rng) else: rstreamlines1 = streamlines1 rstreamlines1 = set_number_of_points(rstreamlines1, nb_pts) rstreamlines1._data.astype('f4') cluster_map1 = qbx_and_merge(rstreamlines1, thresholds=qbx_thr, rng=rng) qb_centroids1 = remove_clusters_by_size(cluster_map1, rm_small_clusters) if select_random is not None: rstreamlines2 = select_random_set_of_streamlines(streamlines2, select_random, rng=rng) else: rstreamlines2 = streamlines2 rstreamlines2 = set_number_of_points(rstreamlines2, nb_pts) rstreamlines2._data.astype('f4') cluster_map2 = qbx_and_merge(rstreamlines2, thresholds=qbx_thr, rng=rng) qb_centroids2 = remove_clusters_by_size(cluster_map2, rm_small_clusters) 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
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
t1_data = t1.get_data() t1_aff = t1.affine color = cmap.line_colors(streamlines) # Enables/disables interactive visualization interactive = False """ To speed up visualization, we will select a random sub-set of streamlines to display. This is particularly important, if you track from seeds throughout the entire white matter, generating many streamlines. In this case, for demonstration purposes, we subselect 900 streamlines. """ from dipy.tracking.streamline import select_random_set_of_streamlines plot_streamlines = select_random_set_of_streamlines(streamlines, 900) streamlines_actor = actor.streamtube( list(move_streamlines(plot_streamlines, inv(t1_aff))), cmap.line_colors(streamlines), linewidth=0.1) vol_actor = actor.slicer(t1_data) vol_actor.display(40, None, None) vol_actor2 = vol_actor.copy() vol_actor2.display(None, None, 35) ren = window.Renderer() ren.add(streamlines_actor) ren.add(vol_actor) ren.add(vol_actor2)
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