def test_slr_flow(): with TemporaryDirectory() as out_dir: data_path = get_fnames('fornix') streams, hdr = nib.trackvis.read(data_path) fornix = [s[0] for s in streams] f = Streamlines(fornix) f1 = f.copy() f1_path = pjoin(out_dir, "f1.trk") save_trk(f1_path, Streamlines(f1), affine=np.eye(4)) f2 = f1.copy() f2._data += np.array([50, 0, 0]) f2_path = pjoin(out_dir, "f2.trk") save_trk(f2_path, Streamlines(f2), affine=np.eye(4)) slr_flow = SlrWithQbxFlow(force=True) slr_flow.run(f1_path, f2_path) out_path = slr_flow.last_generated_outputs['out_moved'] npt.assert_equal(os.path.isfile(out_path), True)
def test_io_streamline(): with InTemporaryDirectory(): fname = 'test.trk' affine = np.eye(4) # Test save save_trk(fname, streamlines, affine, vox_size=np.array([2, 1.5, 1.5]), shape=np.array([50, 50, 50])) tfile = nib.streamlines.load(fname) npt.assert_array_equal(affine, tfile.affine) npt.assert_array_equal(np.array([2, 1.5, 1.5]), tfile.header.get('voxel_sizes')) npt.assert_array_equal(np.array([50, 50, 50]), tfile.header.get('dimensions')) npt.assert_equal(len(tfile.streamlines), len(streamlines)) npt.assert_array_almost_equal(tfile.streamlines[1], streamline, decimal=4) # Test basic save save_trk(fname, streamlines, affine) tfile = nib.streamlines.load(fname) npt.assert_array_equal(affine, tfile.affine) npt.assert_equal(len(tfile.streamlines), len(streamlines)) npt.assert_array_almost_equal(tfile.streamlines[1], streamline, decimal=5) # Test Load local_streamlines, hdr = load_trk(fname) npt.assert_equal(len(local_streamlines), len(streamlines)) for arr1, arr2 in zip(local_streamlines, streamlines): npt.assert_allclose(arr1, arr2)
def test_recobundles_flow(): with TemporaryDirectory() as out_dir: data_path = get_fnames('fornix') streams, hdr = nib.trackvis.read(data_path) fornix = [s[0] for s in streams] f = Streamlines(fornix) f1 = f.copy() f2 = f1[:15].copy() f2._data += np.array([40, 0, 0]) f.extend(f2) f2_path = pjoin(out_dir, "f2.trk") save_trk(f2_path, f2, affine=np.eye(4)) f1_path = pjoin(out_dir, "f1.trk") save_trk(f1_path, f, affine=np.eye(4)) rb_flow = RecoBundlesFlow(force=True) rb_flow.run(f1_path, f2_path, greater_than=0, clust_thr=10, model_clust_thr=5., reduction_thr=10, out_dir=out_dir) labels = rb_flow.last_generated_outputs['out_recognized_labels'] recog_trk = rb_flow.last_generated_outputs['out_recognized_transf'] rec_bundle, _ = load_trk(recog_trk) npt.assert_equal(len(rec_bundle) == len(f2), True) label_flow = LabelsBundlesFlow(force=True) label_flow.run(f1_path, labels) recog_bundle = label_flow.last_generated_outputs['out_bundle'] rec_bundle_org, _ = load_trk(recog_bundle) BMD = BundleMinDistanceMetric() nb_pts = 20 static = set_number_of_points(f2, nb_pts) moving = set_number_of_points(rec_bundle_org, 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()) npt.assert_equal(bmd_value < 1, True)
def test_bundle_analysis_population_flow(): with TemporaryDirectory() as dirpath: streams, hdr = nib.trackvis.read(get_fnames('fornix')) fornix = [s[0] for s in streams] f = Streamlines(fornix) mb = os.path.join(dirpath, "model_bundles") sub = os.path.join(dirpath, "subjects") os.mkdir(mb) save_trk(os.path.join(mb, "temp.trk"), f, affine=np.eye(4)) os.mkdir(sub) os.mkdir(os.path.join(sub, "patient")) os.mkdir(os.path.join(sub, "control")) p = os.path.join(sub, "patient", "10001") os.mkdir(p) c = os.path.join(sub, "control", "20002") os.mkdir(c) for pre in [p, c]: os.mkdir(os.path.join(pre, "rec_bundles")) save_trk(os.path.join(pre, "rec_bundles", "temp.trk"), f, affine=np.eye(4)) os.mkdir(os.path.join(pre, "org_bundles")) save_trk(os.path.join(pre, "org_bundles", "temp.trk"), f, affine=np.eye(4)) os.mkdir(os.path.join(pre, "measures")) fa = np.random.rand(255, 255, 255) save_nifti(os.path.join(pre, "measures", "fa.nii.gz"), fa, affine=np.eye(4)) out_dir = os.path.join(dirpath, "output") os.mkdir(out_dir) ba_flow = BundleAnalysisPopulationFlow() ba_flow.run(mb, sub, out_dir=out_dir) assert_true(os.path.exists(os.path.join(out_dir, 'fa.h5'))) dft = pd.read_hdf(os.path.join(out_dir, 'fa.h5')) assert_true(dft.bundle.unique() == "temp") assert_true(set(dft.subject.unique()) == set(['10001', '20002']))
def run(self, streamline_files, labels_files, out_dir='', out_bundle='recognized_orig.trk'): """ Extract bundles using existing indices (labels) Parameters ---------- streamline_files : string The path of streamline files where you want to recognize bundles labels_files : string The path of model bundle files out_dir : string, optional Output directory (default input file directory) out_bundle : string, optional Recognized bundle in the space of the model bundle (default 'recognized_orig.trk') References ---------- .. [Garyfallidis17] Garyfallidis et al. Recognition of white matter bundles using local and global streamline-based registration and clustering, Neuroimage, 2017. """ logging.info('### Labels to Bundles ###') io_it = self.get_io_iterator() for sf, lb, out_bundle in io_it: logging.info(sf) streamlines, header = load_trk(sf) logging.info(lb) location = np.load(lb) logging.info('Saving output files ...') save_trk(out_bundle, streamlines[location], np.eye(4)) logging.info(out_bundle)
def test_ba(): with TemporaryDirectory() as dirpath: streams, hdr = nib.trackvis.read(get_fnames('fornix')) fornix = [s[0] for s in streams] f = Streamlines(fornix) mb = os.path.join(dirpath, "model_bundles") os.mkdir(mb) save_trk(os.path.join(mb, "temp.trk"), f, affine=np.eye(4)) rb = os.path.join(dirpath, "rec_bundles") os.mkdir(rb) save_trk(os.path.join(rb, "temp.trk"), f, affine=np.eye(4)) ob = os.path.join(dirpath, "org_bundles") os.mkdir(ob) save_trk(os.path.join(ob, "temp.trk"), f, affine=np.eye(4)) dt = os.path.join(dirpath, "dti_measures") os.mkdir(dt) fa = np.random.rand(255, 255, 255) save_nifti(os.path.join(dt, "fa.nii.gz"), fa, affine=np.eye(4)) out_dir = os.path.join(dirpath, "output") os.mkdir(out_dir) bundle_analysis(mb, rb, ob, dt, group="patient", subject="10001", no_disks=100, out_dir=out_dir) assert_true(os.path.exists(os.path.join(out_dir, 'fa.h5')))
def run(self, static_files, moving_files, x0='affine', rm_small_clusters=50, qbx_thr=[40, 30, 20, 15], num_threads=None, greater_than=50, less_than=250, nb_pts=20, progressive=True, out_dir='', out_moved='moved.trk', out_affine='affine.txt', out_stat_centroids='static_centroids.trk', out_moving_centroids='moving_centroids.trk', out_moved_centroids='moved_centroids.trk'): """ Streamline-based linear registration. For efficiency we apply the registration on cluster centroids and remove small clusters. Parameters ---------- static_files : string moving_files : string x0 : string, 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) qbx_thr : variable int, optional Thresholds for QuickBundlesX (default [40, 30, 20, 15]) num_threads : int, optional Number of threads. If None (default) then all available threads will be used. Only metrics using OpenMP will use this variable. 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) np_pts : int, optional Number of points for discretizing each streamline (default 20) progressive : boolean, optional (default True) out_dir : string, optional Output directory (default input file directory) out_moved : string, optional Filename of moved tractogram (default 'moved.trk') out_affine : string, optional Filename of affine for SLR transformation (default 'affine.txt') out_stat_centroids : string, optional Filename of static centroids (default 'static_centroids.trk') out_moving_centroids : string, optional Filename of moving centroids (default 'moving_centroids.trk') out_moved_centroids : string, optional Filename of moved centroids (default 'moved_centroids.trk') 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 QuickBundlesX. 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. """ io_it = self.get_io_iterator() logging.info("QuickBundlesX clustering is in use") logging.info('QBX thresholds {0}'.format(qbx_thr)) for static_file, moving_file, out_moved_file, out_affine_file, \ static_centroids_file, moving_centroids_file, \ moved_centroids_file in io_it: logging.info('Loading static file {0}'.format(static_file)) logging.info('Loading moving file {0}'.format(moving_file)) static, static_header = load_trk(static_file) moving, moving_header = load_trk(moving_file) moved, affine, centroids_static, centroids_moving = \ slr_with_qbx( static, moving, x0, rm_small_clusters=rm_small_clusters, greater_than=greater_than, less_than=less_than, qbx_thr=qbx_thr) logging.info('Saving output file {0}'.format(out_moved_file)) save_trk(out_moved_file, moved, affine=np.eye(4), header=static_header) logging.info('Saving output file {0}'.format(out_affine_file)) np.savetxt(out_affine_file, affine) logging.info('Saving output file {0}' .format(static_centroids_file)) save_trk(static_centroids_file, centroids_static, affine=np.eye(4), header=static_header) logging.info('Saving output file {0}' .format(moving_centroids_file)) save_trk(moving_centroids_file, centroids_moving, affine=np.eye(4), header=static_header) centroids_moved = transform_streamlines(centroids_moving, affine) logging.info('Saving output file {0}' .format(moved_centroids_file)) save_trk(moved_centroids_file, centroids_moved, affine=np.eye(4), header=static_header)
from dipy.io.streamline import save_trk # Save density map dm_img = nib.Nifti1Image(dm.astype("int16"), hardi_img.affine) dm_img.to_filename("lr-superiorfrontal-dm.nii.gz") # Move streamlines to "trackvis space" voxel_size = labels_img.header.get_zooms() trackvis_point_space = utils.affine_for_trackvis(voxel_size) # lr_sf_trk = utils.move_streamlines(lr_superiorfrontal_track, # trackvis_point_space, input_space=affine) lr_sf_trk = Streamlines(lr_superiorfrontal_track) # Save streamlines save_trk("lr-superiorfrontal.trk", lr_sf_trk, shape=shape, vox_size=voxel_size, affine=affine) """ Let's take a moment here to consider the representation of streamlines used in DIPY. Streamlines are a path though the 3D space of an image represented by a set of points. For these points to have a meaningful interpretation, these points must be given in a known coordinate system. The ``affine`` attribute of the ``streamline_generator`` object specifies the coordinate system of the points with respect to the voxel indices of the input data. ``trackvis_point_space`` specifies the trackvis coordinate system with respect to the same indices. The ``move_streamlines`` function returns a new set of streamlines from an existing set of streamlines in the target space. The target space and the input space must be specified as affine transformations with respect to the same reference [#]_. If no input space is given, the input space will be the same as the current representation of the streamlines, in other words the input space is assumed to be ``np.eye(4)``, the 4-by-4 identity
tensor_streamlines = Streamlines(eu) """ We can now save the results in the disk. For this purpose we can use the TrackVis format (``*.trk``). First, we need to import ``save_trk`` function. """ from dipy.io.streamline import save_trk """ Save the streamlines. """ ten_sl_fname = 'tensor_streamlines.trk' save_trk(ten_sl_fname, tensor_streamlines, affine=np.eye(4), vox_size=fa_img.header.get_zooms()[:3], shape=FA.shape) """ If you don't want to use Trackvis to visualize the file you can use our lightweight `dipy.viz` module. """ try: from dipy.viz import window, actor except ImportError: raise ImportError('Python fury module is not installed') import sys sys.exit() """ Create a scene.
""" .. figure:: threshold_fa.png :align: center **Thresholded fractional anisotropy map.** """ streamline_generator = LocalTracking(dg, threshold_criterion, seeds, affine, step_size=.5, return_all=True) streamlines = Streamlines(streamline_generator) sft = StatefulTractogram(streamlines, hardi_img, Space.RASMM) save_trk(sft, "tractogram_probabilistic_thresh_all.trk") if has_fury: scene = window.Scene() scene.add(actor.line(streamlines, colormap.line_colors(streamlines))) window.record(scene, out_path='tractogram_deterministic_thresh_all.png', size=(800, 800)) if interactive: window.show(scene) """ .. figure:: tractogram_deterministic_thresh_all.png :align: center **Corpus Callosum using deterministic tractography with a thresholded fractional anisotropy mask.**
from dipy.io.streamline import load_trk, save_trk from dipy.tracking.streamline import Streamlines """ 1. Read/write streamline files with DIPY. """ fname = get_data('fornix') print(fname) # Read Streamlines streams, hdr = load_trk(fname) streamlines = Streamlines(streams) # Save Streamlines save_trk("my_streamlines.trk", streamlines=streamlines, affine=np.eye(4)) """ 2. We also work on our HDF5 based file format which can read/write massive datasets (as big as the size of you free disk space). With `Dpy` we can support * direct indexing from the disk * memory usage always low * extensions to include different arrays in the same file Here is a simple example. """ from dipy.io.dpy import Dpy dpw = Dpy('fornix.dpy', 'w')
""" .. figure:: threshold_fa.png :align: center **Thresholded fractional anisotropy map.** """ all_streamline_threshold_tc_generator = LocalTracking(dg, threshold_classifier, seeds, affine, step_size=.5, return_all=True) streamlines = Streamlines(all_streamline_threshold_tc_generator) save_trk("all_streamlines_threshold_classifier.trk", streamlines, affine, labels.shape) if have_fury: window.clear(ren) ren.add(actor.line(streamlines, cmap.line_colors(streamlines))) window.record(ren, out_path='all_streamlines_threshold_classifier.png', size=(600, 600)) if interactive: window.show(ren) """ .. figure:: all_streamlines_threshold_classifier.png :align: center **Deterministic tractography using a thresholded fractional anisotropy.**
average_voxel_size=voxel_size) # Particle Filtering Tractography pft_streamline_generator = ParticleFilteringTracking(dg, cmc_classifier, seeds, affine, max_cross=1, step_size=step_size, maxlen=1000, pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15, return_all=False) streamlines = Streamlines(pft_streamline_generator) save_trk("tractogram_pft.trk", streamlines, affine, shape) if has_fury: r = window.Renderer() r.add(actor.line(streamlines, colormap.line_colors(streamlines))) window.record(r, out_path='tractogram_pft.png', size=(800, 800)) if interactive: window.show(r) """ .. figure:: tractogram_pft.png :align: center **Corpus Callosum using particle filtering tractography** """ # Local Probabilistic Tractography
""" We can now save the results in the disk. For this purpose we can use the TrackVis format (``*.trk``). First, we need to import ``save_trk`` function. """ from dipy.io.streamline import save_trk """ Save the streamlines. """ ten_sl_fname = 'tensor_streamlines.trk' save_trk(ten_sl_fname, tensor_streamlines, affine=np.eye(4), vox_size=fa_img.header.get_zooms()[:3], shape=FA.shape) """ If you don't want to use Trackvis to visualize the file you can use our lightweight `dipy.viz` module. """ try: from dipy.viz import window, actor except ImportError: raise ImportError('Python vtk module is not installed') import sys sys.exit() """
streamlines = Streamlines( LocalTracking(detmax_dg, classifier, seeds, affine, step_size=.5)) long_streamlines = np.ones((len(streamlines)), bool) for i in range(0, len(streamlines)): if streamlines[i].shape[0] < 70: long_streamlines[i] = False streamlines = streamlines[long_streamlines] dir_name = os.path.join( r"C:\Users\Admin\Miniconda3\envs\LabPy\FT\FT\ft_deter_mdg") if not os.path.exists(dir_name): os.mkdir(dir_name) tract_name = os.path.join(dir_name, (subj_name + ".trk")) save_trk(tract_name, streamlines, affine, labels.shape) from dipy.viz import window, actor, colormap as cmap streamlines_actor = actor.line(streamlines, cmap.line_colors(streamlines)) # Create the 3D display. r = window.Renderer() r.add(streamlines_actor) # Save still images for this static example. window.record(r, n_frames=1, out_path='probabilistic.png', size=(800, 800)) window.show(r) ## load trk file:
def execution(self, context): sh_coeff_vol = aims.read(self.sh_coefficients.fullPath()) header = sh_coeff_vol.header() #transformation from Aims LPI mm space to RAS mm (reference space) aims_mm_to_ras_mm = np.array(header['transformations'][0]).reshape((4, 4)) voxel_size = np.array(header['voxel_size']) if len(voxel_size) == 4: voxel_size = voxel_size[:-1] scaling = np.concatenate((voxel_size, np.ones(1))) context.write(voxel_size.shape) scaling_mat = np.diag(scaling) context.write(scaling_mat.shape, aims_mm_to_ras_mm.shape) aims_voxel_to_ras_mm = np.dot(scaling_mat, aims_mm_to_ras_mm) affine_tracking = np.eye(4) sh = np.array(sh_coeff_vol, copy=True) sh = sh.astype(np.float64) vol_shape = sh.shape[:-1] if self.sphere is not None: sphere = read_sphere(self.sphere.fullPath()) else: context.write( 'No Projection Sphere provided. Default dipy sphere symmetric 362 is used' ) sphere = get_sphere() dg = DirectionGetter[self.type].from_shcoeff( sh, self.max_angle, sphere, basis_type=None, relative_peak_threshold=self.relative_peak_threshold, min_separation_angle=self.min_separation_angle) #Handling seeds in both deterministic and probabilistic framework s = np.loadtxt(self.seeds.fullPath()) s = s.astype(np.float32) i = np.arange(self.nb_samples) if self.nb_samples <= 1: seeds = s else: seeds = np.zeros((self.nb_samples, ) + s.shape) seeds[i] = s seeds = seeds.reshape((-1, 3)) seeds = nib.affines.apply_affine(np.linalg.inv(scaling_mat), seeds) #building classifier csf_vol = aims.read(self.csf_pve.fullPath()) grey_vol = aims.read(self.gm_pve.fullPath()) white_vol = aims.read(self.wm_pve.fullPath()) csf = np.array(csf_vol) csf = csf[..., 0] gm = np.array(grey_vol) gm = gm[..., 0] wm = np.array(white_vol) wm = wm[..., 0] #rethreshold volumes due to interpolation (eg values >1) total = (csf + gm + wm).copy() csf[total <= 0] = 0 gm[total <= 0] = 0 wm[total <= 0] = 0 csf[total != 0] = (csf[total != 0]) / (total[total != 0]) wm[total != 0] = (wm[total != 0]) / (total[total != 0]) gm[total != 0] = gm[total != 0] / (total[total != 0]) classif = Classifiers[self.constraint] classifier = classif.from_pve(wm_map=wm, gm_map=gm, csf_map=csf) #Tracking is made in the LPI voxel space in order no to imposes affine to data. The seeds are supposed to also be in LPI voxel space streamlines_generator = ParticleFilteringTracking( dg, classifier, seeds, affine_tracking, step_size=self.step_size, max_cross=self.crossing_max, maxlen=self.nb_iter_max, pft_back_tracking_dist=self.back_tracking_dist, pft_front_tracking_dist=self.front_tracking_dist, pft_max_trial=self.max_trial, particle_count=self.nb_particles, return_all=self.return_all) #Store Fibers directly in LPI orientation with appropriate transformation save_trk(self.streamlines.fullPath(), streamlines_generator, affine=aims_voxel_to_ras_mm, vox_size=voxel_size, shape=vol_shape) transformManager = getTransformationManager() transformManager.copyReferential(self.sh_coefficients, self.streamlines)
def key_press(obj, event): key = obj.GetKeySym() if self.cluster: # hide on/off unselected centroids if key == 'h' or key == 'H': if self.hide_centroids: for ca in self.cea: if (self.cea[ca]['length'] >= self.length_min or self.cea[ca]['size'] >= self.size_min): if self.cea[ca]['selected'] == 0: ca.VisibilityOff() else: for ca in self.cea: if (self.cea[ca]['length'] >= self.length_min and self.cea[ca]['size'] >= self.size_min): if self.cea[ca]['selected'] == 0: ca.VisibilityOn() self.hide_centroids = not self.hide_centroids show_m.render() # invert selection if key == 'i' or key == 'I': for ca in self.cea: if (self.cea[ca]['length'] >= self.self.length_min and self.cea[ca]['size'] >= self.size_min): self.cea[ca]['selected'] = \ not self.cea[ca]['selected'] cas = self.cea[ca]['cluster_actor'] self.cla[cas]['selected'] = \ self.cea[ca]['selected'] show_m.render() # save current result if key == 's' or key == 'S': saving_streamlines = Streamlines() for bundle in self.cla.keys(): if bundle.GetVisibility(): t = self.cla[bundle]['tractogram'] c = self.cla[bundle]['cluster'] indices = self.tractogram_clusters[t][c] saving_streamlines.extend(Streamlines(indices)) print('Saving result in tmp.trk') save_trk('tmp.trk', saving_streamlines, np.eye(4)) if key == 'y' or key == 'Y': active_streamlines = Streamlines() for bundle in self.cla.keys(): if bundle.GetVisibility(): t = self.cla[bundle]['tractogram'] c = self.cla[bundle]['cluster'] indices = self.tractogram_clusters[t][c] active_streamlines.extend(Streamlines(indices)) # self.tractograms = [active_streamlines] hz2 = horizon([active_streamlines], self.images, cluster=True, cluster_thr=5, random_colors=self.random_colors, length_lt=np.inf, length_gt=0, clusters_lt=np.inf, clusters_gt=0, world_coords=True, interactive=True) ren2 = hz2.build_scene() hz2.build_show(ren2) if key == 'a' or key == 'A': if self.select_all is False: for ca in self.cea: if (self.cea[ca]['length'] >= self.length_min and self.cea[ca]['size'] >= self.size_min): self.cea[ca]['selected'] = 1 cas = self.cea[ca]['cluster_actor'] self.cla[cas]['selected'] = \ self.cea[ca]['selected'] show_m.render() self.select_all = True else: for ca in self.cea: if (self.cea[ca]['length'] >= self.length_min and self.cea[ca]['size'] >= self.size_min): self.cea[ca]['selected'] = 0 cas = self.cea[ca]['cluster_actor'] self.cla[cas]['selected'] = \ self.cea[ca]['selected'] show_m.render() self.select_all = False if key == 'e' or key == 'E': for c in self.cea: if self.cea[c]['selected']: if not self.cea[c]['expanded']: len_ = self.cea[c]['length'] sz_ = self.cea[c]['size'] if (len_ >= self.length_min and sz_ >= self.size_min): self.cea[c]['cluster_actor']. \ VisibilityOn() c.VisibilityOff() self.cea[c]['expanded'] = 1 show_m.render() if key == 'r' or key == 'R': for c in self.cea: if (self.cea[c]['length'] >= self.length_min and self.cea[c]['size'] >= self.size_min): self.cea[c]['cluster_actor'].VisibilityOff() c.VisibilityOn() self.cea[c]['expanded'] = 0 show_m.render()
import dipy.reconst.dti as dti from dipy.reconst.dti import fractional_anisotropy tensor_model = dti.TensorModel(gtab) tenfit = tensor_model.fit(data, mask=white_matter) FA = fractional_anisotropy(tenfit.evals) classifier = ThresholdTissueClassifier(FA, .2) """ The Fiber Orientation Distribution (FOD) of the CSD model estimates the distribution of small fiber bundles within each voxel. This distribution can be used for deterministic fiber tracking. As for probabilistic tracking, there are many ways to provide those distributions to the deterministic maximum direction getter. Here, the spherical harmonic representation of the FOD is used. """ from dipy.data import default_sphere from dipy.direction import DeterministicMaximumDirectionGetter from dipy.io.streamline import save_trk detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) streamlines = LocalTracking(detmax_dg, classifier, seeds, affine, step_size=.5) save_trk("deterministic_maximum_shm_coeff.trk", streamlines, affine, labels.shape)
# Particle Filtering Tractography pft_streamline_generator = ParticleFilteringTracking(dg, cmc_classifier, seeds, affine, max_cross=1, step_size=step_size, maxlen=1000, pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15, return_all=False) # streamlines = list(pft_streamline_generator) streamlines = Streamlines(pft_streamline_generator) save_trk("pft_streamline.trk", streamlines, affine, shape) renderer.clear() renderer.add(actor.line(streamlines, cmap.line_colors(streamlines))) window.record(renderer, out_path='pft_streamlines.png', size=(600, 600)) """ .. figure:: pft_streamlines.png :align: center **Particle Filtering Tractography** """ # Local Probabilistic Tractography prob_streamline_generator = LocalTracking(dg,
need to move them to "trackvis space", or the representation of streamlines specified by the trackvis Track File format. """ from dipy.io.stateful_tractogram import Space, StatefulTractogram from dipy.io.streamline import save_trk # Save density map save_nifti("lr-superiorfrontal-dm.nii.gz", dm.astype("int16"), affine) lr_sf_trk = Streamlines(lr_superiorfrontal_track) # Save streamlines sft = StatefulTractogram(lr_sf_trk, hardi_img, Space.VOX) save_trk(sft, "lr-superiorfrontal.trk") """ .. rubric:: Footnotes .. [#] The image `aparc-reduced.nii.gz`, which we load as ``labels_img``, is a modified version of label map `aparc+aseg.mgz` created by `FreeSurfer <https://surfer.nmr.mgh.harvard.edu/>`_. The corpus callosum region is a combination of the FreeSurfer labels 251-255. The remaining FreeSurfer labels were re-mapped and reduced so that they lie between 0 and 88. To see the FreeSurfer region, label and name, represented by each value see `label_info.txt` in `~/.dipy/stanford_hardi`. .. [#] An affine transformation is a mapping between two coordinate systems that can represent scaling, rotation, sheer, translation and reflection. Affine transformations are often represented using a 4x4 matrix where the last row of the matrix is ``[0, 0, 0, 1]``. """
def run(self, streamline_files, model_bundle_files, greater_than=50, less_than=1000000, no_slr=False, clust_thr=15., reduction_thr=15., reduction_distance='mdf', model_clust_thr=2.5, pruning_thr=8., pruning_distance='mdf', slr_metric='symmetric', slr_transform='similarity', slr_matrix='small', refine=False, r_reduction_thr=12., r_pruning_thr=6., no_r_slr=False, out_dir='', out_recognized_transf='recognized.trk', out_recognized_labels='labels.npy'): """ Recognize bundles Parameters ---------- streamline_files : string The path of streamline files where you want to recognize bundles model_bundle_files : string The path of model bundle files greater_than : int, optional Keep streamlines that have length greater than this value (default 50) in mm. less_than : int, optional Keep streamlines have length less than this value (default 1000000) in mm. no_slr : bool, optional Don't enable local Streamline-based Linear Registration (default False). clust_thr : float, optional MDF distance threshold for all streamlines (default 15) reduction_thr : float, optional Reduce search space by (mm) (default 15) reduction_distance : string, optional Reduction distance type can be mdf or mam (default mdf) model_clust_thr : float, optional MDF distance threshold for the model bundles (default 2.5) pruning_thr : float, optional Pruning after matching (default 8). pruning_distance : string, optional Pruning distance type can be mdf or mam (default mdf) slr_metric : string, optional Options are None, symmetric, asymmetric or diagonal (default symmetric). slr_transform : string, optional Transformation allowed. translation, rigid, similarity or scaling (Default 'similarity'). slr_matrix : string, optional Options are 'nano', 'tiny', 'small', 'medium', 'large', 'huge' (default 'small') refine : bool, optional Enable refine recognized bunle (default False) r_reduction_thr : float, optional Refine reduce search space by (mm) (default 12) r_pruning_thr : float, optional Refine pruning after matching (default 6). no_r_slr : bool, optional Don't enable Refine local Streamline-based Linear Registration (default False). out_dir : string, optional Output directory (default input file directory) out_recognized_transf : string, optional Recognized bundle in the space of the model bundle (default 'recognized.trk') out_recognized_labels : string, optional Indices of recognized bundle in the original tractogram (default 'labels.npy') References ---------- .. [Garyfallidis17] Garyfallidis et al. Recognition of white matter bundles using local and global streamline-based registration and clustering, Neuroimage, 2017. """ slr = not no_slr r_slr = not no_r_slr bounds = [(-30, 30), (-30, 30), (-30, 30), (-45, 45), (-45, 45), (-45, 45), (0.8, 1.2), (0.8, 1.2), (0.8, 1.2)] slr_matrix = slr_matrix.lower() if slr_matrix == 'nano': slr_select = (100, 100) if slr_matrix == 'tiny': slr_select = (250, 250) if slr_matrix == 'small': slr_select = (400, 400) if slr_matrix == 'medium': slr_select = (600, 600) if slr_matrix == 'large': slr_select = (800, 800) if slr_matrix == 'huge': slr_select = (1200, 1200) slr_transform = slr_transform.lower() if slr_transform == 'translation': bounds = bounds[:3] if slr_transform == 'rigid': bounds = bounds[:6] if slr_transform == 'similarity': bounds = bounds[:7] if slr_transform == 'scaling': bounds = bounds[:9] logging.info('### RecoBundles ###') io_it = self.get_io_iterator() t = time() logging.info(streamline_files) streamlines, header = load_trk(streamline_files) logging.info(' Loading time %0.3f sec' % (time() - t,)) rb = RecoBundles(streamlines, greater_than=greater_than, less_than=less_than) for _, mb, out_rec, out_labels in io_it: t = time() logging.info(mb) model_bundle, _ = load_trk(mb) logging.info(' Loading time %0.3f sec' % (time() - t,)) logging.info("model file = ") logging.info(mb) recognized_bundle, labels = \ rb.recognize( model_bundle, model_clust_thr=model_clust_thr, reduction_thr=reduction_thr, reduction_distance=reduction_distance, pruning_thr=pruning_thr, pruning_distance=pruning_distance, slr=slr, slr_metric=slr_metric, slr_x0=slr_transform, slr_bounds=bounds, slr_select=slr_select, slr_method='L-BFGS-B') if refine: if len(recognized_bundle) > 1: # affine x0 = np.array([0, 0, 0, 0, 0, 0, 1., 1., 1, 0, 0, 0]) affine_bounds = [(-30, 30), (-30, 30), (-30, 30), (-45, 45), (-45, 45), (-45, 45), (0.8, 1.2), (0.8, 1.2), (0.8, 1.2), (-10, 10), (-10, 10), (-10, 10)] recognized_bundle, labels = \ rb.refine( model_bundle, recognized_bundle, model_clust_thr=model_clust_thr, reduction_thr=r_reduction_thr, reduction_distance=reduction_distance, pruning_thr=r_pruning_thr, pruning_distance=pruning_distance, slr=r_slr, slr_metric=slr_metric, slr_x0=x0, slr_bounds=affine_bounds, slr_select=slr_select, slr_method='L-BFGS-B') if len(labels) > 0: ba, bmd = rb.evaluate_results( model_bundle, recognized_bundle, slr_select) logging.info("Bundle adjacency Metric {0}".format(ba)) logging.info("Bundle Min Distance Metric {0}".format(bmd)) save_trk(out_rec, recognized_bundle, np.eye(4)) logging.info('Saving output files ...') np.save(out_labels, np.array(labels)) logging.info(out_rec) logging.info(out_labels)
from dipy.io.stateful_tractogram import Space, StatefulTractogram from dipy.io.streamline import save_trk fod = csd_fit.odf(small_sphere) pmf = fod.clip(min=0) prob_dg = ProbabilisticDirectionGetter.from_pmf(pmf, max_angle=30., sphere=small_sphere) streamline_generator = LocalTracking(prob_dg, stopping_criterion, seeds, affine, step_size=.5) streamlines = Streamlines(streamline_generator) sft = StatefulTractogram(streamlines, hardi_img, Space.RASMM) save_trk(sft, "tractogram_probabilistic_dg_pmf.trk") if has_fury: r = window.Renderer() r.add(actor.line(streamlines, colormap.line_colors(streamlines))) window.record(r, out_path='tractogram_probabilistic_dg_pmf.png', size=(800, 800)) if interactive: window.show(r) """ .. figure:: tractogram_probabilistic_dg_pmf.png :align: center **Corpus Callosum using probabilistic direction getter from PMF** """
``ProbabilisticDirectionGetter`` as a PMF for sampling tracking directions. We need to clip the FOD to use it as a PMF because the latter cannot have negative values. Ideally, the FOD should be strictly positive, but because of noise and/or model failures sometimes it can have negative values. """ from dipy.direction import ProbabilisticDirectionGetter from dipy.data import small_sphere from dipy.io.streamline import save_trk fod = csd_fit.odf(small_sphere) pmf = fod.clip(min=0) prob_dg = ProbabilisticDirectionGetter.from_pmf(pmf, max_angle=30., sphere=small_sphere) streamlines_generator = LocalTracking(prob_dg, classifier, seeds, affine, step_size=.5) save_trk("probabilistic_small_sphere.trk", streamlines_generator, affine, labels.shape) """ One disadvantage of using a discrete PMF to represent possible tracking directions is that it tends to take up a lot of memory (RAM). The size of the PMF, the FOD in this case, must be equal to the number of possible tracking directions on the hemisphere, and every voxel has a unique PMF. In this case the data is ``(81, 106, 76)`` and ``small_sphere`` has 181 directions so the FOD is ``(81, 106, 76, 181)``. One way to avoid sampling the PMF and holding it in memory is to build the direction getter directly from the spherical harmonic representation of the FOD. By using this approach, we can also use a larger sphere, like ``default_sphere`` which has 362 directions on the hemisphere, without having to worry about memory limitations. """ from dipy.data import default_sphere
# Particle Filtering Tractography pft_streamline_generator = ParticleFilteringTracking(dg, cmc_criterion, seeds, affine, max_cross=1, step_size=step_size, maxlen=1000, pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15, return_all=False) streamlines = Streamlines(pft_streamline_generator) sft = StatefulTractogram(streamlines, hardi_img, Space.RASMM) save_trk(sft, "tractogram_pft.trk") if has_fury: scene = window.Scene() scene.add(actor.line(streamlines, colormap.line_colors(streamlines))) window.record(scene, out_path='tractogram_pft.png', size=(800, 800)) if interactive: window.show(scene) """ .. figure:: tractogram_pft.png :align: center **Corpus Callosum using particle filtering tractography** """
renderer.add(actor.line(streamlines, cmap.line_colors(streamlines))) window.record(renderer, out_path='bootstrap_dg_CSD.png', size=(600, 600)) """ .. figure:: bootstrap_dg_CSD.png :align: center **Corpus Callosum Bootstrap Probabilistic Direction Getter** We have created a bootstrapped probabilistic set of streamlines. If you repeat the fiber tracking (keeping all inputs the same) you will NOT get exactly the same set of streamlines. We can save the streamlines as a Trackvis file so it can be loaded into other software for visualization or further analysis. """ save_trk("bootstrap_dg_CSD.trk", streamlines, affine, labels.shape) """ Example #2: Closest peak direction getter with CSD Model """ from dipy.direction import ClosestPeakDirectionGetter pmf = csd_fit.odf(small_sphere).clip(min=0) peak_dg = ClosestPeakDirectionGetter.from_pmf(pmf, max_angle=30., sphere=small_sphere) peak_streamline_generator = LocalTracking(peak_dg, classifier, seeds, affine, step_size=.5) streamlines = Streamlines(peak_streamline_generator) renderer.clear()
there are many ways to provide those distributions to the deterministic maximum direction getter. Here, the spherical harmonic representation of the FOD is used. """ detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff( csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) streamline_generator = LocalTracking(detmax_dg, stopping_criterion, seeds, affine, step_size=.5) streamlines = Streamlines(streamline_generator) sft = StatefulTractogram(streamlines, hardi_img, Space.RASMM) save_trk(sft, "tractogram_deterministic_dg.trk") if has_fury: r = window.Renderer() r.add(actor.line(streamlines, colormap.line_colors(streamlines))) window.record(r, out_path='tractogram_deterministic_dg.png', size=(800, 800)) if interactive: window.show(r) """ .. figure:: tractogram_deterministic_dg.png :align: center **Corpus Callosum using deterministic maximum direction getter** """
from dipy.io.streamline import save_trk # Save density map dm_img = nib.Nifti1Image(dm.astype("int16"), hardi_img.affine) dm_img.to_filename("lr-superiorfrontal-dm.nii.gz") # Move streamlines to "trackvis space" voxel_size = labels_img.header.get_zooms() trackvis_point_space = utils.affine_for_trackvis(voxel_size) lr_sf_trk = utils.move_streamlines(lr_superiorfrontal_track, trackvis_point_space, input_space=affine) lr_sf_trk = Streamlines(lr_sf_trk) # Save streamlines save_trk("lr-superiorfrontal.trk", lr_sf_trk, shape=shape, vox_size=voxel_size) """ Let's take a moment here to consider the representation of streamlines used in DIPY. Streamlines are a path though the 3D space of an image represented by a set of points. For these points to have a meaningful interpretation, these points must be given in a known coordinate system. The ``affine`` attribute of the ``streamline_generator`` object specifies the coordinate system of the points with respect to the voxel indices of the input data. ``trackvis_point_space`` specifies the trackvis coordinate system with respect to the same indices. The ``move_streamlines`` function returns a new set of streamlines from an existing set of streamlines in the target space. The target space and the input space must be specified as affine transformations with respect to the same reference [#]_. If no input space is given, the input space will be the same as the current representation of the streamlines, in other words the input space is assumed to be ``np.eye(4)``, the 4-by-4 identity
""" Now that we have our streamlines in memory we can save the results on the disk. For this purpose we can use the TrackVis format (``*.trk``). First, we need to import the ``save_trk`` function. """ from dipy.io.streamline import save_trk """ Save the streamlines. """ csa_sl_fname = 'csa_streamline.trk' save_trk(csa_sl_fname, csa_streamlines, affine=np.eye(4), vox_size=np.array([2., 2., 2.]), shape=csapeaks.gfa.shape[:3]) """ Visualize the streamlines with `dipy.viz` module (python vtk is required). """ from dipy.viz import window, actor from dipy.viz.colormap import line_colors # Enables/disables interactive visualization interactive = False ren = window.Renderer() ren.add(actor.line(csa_streamlines, line_colors(csa_streamlines)))
from dipy.io.streamline import load_trk, save_trk from dipy.tracking.streamline import Streamlines """ 1. Read/write streamline files with DIPY. """ fname = get_fnames('fornix') print(fname) # Read Streamlines streams, hdr = load_trk(fname) streamlines = Streamlines(streams) # Save Streamlines save_trk("my_streamlines.trk", streamlines=streamlines, affine=np.eye(4)) """ 2. We also work on our HDF5 based file format which can read/write massive datasets (as big as the size of your free disk space). With `Dpy` we can support * direct indexing from the disk * memory usage always low * extensions to include different arrays in the same file Here is a simple example. """ from dipy.io.dpy import Dpy
window.record(scene, out_path='tractogram_EuDX.png', size=(800, 800)) if interactive: window.show(scene) """ .. figure:: tractogram_EuDX.png :align: center **Corpus Callosum using EuDx** We've created a deterministic set of streamlines using the EuDX algorithm. This is so called deterministic because if you repeat the fiber tracking (keeping all the inputs the same) you will get exactly the same set of streamlines. We can save the streamlines as a Trackvis file so it can be loaded into other software for visualization or further analysis. """ from dipy.io.stateful_tractogram import Space, StatefulTractogram from dipy.io.streamline import save_trk sft = StatefulTractogram(streamlines, hardi_img, Space.RASMM) save_trk(sft, "tractogram_EuDX.trk", streamlines) """ References ---------- .. [Garyfallidis12] Garyfallidis E., "Towards an accurate brain tractography", PhD thesis, University of Cambridge, 2012. .. include:: ../links_names.inc """
""" .. figure:: deterministic.png :align: center **Corpus Callosum Deterministic** We've created a deterministic set of streamlines, so called because if you repeat the fiber tracking (keeping all the inputs the same) you will get exactly the same set of streamlines. We can save the streamlines as a Trackvis file so it can be loaded into other software for visualization or further analysis. """ from dipy.io.streamline import save_trk save_trk("CSA_detr.trk", streamlines, affine, shape=labels.shape, vox_size=labels_img.header.get_zooms()) """ Next let's try some probabilistic fiber tracking. For this, we'll be using the Constrained Spherical Deconvolution (CSD) Model. This model represents each voxel in the data set as a collection of small white matter fibers with different orientations. The density of fibers along each orientation is known as the Fiber Orientation Distribution (FOD). In order to perform probabilistic fiber tracking, we pick a fiber from the FOD at random at each new location along the streamline. Note: one could use this model to perform deterministic fiber tracking by always tracking along the directions that have the most fibers. Let's begin probabilistic fiber tracking by fitting the data to the CSD model. """
""" .. figure:: threshold_fa.png :align: center **Thresholded fractional anisotropy map.** """ all_streamlines_threshold_classifier = LocalTracking(dg, threshold_classifier, seeds, affine, step_size=.5, return_all=True) save_trk("deterministic_threshold_classifier_all.trk", all_streamlines_threshold_classifier, affine, labels.shape) streamlines = Streamlines(all_streamlines_threshold_classifier) if have_fury: window.clear(ren) ren.add(actor.line(streamlines, cmap.line_colors(streamlines))) window.record(ren, out_path='all_streamlines_threshold_classifier.png', size=(600, 600)) if interactive: window.show(ren) """ .. figure:: all_streamlines_threshold_classifier.png :align: center