def test_MaximumDeterministicTracker(): """This tests that the Maximum Deterministic Direction Getter plays nice LocalTracking and produces reasonable streamlines in a simple example. """ sphere = HemiSphere.from_sphere(unit_octahedron) # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing pmf_lookup = np.array([[0., 0., 1.], [1., 0., 0.], [0., 1., 0.], [.4, .6, 0.]]) simple_image = np.array([[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] pmf = pmf_lookup[simple_image] seeds = [np.array([1., 1., 0.])] * 30 mask = (simple_image > 0).astype(float) tc = ThresholdTissueClassifier(mask, .5) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 90, sphere) streamlines = LocalTracking(dg, tc, seeds, np.eye(4), 1.) expected = [np.array([[ 0., 1., 0.], [ 1., 1., 0.], [ 2., 1., 0.], [ 2., 2., 0.], [ 2., 3., 0.], [ 2., 4., 0.], [ 2., 5., 0.]]), np.array([[ 0., 1., 0.], [ 1., 1., 0.], [ 2., 1., 0.], [ 3., 1., 0.], [ 4., 1., 0.]]) ] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y) for sl in streamlines: dir = ( -sphere.vertices[0] ).copy() if not allclose(sl, expected[0]): raise AssertionError() # The first path is not possible if 90 degree turns are excluded dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 80, sphere) streamlines = LocalTracking(dg, tc, seeds, np.eye(4), 1.) for sl in streamlines: npt.assert_(np.allclose(sl, expected[1]))
def test_MaximumDeterministicTracker(): """This tests that the Maximum Deterministic Direction Getter plays nice LocalTracking and produces reasonable streamlines in a simple example. """ sphere = HemiSphere.from_sphere(unit_octahedron) # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing pmf_lookup = np.array([[0., 0., 1.], [1., 0., 0.], [0., 1., 0.], [.4, .6, 0.]]) simple_image = np.array([[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] pmf = pmf_lookup[simple_image] seeds = [np.array([1., 1., 0.])] * 30 mask = (simple_image > 0).astype(float) tc = ThresholdTissueClassifier(mask, .5) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 90, sphere) streamlines = LocalTracking(dg, tc, seeds, np.eye(4), 1.) expected = [np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [2., 2., 0.], [2., 3., 0.], [2., 4., 0.], [2., 5., 0.]]), np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [3., 1., 0.], [4., 1., 0.]])] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y) for sl in streamlines: if not allclose(sl, expected[0]): raise AssertionError() # The first path is not possible if 90 degree turns are excluded dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 80, sphere) streamlines = LocalTracking(dg, tc, seeds, np.eye(4), 1.) for sl in streamlines: npt.assert_(np.allclose(sl, expected[1]))
def _get_direction_getter(self, strategy_name, pam, pmf_threshold=0.1, max_angle=30.): """Get Tracking Direction Getter object. Parameters ---------- strategy_name: str string representing direction getter name Returns ------- direction_getter : instance of DirectionGetter Used to get directions for fiber tracking. """ dg, msg = None, '' if strategy_name.lower() in ["deterministic", "det"]: msg = "Deterministic" dg = DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["probabilistic", "prob"]: msg = "Probabilistic" dg = ProbabilisticDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["closestpeaks", "cp"]: msg = "ClosestPeaks" dg = ClosestPeakDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in [ "eudx", ]: msg = "Eudx" dg = pam else: msg = "No direction getter defined. Deterministic" dg = DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) logging.info('{0} direction getter strategy selected'.format(msg)) return dg
def _get_direction_getter(self, strategy_name, pam, pmf_threshold=0.1, max_angle=30.): """Get Tracking Direction Getter object. Parameters ---------- strategy_name: str string representing direction getter name Returns ------- direction_getter : instance of DirectionGetter Used to get directions for fiber tracking. """ dg, msg = None, '' if strategy_name.lower() in ["deterministic", "det"]: msg = "Deterministic" dg = DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["probabilistic", "prob"]: msg = "Probabilistic" dg = ProbabilisticDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["closestpeaks", "cp"]: msg = "ClosestPeaks" dg = ClosestPeakDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["eudx", ]: msg = "Eudx" dg = pam else: msg = "No direction getter defined. Deterministic" dg = DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) logging.info('{0} direction getter strategy selected'.format(msg)) return dg
def fiber_tracking(self): from dipy.data import default_sphere from dipy.direction import DeterministicMaximumDirectionGetter from dipy.tracking.streamline import Streamlines from dipy.tracking.local_tracking import ParticleFilteringTracking from Tractography.files_saving import save_ft self.create_model_fit() detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff( self.model_fit.shm_coeff, max_angle=self.parameters_dict['max_ang'], sphere=default_sphere) print(f"Tractography using PFT and {self.sc_method} clasifier") self.create_classifier() print('Starting to compute streamlines') self.streamlines = Streamlines( ParticleFilteringTracking( detmax_dg, self.classifier, self.seeds, self.affine, step_size=self.parameters_dict['step_size'], maxlen=self.parameters_dict['length_margins'][1], pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15, return_all=False)) self._remove_streamlines_outliers() file_name = f'wb_{self.ft_method}_{self.sc_method}.tck' save_ft(self.subj_folder, self.streamlines, self.nii_ref, file_name)
def tracking_maxodf(dir_src, dir_out, verbose=False): wm_name = 'wm_mask_' + par_b_tag + '_' + par_dim_tag + '.nii.gz' wm_mask, affine = load_nifti(pjoin(dir_src, wm_name), verbose) sh_name = 'sh_' + par_b_tag + '_' + par_dim_tag + '.nii.gz' sh, _ = load_nifti(pjoin(dir_src, sh_name), verbose) sphere = get_sphere('symmetric724') classifier = ThresholdTissueClassifier(wm_mask.astype('f8'), .5) classifier = BinaryTissueClassifier(wm_mask) max_dg = DeterministicMaximumDirectionGetter.from_shcoeff(sh, max_angle=par_trk_max_angle, sphere=sphere) seeds = utils.seeds_from_mask(wm_mask, density=2, affine=affine) streamlines = LocalTracking(max_dg, classifier, seeds, affine, step_size=par_trk_step_size) streamlines = list(streamlines) trk_name = 'tractogram_' + par_b_tag + '_' + par_dim_tag + '_' + par_trk_odf_tag + '.trk' trk_out = os.path.join(dir_out, trk_name) save_trk(trk_out, streamlines, affine, wm_mask.shape) dpy_out = trk_out.replace('.trk', '.dpy') dpy = Dpy(dpy_out, 'w') dpy.write_tracks(streamlines) dpy.close()
def _core_run(self, stopping_path, stopping_thr, seeding_path, seed_density, use_sh, pam, out_tract): stop, affine = load_nifti(stopping_path) classifier = ThresholdTissueClassifier(stop, stopping_thr) logging.info('classifier done') seed_mask, _ = load_nifti(seeding_path) seeds = \ utils.seeds_from_mask( seed_mask, density=[seed_density, seed_density, seed_density], affine=affine) logging.info('seeds done') direction_getter = pam if use_sh: direction_getter = \ DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, max_angle=30., sphere=pam.sphere) streamlines = LocalTracking(direction_getter, classifier, seeds, affine, step_size=.5) logging.info('LocalTracking initiated') tractogram = Tractogram(streamlines, affine_to_rasmm=np.eye(4)) save(tractogram, out_tract) logging.info('Saved {0}'.format(out_tract))
def create_streamlines(model_fit, seeds, affine, gtab=None, data=None, white_matter=None, classifier_type="fa"): from dipy.data import default_sphere from dipy.direction import DeterministicMaximumDirectionGetter from dipy.tracking.streamline import Streamlines from dipy.tracking.local_tracking import LocalTracking detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff( model_fit.shm_coeff, max_angle=30., sphere=default_sphere) if classifier_type == "fa": print("Tractography using local tracking and FA clasifier") classifier = create_fa_classifier(gtab, data, white_matter)[1] print('Starting to compute streamlines') streamlines = Streamlines( LocalTracking(detmax_dg, classifier, seeds, affine, step_size=1, return_all=False)) long_streamlines = np.ones((len(streamlines)), bool) for i in range(0, len(streamlines)): if streamlines[i].shape[0] < 100: long_streamlines[i] = False streamlines = streamlines[long_streamlines] return streamlines
def _core_run(self, stopping_path, stopping_thr, seeding_path, seed_density, use_sh, pam, out_tract): stop, affine = load_nifti(stopping_path) classifier = ThresholdTissueClassifier(stop, stopping_thr) logging.info('classifier done') seed_mask, _ = load_nifti(seeding_path) seeds = \ utils.seeds_from_mask( seed_mask, density=[seed_density, seed_density, seed_density], affine=affine) logging.info('seeds done') direction_getter = pam if use_sh: direction_getter = \ DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, max_angle=30., sphere=pam.sphere) streamlines = LocalTracking(direction_getter, classifier, seeds, affine, step_size=.5) logging.info('LocalTracking initiated') tractogram = Tractogram(streamlines, affine_to_rasmm=np.eye(4)) save(tractogram, out_tract) logging.info('Saved {0}'.format(out_tract))
def test_DeterministicMaximumDirectionGetter(): # Test the DeterministicMaximumDirectionGetter dir = unit_octahedron.vertices[-1].copy() point = np.zeros(3) N = unit_octahedron.theta.shape[0] # No valid direction pmf = np.zeros((3, 3, 3, N)) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 90, unit_octahedron) state = dg.get_direction(point, dir) npt.assert_equal(state, 1) # Test BF #1566 - bad condition in DeterministicMaximumDirectionGetter pmf = np.zeros((3, 3, 3, N)) pmf[0, 0, 0, 0] = 1 dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 0, unit_octahedron) state = dg.get_direction(point, dir) npt.assert_equal(state, 1)
def _get_direction_getter(self, strategy_name, pam, pmf_threshold, max_angle): """Get Tracking Direction Getter object. Parameters ---------- strategy_name : str String representing direction getter name. pam : instance of PeaksAndMetrics An object with ``gfa``, ``peak_directions``, ``peak_values``, ``peak_indices``, ``odf``, ``shm_coeffs`` as attributes. pmf_threshold : float Threshold for ODF functions. max_angle : float Maximum angle between streamline segments. Returns ------- direction_getter : instance of DirectionGetter Used to get directions for fiber tracking. """ dg, msg = None, '' if strategy_name.lower() in ["deterministic", "det"]: msg = "Deterministic" dg = DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["probabilistic", "prob"]: msg = "Probabilistic" dg = ProbabilisticDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["closestpeaks", "cp"]: msg = "ClosestPeaks" dg = ClosestPeakDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in [ "eudx", ]: msg = "Eudx" dg = pam else: msg = "No direction getter defined. Eudx" dg = pam logging.info('{0} direction getter strategy selected'.format(msg)) return dg
def _get_direction_getter(self, strategy_name, pam, pmf_threshold, max_angle): """Get Tracking Direction Getter object. Parameters ---------- strategy_name: str String representing direction getter name. pam: instance of PeaksAndMetrics An object with ``gfa``, ``peak_directions``, ``peak_values``, ``peak_indices``, ``odf``, ``shm_coeffs`` as attributes. pmf_threshold : float Threshold for ODF functions. max_angle : float Maximum angle between streamline segments. Returns ------- direction_getter : instance of DirectionGetter Used to get directions for fiber tracking. """ dg, msg = None, '' if strategy_name.lower() in ["deterministic", "det"]: msg = "Deterministic" dg = DeterministicMaximumDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["probabilistic", "prob"]: msg = "Probabilistic" dg = ProbabilisticDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["closestpeaks", "cp"]: msg = "ClosestPeaks" dg = ClosestPeakDirectionGetter.from_shcoeff( pam.shm_coeff, sphere=pam.sphere, max_angle=max_angle, pmf_threshold=pmf_threshold) elif strategy_name.lower() in ["eudx", ]: msg = "Eudx" dg = pam else: msg = "No direction getter defined. Eudx" dg = pam logging.info('{0} direction getter strategy selected'.format(msg)) return dg
def test_DeterministicMaximumDirectionGetter(): # Test the DeterministicMaximumDirectionGetter dir = unit_octahedron.vertices[-1].copy() point = np.zeros(3) N = unit_octahedron.theta.shape[0] # No valid direction pmf = np.zeros((3, 3, 3, N)) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 90, unit_octahedron) state = dg.get_direction(point, dir) npt.assert_equal(state, 1) # Test BF #1566 - bad condition in DeterministicMaximumDirectionGetter pmf = np.zeros((3, 3, 3, N)) pmf[0, 0, 0, 0] = 1 dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 0, unit_octahedron) state = dg.get_direction(point, dir) npt.assert_equal(state, 1)
def get_dti_streamlines(data_container, random_seeds=False, seeds_count=30000, seeds_per_voxel=False, step_width=1.0, max_angle=30.0, fa_threshold=0.15): """ Tracks and returns CSD Streamlines for the given DataContainer. Parameters ---------- data_container The DataContainer we would like to track streamlines on random_seeds A boolean indicating whether we would like to use random seeds seeds_count If we use random seeds, this specifies the seed count seeds_per_voxel If True, the seed count is specified per voxel step_width The step width used while tracking fa_threshold The FA threshold to use to stop tracking max_angle The maximum allowed angle between incoming and outgoing angle, float between 0.0 and 90.0 deg Returns ------- Streamlines A list of Streamlines """ seeds = _get_seeds(data_container, random_seeds, seeds_count, seeds_per_voxel) dti_fit = TensorModel(data_container.gtab).fit( data_container.dwi, mask=data_container.binary_mask) dti_fit_odf = dti_fit.odf(sphere=default_sphere) direction_getter = DeterministicMaximumDirectionGetter.from_pmf( dti_fit_odf, max_angle=max_angle, sphere=default_sphere) classifier = ThresholdStoppingCriterion(dti_fit.fa, fa_threshold) streamlines_generator = LocalTracking(direction_getter, classifier, seeds, data_container.aff, step_size=step_width) streamlines = Streamlines(streamlines_generator) return streamlines
def track(self): SeedBasedTracker.track(self) if self.streamlines is not None: return dti_model = TensorModel(self.data.gtab) dti_fit = dti_model.fit(self.data.dwi, mask=self.data.binarymask) dti_fit_odf = dti_fit.odf(sphere=default_sphere) max_angle = Config.get_config().getfloat("DTITracking", "maxAngle", fallback="30.0") direction_getter = DeterministicMaximumDirectionGetter.from_pmf(dti_fit_odf, max_angle=max_angle, sphere=default_sphere) self._track(ThresholdStoppingCriterion(dti_fit.fa, self.options.fa_threshold), direction_getter) Cache.get_cache().set(self.id, self.streamlines)
def tracking_maxodf(dir_src, dir_out, verbose=False): wm_name = 'wm_mask_' + par_b_tag + '_' + par_dim_tag + '.nii.gz' wm_mask, affine = load_nifti(pjoin(dir_src, wm_name), verbose) sh_name = 'sh_' + par_b_tag + '_' + par_dim_tag + '.nii.gz' sh, _ = load_nifti(pjoin(dir_src, sh_name), verbose) sphere = get_sphere('symmetric724') classifier = ThresholdTissueClassifier(wm_mask.astype('f8'), .5) classifier = BinaryTissueClassifier(wm_mask) max_dg = DeterministicMaximumDirectionGetter.from_shcoeff(sh, max_angle=par_trk_max_angle, sphere=sphere) seeds = utils.seeds_from_mask(wm_mask, density=2, affine=affine) streamlines = LocalTracking(max_dg, classifier, seeds, affine, step_size=par_trk_step_size) streamlines = list(streamlines) trk_name = 'tractogram_' + par_b_tag + '_' + par_dim_tag + '_' + par_trk_odf_tag + '.trk' save_trk(pjoin(dir_out, trk_name), streamlines, affine, wm_mask.shape)
def test_num_sls(): toydict = uniform_toy_data() csd_model = ConstrainedSphericalDeconvModel(toydict['gtab'], None, sh_order=6) csd_fit = csd_model.fit(toydict['toy_data']) sltest_list = [('toy_roi_long_plane', 121), ('toy_roi_radial_plane', 121), ('toy_roi_center_vox', 1)] classifier = ThresholdTissueClassifier(toydict['toy_tissue_classifier'], .1) detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) expected_sl_length = 11 for roi, num_sl in sltest_list: seed = utils.seeds_from_mask(toydict[roi]) streamlines = LocalTracking(detmax_dg, classifier, seed, toydict['toy_affine'], step_size=1) streamlines = list(streamlines) npt.assert_equal(len(streamlines), num_sl) for sl in streamlines: npt.assert_equal(len(sl), expected_sl_length)
def create_streamlines(csd_fit, classifier, seeds, affine): from dipy.data import default_sphere from dipy.direction import DeterministicMaximumDirectionGetter from dipy.tracking.streamline import Streamlines detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff( csd_fit.shm_coeff, max_angle=30.0, sphere=default_sphere) streamlines = Streamlines( LocalTracking(detmax_dg, classifier, seeds, affine, step_size=1, return_all=False)) long_streamlines = np.ones((len(streamlines)), bool) for i in range(0, len(streamlines)): if streamlines[i].shape[0] < 100: long_streamlines[i] = False streamlines = streamlines[long_streamlines] return streamlines
def test_maximum_deterministic_tracker(): """This tests that the Maximum Deterministic Direction Getter plays nice LocalTracking and produces reasonable streamlines in a simple example. """ sphere = HemiSphere.from_sphere(unit_octahedron) # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing pmf_lookup = np.array([[0., 0., 1.], [1., 0., 0.], [0., 1., 0.], [.4, .6, 0.]]) simple_image = np.array([ [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] pmf = pmf_lookup[simple_image] seeds = [np.array([1., 1., 0.])] * 30 mask = (simple_image > 0).astype(float) sc = ThresholdStoppingCriterion(mask, .5) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 90, sphere, pmf_threshold=0.1) streamlines = LocalTracking(dg, sc, seeds, np.eye(4), 1.) expected = [ np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [2., 2., 0.], [2., 3., 0.], [2., 4., 0.]]), np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [3., 1., 0.], [4., 1., 0.]]), np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.]]) ] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y) for sl in streamlines: if not allclose(sl, expected[0]): raise AssertionError() # The first path is not possible if 90 degree turns are excluded dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 80, sphere, pmf_threshold=0.1) streamlines = LocalTracking(dg, sc, seeds, np.eye(4), 1.) for sl in streamlines: npt.assert_(np.allclose(sl, expected[1])) # Both path are not possible if 90 degree turns are exclude and # if pmf_threshold is larger than 0.67. Streamlines should stop at # the crossing. # 0.4/0.6 < 2/3, multiplying the pmf should not change the ratio dg = DeterministicMaximumDirectionGetter.from_pmf(10 * pmf, 80, sphere, pmf_threshold=0.67) streamlines = LocalTracking(dg, sc, seeds, np.eye(4), 1.) for sl in streamlines: npt.assert_(np.allclose(sl, expected[2]))
_, _, img_pve_wm = read_stanford_pve_maps() data = hardi_img.get_data() labels = labels_img.get_data() affine = hardi_img.get_affine() white_matter = img_pve_wm.get_data() seed_mask = np.logical_and(labels == 2, white_matter == 1) seeds = utils.seeds_from_mask(seed_mask, density=2, affine=affine) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd_model.fit(data, mask=white_matter) dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) """ Threshold Tissue Classifier --------------------------- A scalar map can be used to define where the tracking stops. The threshold tissue classifier uses a scalar map to stop the tracking whenever the interpolated scalar value is lower than a fixed threshold. Here, we show an example using the fractional anisotropy (FA) map of the DTI model. The threshold tissue classifier uses a trilinear interpolation at the tracking position. **Parameters** - metric_map: numpy array [:, :, :]
def track_ensemble(target_samples, atlas_data_wm_gm_int, parcels, parcel_vec, mod_fit, tiss_classifier, sphere, directget, curv_thr_list, step_list, track_type, maxcrossing, max_length, n_seeds_per_iter=200): from colorama import Fore, Style from dipy.tracking import utils from dipy.tracking.streamline import Streamlines, select_by_rois from dipy.tracking.local import LocalTracking, ParticleFilteringTracking from dipy.direction import ProbabilisticDirectionGetter, BootDirectionGetter, ClosestPeakDirectionGetter, DeterministicMaximumDirectionGetter # Commence Ensemble Tractography streamlines = nib.streamlines.array_sequence.ArraySequence() ix = 0 circuit_ix = 0 stream_counter = 0 while int(stream_counter) < int(target_samples): for curv_thr in curv_thr_list: print("%s%s" % ('Curvature: ', curv_thr)) # Instantiate DirectionGetter if directget == 'prob': dg = ProbabilisticDirectionGetter.from_shcoeff(mod_fit, max_angle=float(curv_thr), sphere=sphere) elif directget == 'boot': dg = BootDirectionGetter.from_shcoeff(mod_fit, max_angle=float(curv_thr), sphere=sphere) elif directget == 'closest': dg = ClosestPeakDirectionGetter.from_shcoeff(mod_fit, max_angle=float(curv_thr), sphere=sphere) elif directget == 'det': dg = DeterministicMaximumDirectionGetter.from_shcoeff(mod_fit, max_angle=float(curv_thr), sphere=sphere) else: raise ValueError('ERROR: No valid direction getter(s) specified.') for step in step_list: print("%s%s" % ('Step: ', step)) # Perform wm-gm interface seeding, using n_seeds at a time seeds = utils.random_seeds_from_mask(atlas_data_wm_gm_int > 0, seeds_count=n_seeds_per_iter, seed_count_per_voxel=False, affine=np.eye(4)) if len(seeds) == 0: raise RuntimeWarning('Warning: No valid seed points found in wm-gm interface...') print(seeds) # Perform tracking if track_type == 'local': streamline_generator = LocalTracking(dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), maxlen=int(max_length), step_size=float(step), return_all=True) elif track_type == 'particle': streamline_generator = ParticleFilteringTracking(dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), step_size=float(step), maxlen=int(max_length), pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15, return_all=True) else: raise ValueError('ERROR: No valid tracking method(s) specified.') # Filter resulting streamlines by roi-intersection characteristics streamlines_more = Streamlines(select_by_rois(streamline_generator, parcels, parcel_vec.astype('bool'), mode='any', affine=np.eye(4), tol=8)) # Repeat process until target samples condition is met ix = ix + 1 for s in streamlines_more: stream_counter = stream_counter + len(s) streamlines.append(s) if int(stream_counter) >= int(target_samples): break else: continue circuit_ix = circuit_ix + 1 print("%s%s%s%s%s" % ('Completed hyperparameter circuit: ', circuit_ix, '...\nCumulative Streamline Count: ', Fore.CYAN, stream_counter)) print(Style.RESET_ALL) print('\n') return streamlines
def test_maximum_deterministic_tracker(): """This tests that the Maximum Deterministic Direction Getter plays nice LocalTracking and produces reasonable streamlines in a simple example. """ sphere = HemiSphere.from_sphere(unit_octahedron) # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing pmf_lookup = np.array([[0., 0., 1.], [1., 0., 0.], [0., 1., 0.], [.4, .6, 0.]]) simple_image = np.array([[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] pmf = pmf_lookup[simple_image] seeds = [np.array([1., 1., 0.])] * 30 mask = (simple_image > 0).astype(float) tc = ThresholdTissueClassifier(mask, .5) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 90, sphere, pmf_threshold=0.1) streamlines = LocalTracking(dg, tc, seeds, np.eye(4), 1.) expected = [np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [2., 2., 0.], [2., 3., 0.], [2., 4., 0.]]), np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [3., 1., 0.], [4., 1., 0.]]), np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.]])] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y) for sl in streamlines: if not allclose(sl, expected[0]): raise AssertionError() # The first path is not possible if 90 degree turns are excluded dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 80, sphere, pmf_threshold=0.1) streamlines = LocalTracking(dg, tc, seeds, np.eye(4), 1.) for sl in streamlines: npt.assert_(np.allclose(sl, expected[1])) # Both path are not possible if 90 degree turns are exclude and # if pmf_threshold is larger than 0.67. Streamlines should stop at # the crossing. # 0.4/0.6 < 2/3, multiplying the pmf should not change the ratio dg = DeterministicMaximumDirectionGetter.from_pmf(10*pmf, 80, sphere, pmf_threshold=0.67) streamlines = LocalTracking(dg, tc, seeds, np.eye(4), 1.) for sl in streamlines: npt.assert_(np.allclose(sl, expected[2]))
def determine(name=None, data_path=None, output_path='.', Threshold=.20, data_list=None, seed='.', minus_ROI_mask='.', one_node=False, two_node=False): time0 = time.time() print("begin loading data, time:", time.time() - time0) if data_list == None: data, affine, img, labels, gtab, head_mask = get_data(name, data_path) else: data = data_list['DWI'] affine = data_list['affine'] img = data_list['img'] labels = data_list['labels'] gtab = data_list['gtab'] head_mask = data_list['head_mask'] print(type(seed)) if type(seed) != str: seed_mask = seed else: seed_mask = (labels == 2) * (head_mask == 1) white_matter = (labels == 2) * (head_mask == 1) seeds = utils.seeds_from_mask(seed_mask, affine, density=1) print("begin reconstruction, time:", time.time() - time0) response, ratio = auto_response_ssst(gtab, data, roi_radii=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) csa_model = CsaOdfModel(gtab, sh_order=6) gfa = csa_model.fit(data, mask=white_matter).gfa stopping_criterion = ThresholdStoppingCriterion(gfa, Threshold) #from dipy.data import small_sphere print("begin tracking, time:", time.time() - time0) 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, img, Space.RASMM) if one_node or two_node: sft.to_vox() streamlines = reduct_seed_ROI(sft.streamlines, seed_mask, one_node, two_node) if type(minus_ROI_mask) != str: streamlines = minus_ROI(streamlines=streamlines, ROI=minus_ROI_mask) sft = StatefulTractogram(streamlines, img, Space.VOX) sft._vox_to_rasmm() print("begin saving, time:", time.time() - time0) output = output_path + '/tractogram_deterministic_' + name + '.trk' save_trk(sft, output) print("finished, time:", time.time() - time0)
def _run_interface(self, runtime): import numpy as np import nibabel as nib from dipy.io import read_bvals_bvecs from dipy.core.gradients import gradient_table from nipype.utils.filemanip import split_filename # Loading the data fname = self.inputs.in_file img = nib.load(fname) data = img.get_data() affine = img.get_affine() FA_fname = self.inputs.FA_file FA_img = nib.load(FA_fname) fa = FA_img.get_data() affine = FA_img.get_affine() affine = np.matrix.round(affine) mask_fname = self.inputs.brain_mask mask_img = nib.load(mask_fname) mask = mask_img.get_data() bval_fname = self.inputs.bval bvals = np.loadtxt(bval_fname) bvec_fname = self.inputs.bvec bvecs = np.loadtxt(bvec_fname) bvecs = np.vstack([bvecs[0,:],bvecs[1,:],bvecs[2,:]]).T gtab = gradient_table(bvals, bvecs) # Creating a white matter mask fa = fa*mask white_matter = fa >= 0.2 # Creating a seed mask from dipy.tracking import utils seeds = utils.seeds_from_mask(white_matter, density=[2, 2, 2], affine=affine) # Fitting the CSA model from dipy.reconst.shm import CsaOdfModel from dipy.data import default_sphere from dipy.direction import peaks_from_model csa_model = CsaOdfModel(gtab, sh_order=8) csa_peaks = peaks_from_model(csa_model, data, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=white_matter) from dipy.tracking.local import ThresholdTissueClassifier classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) # CSD model from dipy.reconst.csdeconv import (ConstrainedSphericalDeconvModel, auto_response) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) csd_fit = csd_model.fit(data, mask=white_matter) from dipy.direction import DeterministicMaximumDirectionGetter det_dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=45., sphere=default_sphere) # Tracking from dipy.tracking.local import LocalTracking streamlines = LocalTracking(det_dg, classifier, seeds, affine, step_size=.5, maxlen=200, max_cross=1) # Compute streamlines and store as a list. streamlines = list(streamlines) # Saving the trackfile from dipy.io.trackvis import save_trk _, base, _ = split_filename(fname) save_trk(base + '_CSDdet.trk', streamlines, affine, fa.shape) return runtime
def track_ensemble(target_samples, atlas_data_wm_gm_int, parcels, mod_fit, tiss_classifier, sphere, directget, curv_thr_list, step_list, track_type, maxcrossing, roi_neighborhood_tol, min_length, waymask, B0_mask, max_length=1000, n_seeds_per_iter=500, pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15, min_separation_angle=20): """ Perform native-space ensemble tractography, restricted to a vector of ROI masks. target_samples : int Total number of streamline samples specified to generate streams. atlas_data_wm_gm_int : array 3D int32 numpy array of atlas parcellation intensities from Nifti1Image in T1w-warped native diffusion space, restricted to wm-gm interface. parcels : list List of 3D boolean numpy arrays of atlas parcellation ROI masks from a Nifti1Image in T1w-warped native diffusion space. mod : obj Connectivity reconstruction model. tiss_classifier : str Tissue classification method. sphere : obj DiPy object for modeling diffusion directions on a sphere. directget : str The statistical approach to tracking. Options are: det (deterministic), closest (clos), boot (bootstrapped), and prob (probabilistic). curv_thr_list : list List of integer curvature thresholds used to perform ensemble tracking. step_list : list List of float step-sizes used to perform ensemble tracking. track_type : str Tracking algorithm used (e.g. 'local' or 'particle'). maxcrossing : int Maximum number if diffusion directions that can be assumed per voxel while tracking. roi_neighborhood_tol : float Distance (in the units of the streamlines, usually mm). If any coordinate in the streamline is within this distance from the center of any voxel in the ROI, the filtering criterion is set to True for this streamline, otherwise False. Defaults to the distance between the center of each voxel and the corner of the voxel. min_length : int Minimum fiber length threshold in mm. waymask : str Path to a Nifti1Image in native diffusion space to constrain tractography. B0_mask : str File path to B0 brain mask. max_length : int Maximum number of steps to restrict tracking. n_seeds_per_iter : int Number of seeds from which to initiate tracking for each unique ensemble combination. By default this is set to 200. particle_count pft_back_tracking_dist : float Distance in mm to back track before starting the particle filtering tractography. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 2 mm. pft_front_tracking_dist : float Distance in mm to run the particle filtering tractography after the the back track distance. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 1 mm. particle_count : int Number of particles to use in the particle filter. min_separation_angle : float The minimum angle between directions [0, 90]. Returns ------- streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. References ---------- .. [1] Takemura, H., Caiafa, C. F., Wandell, B. A., & Pestilli, F. (2016). Ensemble Tractography. PLoS Computational Biology. https://doi.org/10.1371/journal.pcbi.1004692 """ import gc import time from colorama import Fore, Style from dipy.tracking import utils from dipy.tracking.streamline import Streamlines, select_by_rois from dipy.tracking.local_tracking import LocalTracking, ParticleFilteringTracking from dipy.direction import (ProbabilisticDirectionGetter, ClosestPeakDirectionGetter, DeterministicMaximumDirectionGetter) start = time.time() B0_mask_data = nib.load(B0_mask).get_fdata() if waymask: waymask_data = np.asarray(nib.load(waymask).dataobj).astype('bool') # Commence Ensemble Tractography parcel_vec = list(np.ones(len(parcels)).astype('bool')) streamlines = nib.streamlines.array_sequence.ArraySequence() circuit_ix = 0 stream_counter = 0 while int(stream_counter) < int(target_samples): for curv_thr in curv_thr_list: print("%s%s" % ('Curvature: ', curv_thr)) # Instantiate DirectionGetter if directget == 'prob': dg = ProbabilisticDirectionGetter.from_shcoeff(mod_fit, max_angle=float(curv_thr), sphere=sphere, min_separation_angle=min_separation_angle) elif directget == 'clos': dg = ClosestPeakDirectionGetter.from_shcoeff(mod_fit, max_angle=float(curv_thr), sphere=sphere, min_separation_angle=min_separation_angle) elif directget == 'det': dg = DeterministicMaximumDirectionGetter.from_shcoeff(mod_fit, max_angle=float(curv_thr), sphere=sphere, min_separation_angle=min_separation_angle) else: raise ValueError('ERROR: No valid direction getter(s) specified.') for step in step_list: print("%s%s" % ('Step: ', step)) # Perform wm-gm interface seeding, using n_seeds at a time seeds = utils.random_seeds_from_mask(atlas_data_wm_gm_int > 0, seeds_count=n_seeds_per_iter, seed_count_per_voxel=False, affine=np.eye(4)) if len(seeds) == 0: raise RuntimeWarning('Warning: No valid seed points found in wm-gm interface...') # print(seeds) # Perform tracking if track_type == 'local': streamline_generator = LocalTracking(dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), maxlen=int(max_length), step_size=float(step), fixedstep=False, return_all=True) elif track_type == 'particle': streamline_generator = ParticleFilteringTracking(dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), step_size=float(step), maxlen=int(max_length), pft_back_tracking_dist=pft_back_tracking_dist, pft_front_tracking_dist=pft_front_tracking_dist, particle_count=particle_count, return_all=True) else: raise ValueError('ERROR: No valid tracking method(s) specified.') # Filter resulting streamlines by those that stay entirely inside the brain roi_proximal_streamlines = utils.target(streamline_generator, np.eye(4), B0_mask_data, include=True) # Filter resulting streamlines by roi-intersection characteristics roi_proximal_streamlines = Streamlines(select_by_rois(roi_proximal_streamlines, affine=np.eye(4), rois=parcels, include=parcel_vec, mode='both_end', tol=roi_neighborhood_tol)) print("%s%s" % ('Filtering by: \nnode intersection: ', len(roi_proximal_streamlines))) if str(min_length) != '0': roi_proximal_streamlines = nib.streamlines.array_sequence.ArraySequence([s for s in roi_proximal_streamlines if len(s) >= float(min_length)]) print("%s%s" % ('Minimum length criterion: ', len(roi_proximal_streamlines))) if waymask: roi_proximal_streamlines = roi_proximal_streamlines[utils.near_roi(roi_proximal_streamlines, np.eye(4), waymask_data, tol=roi_neighborhood_tol, mode='any')] print("%s%s" % ('Waymask proximity: ', len(roi_proximal_streamlines))) out_streams = [s.astype('float32') for s in roi_proximal_streamlines] streamlines.extend(out_streams) stream_counter = stream_counter + len(out_streams) # Cleanup memory del seeds, roi_proximal_streamlines, streamline_generator, out_streams gc.collect() del dg circuit_ix = circuit_ix + 1 print("%s%s%s%s%s%s" % ('Completed Hyperparameter Circuit: ', circuit_ix, '\nCumulative Streamline Count: ', Fore.CYAN, stream_counter, "\n")) print(Style.RESET_ALL) print('Tracking Complete:\n', str(time.time() - start)) return streamlines
def run_tracking(step_curv_combinations, recon_shelved, n_seeds_per_iter, traversal, maxcrossing, max_length, pft_back_tracking_dist, pft_front_tracking_dist, particle_count, roi_neighborhood_tol, min_length, track_type, min_separation_angle, sphere, tiss_class, tissue_shelved, verbose=False): """ Create a density map of the list of streamlines. Parameters ---------- step_curv_combinations : list List of tuples representing all pair combinations of step sizes and curvature thresholds from which to sample streamlines. recon_path : str File path to diffusion reconstruction model. n_seeds_per_iter : int Number of seeds from which to initiate tracking for each unique ensemble combination. By default this is set to 250. directget : str The statistical approach to tracking. Options are: det (deterministic), closest (clos), boot (bootstrapped), and prob (probabilistic). maxcrossing : int Maximum number if diffusion directions that can be assumed per voxel while tracking. max_length : int Maximum number of steps to restrict tracking. pft_back_tracking_dist : float Distance in mm to back track before starting the particle filtering tractography. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 2 mm. pft_front_tracking_dist : float Distance in mm to run the particle filtering tractography after the the back track distance. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 1 mm. particle_count : int Number of particles to use in the particle filter. roi_neighborhood_tol : float Distance (in the units of the streamlines, usually mm). If any coordinate in the streamline is within this distance from the center of any voxel in the ROI, the filtering criterion is set to True for this streamline, otherwise False. Defaults to the distance between the center of each voxel and the corner of the voxel. waymask_data : ndarray Tractography constraint mask array in native diffusion space. min_length : int Minimum fiber length threshold in mm to restrict tracking. track_type : str Tracking algorithm used (e.g. 'local' or 'particle'). min_separation_angle : float The minimum angle between directions [0, 90]. sphere : obj DiPy object for modeling diffusion directions on a sphere. tiss_class : str Tissue classification method. tissue_shelved : str File path to joblib-shelved 4D T1w tissue segmentations in native diffusion space. Returns ------- streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. """ import gc import time import numpy as np from dipy.tracking import utils from dipy.tracking.streamline import select_by_rois from dipy.tracking.local_tracking import LocalTracking, \ ParticleFilteringTracking from dipy.direction import (ProbabilisticDirectionGetter, ClosestPeakDirectionGetter, DeterministicMaximumDirectionGetter) from nilearn.image import index_img, math_img from pynets.dmri.utils import generate_seeds, random_seeds_from_mask from nibabel.streamlines.array_sequence import ArraySequence start_time = time.time() if verbose is True: print("%s%s%s" % ('Preparing tissue constraints:', np.round(time.time() - start_time, 1), 's')) start_time = time.time() tissue_img = tissue_shelved.get() # Order: B0_mask = index_img(tissue_img, 0) atlas_img = index_img(tissue_img, 1) t1w2dwi = index_img(tissue_img, 3) gm_in_dwi = index_img(tissue_img, 4) vent_csf_in_dwi = index_img(tissue_img, 5) wm_in_dwi = index_img(tissue_img, 6) tissue_img.uncache() tiss_classifier = prep_tissues(t1w2dwi, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi, tiss_class, B0_mask) # if verbose is True: # print("%s%s%s" % ( # 'Fitting tissue classifier:', # np.round(time.time() - start_time, 1), 's')) # start_time = time.time() if verbose is True: print("%s%s%s" % ('Loading reconstruction:', np.round(time.time() - start_time, 1), 's')) start_time = time.time() print("%s%s" % ("Curvature: ", step_curv_combinations[1])) # Instantiate DirectionGetter if traversal.lower() in ["probabilistic", "prob"]: dg = ProbabilisticDirectionGetter.from_shcoeff( recon_shelved.get(), max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) elif traversal.lower() in ["closestpeaks", "cp"]: dg = ClosestPeakDirectionGetter.from_shcoeff( recon_shelved.get(), max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) elif traversal.lower() in ["deterministic", "det"]: maxcrossing = 1 dg = DeterministicMaximumDirectionGetter.from_shcoeff( recon_shelved.get(), max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) else: raise ValueError("ERROR: No valid direction getter(s) specified.") if verbose is True: print("%s%s%s" % ('Extracting directions:', np.round(time.time() - start_time, 1), 's')) start_time = time.time() print("%s%s" % ("Step: ", step_curv_combinations[0])) # Perform wm-gm interface seeding, using n_seeds at a time seeds = generate_seeds( random_seeds_from_mask(np.asarray( math_img("img > 0.01", img=index_img( tissue_img, 2)).dataobj).astype("bool").astype("int16") > 0, seeds_count=n_seeds_per_iter, random_seed=42)) if verbose is True: print("%s%s%s" % ('Drawing random seeds:', np.round(time.time() - start_time, 1), 's')) start_time = time.time() # print(seeds) # Perform tracking if track_type == "local": streamline_generator = LocalTracking(dg, tiss_classifier, np.stack([i for i in seeds]), np.eye(4), max_cross=int(maxcrossing), maxlen=int(max_length), step_size=float( step_curv_combinations[0]), fixedstep=False, return_all=True, random_seed=42) elif track_type == "particle": streamline_generator = ParticleFilteringTracking( dg, tiss_classifier, np.stack([i for i in seeds]), np.eye(4), max_cross=int(maxcrossing), step_size=float(step_curv_combinations[0]), maxlen=int(max_length), pft_back_tracking_dist=pft_back_tracking_dist, pft_front_tracking_dist=pft_front_tracking_dist, pft_max_trial=20, particle_count=particle_count, return_all=True, random_seed=42) else: raise ValueError("ERROR: No valid tracking method(s) specified.") if verbose is True: print("%s%s%s" % ('Instantiating tracking:', np.round(time.time() - start_time, 1), 's')) start_time = time.time() # print(seeds) del dg # Filter resulting streamlines by those that stay entirely # inside the brain try: roi_proximal_streamlines = utils.target( streamline_generator, np.eye(4), np.asarray(B0_mask.dataobj).astype('bool'), include=True) except BaseException: print('No streamlines found inside the brain! ' 'Check registrations.') #return None if verbose is True: print("%s%s%s" % ('Drawing streamlines:', np.round(time.time() - start_time, 1), 's')) start_time = time.time() del seeds, tiss_classifier, streamline_generator B0_mask.uncache() atlas_img.uncache() t1w2dwi.uncache() gm_in_dwi.uncache() vent_csf_in_dwi.uncache() wm_in_dwi.uncache() gc.collect() # Filter resulting streamlines by roi-intersection # characteristics atlas_data = np.array(atlas_img.dataobj).astype("uint16") # Build mask vector from atlas for later roi filtering parcels = [ atlas_data == roi_val for roi_val in [i for i in np.unique(atlas_data) if i != 0] ] try: roi_proximal_streamlines = \ select_by_rois( roi_proximal_streamlines, affine=np.eye(4), rois=parcels, include=list(np.ones(len(parcels)).astype("bool")), mode="any", tol=roi_neighborhood_tol, ) except BaseException: print('No streamlines found to connect any parcels! ' 'Check registrations.') #return None del atlas_data if verbose is True: print("%s%s%s" % ('Selecting by parcellation:', np.round(time.time() - start_time, 1), 's')) start_time = time.time() del parcels gc.collect() if verbose is True: print("%s%s%s" % ('Selecting by minimum length criterion:', np.round(time.time() - start_time, 1), 's')) gc.collect() return ArraySequence([ s.astype("float32") for s in roi_proximal_streamlines if len(s) > float(min_length) ])
def run_tracking(step_curv_combinations, recon_path, n_seeds_per_iter, directget, maxcrossing, max_length, pft_back_tracking_dist, pft_front_tracking_dist, particle_count, roi_neighborhood_tol, waymask, min_length, track_type, min_separation_angle, sphere, tiss_class, tissues4d, cache_dir, min_seeds=100): import gc import os import h5py from dipy.tracking import utils from dipy.tracking.streamline import select_by_rois from dipy.tracking.local_tracking import LocalTracking, \ ParticleFilteringTracking from dipy.direction import (ProbabilisticDirectionGetter, ClosestPeakDirectionGetter, DeterministicMaximumDirectionGetter) from nilearn.image import index_img from pynets.dmri.track import prep_tissues from nibabel.streamlines.array_sequence import ArraySequence from nipype.utils.filemanip import copyfile, fname_presuffix import uuid from time import strftime run_uuid = f"{strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4()}" recon_path_tmp_path = fname_presuffix( recon_path, suffix=f"_{'_'.join([str(i) for i in step_curv_combinations])}_" f"{run_uuid}", newpath=cache_dir) copyfile(recon_path, recon_path_tmp_path, copy=True, use_hardlink=False) tissues4d_tmp_path = fname_presuffix( tissues4d, suffix=f"_{'_'.join([str(i) for i in step_curv_combinations])}_" f"{run_uuid}", newpath=cache_dir) copyfile(tissues4d, tissues4d_tmp_path, copy=True, use_hardlink=False) if waymask is not None: waymask_tmp_path = fname_presuffix( waymask, suffix=f"_{'_'.join([str(i) for i in step_curv_combinations])}_" f"{run_uuid}", newpath=cache_dir) copyfile(waymask, waymask_tmp_path, copy=True, use_hardlink=False) else: waymask_tmp_path = None tissue_img = nib.load(tissues4d_tmp_path) # Order: B0_mask = index_img(tissue_img, 0) atlas_img = index_img(tissue_img, 1) seeding_mask = index_img(tissue_img, 2) t1w2dwi = index_img(tissue_img, 3) gm_in_dwi = index_img(tissue_img, 4) vent_csf_in_dwi = index_img(tissue_img, 5) wm_in_dwi = index_img(tissue_img, 6) tiss_classifier = prep_tissues(t1w2dwi, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi, tiss_class, B0_mask) B0_mask_data = np.asarray(B0_mask.dataobj).astype("bool") seeding_mask = np.asarray( seeding_mask.dataobj).astype("bool").astype("int16") with h5py.File(recon_path_tmp_path, 'r+') as hf: mod_fit = hf['reconstruction'][:].astype('float32') print("%s%s" % ("Curvature: ", step_curv_combinations[1])) # Instantiate DirectionGetter if directget.lower() in ["probabilistic", "prob"]: dg = ProbabilisticDirectionGetter.from_shcoeff( mod_fit, max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) elif directget.lower() in ["closestpeaks", "cp"]: dg = ClosestPeakDirectionGetter.from_shcoeff( mod_fit, max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) elif directget.lower() in ["deterministic", "det"]: maxcrossing = 1 dg = DeterministicMaximumDirectionGetter.from_shcoeff( mod_fit, max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) else: raise ValueError("ERROR: No valid direction getter(s) specified.") print("%s%s" % ("Step: ", step_curv_combinations[0])) # Perform wm-gm interface seeding, using n_seeds at a time seeds = utils.random_seeds_from_mask( seeding_mask > 0, seeds_count=n_seeds_per_iter, seed_count_per_voxel=False, affine=np.eye(4), ) if len(seeds) < min_seeds: print( UserWarning( f"<{min_seeds} valid seed points found in wm-gm interface...")) return None # print(seeds) # Perform tracking if track_type == "local": streamline_generator = LocalTracking(dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), maxlen=int(max_length), step_size=float( step_curv_combinations[0]), fixedstep=False, return_all=True, random_seed=42) elif track_type == "particle": streamline_generator = ParticleFilteringTracking( dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), step_size=float(step_curv_combinations[0]), maxlen=int(max_length), pft_back_tracking_dist=pft_back_tracking_dist, pft_front_tracking_dist=pft_front_tracking_dist, pft_max_trial=20, particle_count=particle_count, return_all=True, random_seed=42) else: raise ValueError("ERROR: No valid tracking method(s) specified.") # Filter resulting streamlines by those that stay entirely # inside the brain try: roi_proximal_streamlines = utils.target(streamline_generator, np.eye(4), B0_mask_data.astype('bool'), include=True) except BaseException: print('No streamlines found inside the brain! ' 'Check registrations.') return None del mod_fit, seeds, tiss_classifier, streamline_generator, \ B0_mask_data, seeding_mask, dg B0_mask.uncache() atlas_img.uncache() t1w2dwi.uncache() gm_in_dwi.uncache() vent_csf_in_dwi.uncache() wm_in_dwi.uncache() atlas_img.uncache() tissue_img.uncache() gc.collect() # Filter resulting streamlines by roi-intersection # characteristics atlas_data = np.array(atlas_img.dataobj).astype("uint16") # Build mask vector from atlas for later roi filtering parcels = [] i = 0 intensities = [i for i in np.unique(atlas_data) if i != 0] for roi_val in intensities: parcels.append(atlas_data == roi_val) i += 1 parcel_vec = list(np.ones(len(parcels)).astype("bool")) try: roi_proximal_streamlines = \ nib.streamlines.array_sequence.ArraySequence( select_by_rois( roi_proximal_streamlines, affine=np.eye(4), rois=parcels, include=parcel_vec, mode="any", tol=roi_neighborhood_tol, ) ) print("%s%s" % ("Filtering by: \nNode intersection: ", len(roi_proximal_streamlines))) except BaseException: print('No streamlines found to connect any parcels! ' 'Check registrations.') return None try: roi_proximal_streamlines = nib.streamlines. \ array_sequence.ArraySequence( [ s for s in roi_proximal_streamlines if len(s) >= float(min_length) ] ) print(f"Minimum fiber length >{min_length}mm: " f"{len(roi_proximal_streamlines)}") except BaseException: print('No streamlines remaining after minimal length criterion.') return None if waymask is not None and os.path.isfile(waymask_tmp_path): waymask_data = np.asarray( nib.load(waymask_tmp_path).dataobj).astype("bool") try: roi_proximal_streamlines = roi_proximal_streamlines[utils.near_roi( roi_proximal_streamlines, np.eye(4), waymask_data, tol=int(round(roi_neighborhood_tol * 0.50, 1)), mode="all")] print("%s%s" % ("Waymask proximity: ", len(roi_proximal_streamlines))) del waymask_data except BaseException: print('No streamlines remaining in waymask\'s vacinity.') return None hf.close() del parcels, atlas_data tmp_files = [tissues4d_tmp_path, waymask_tmp_path, recon_path_tmp_path] for j in tmp_files: if j is not None: if os.path.isfile(j): os.system(f"rm -f {j} &") if len(roi_proximal_streamlines) > 0: return ArraySequence( [s.astype("float32") for s in roi_proximal_streamlines]) else: return None
def track_ensemble(dwi_data, target_samples, atlas_data_wm_gm_int, parcels, mod_fit, tiss_classifier, sphere, directget, curv_thr_list, step_list, track_type, maxcrossing, max_length, roi_neighborhood_tol, min_length, waymask, n_seeds_per_iter=100, pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15): """ Perform native-space ensemble tractography, restricted to a vector of ROI masks. dwi_data : array 4D array of dwi data. target_samples : int Total number of streamline samples specified to generate streams. atlas_data_wm_gm_int : array 3D int32 numpy array of atlas parcellation intensities from Nifti1Image in T1w-warped native diffusion space, restricted to wm-gm interface. parcels : list List of 3D boolean numpy arrays of atlas parcellation ROI masks from a Nifti1Image in T1w-warped native diffusion space. mod : obj Connectivity reconstruction model. tiss_classifier : str Tissue classification method. sphere : obj DiPy object for modeling diffusion directions on a sphere. directget : str The statistical approach to tracking. Options are: det (deterministic), closest (clos), boot (bootstrapped), and prob (probabilistic). curv_thr_list : list List of integer curvature thresholds used to perform ensemble tracking. step_list : list List of float step-sizes used to perform ensemble tracking. track_type : str Tracking algorithm used (e.g. 'local' or 'particle'). maxcrossing : int Maximum number if diffusion directions that can be assumed per voxel while tracking. max_length : int Maximum fiber length threshold in mm to restrict tracking. roi_neighborhood_tol : float Distance (in the units of the streamlines, usually mm). If any coordinate in the streamline is within this distance from the center of any voxel in the ROI, the filtering criterion is set to True for this streamline, otherwise False. Defaults to the distance between the center of each voxel and the corner of the voxel. min_length : int Minimum fiber length threshold in mm. waymask : str Path to a Nifti1Image in native diffusion space to constrain tractography. n_seeds_per_iter : int Number of seeds from which to initiate tracking for each unique ensemble combination. By default this is set to 200. particle_count pft_back_tracking_dist : float Distance in mm to back track before starting the particle filtering tractography. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 2 mm. pft_front_tracking_dist : float Distance in mm to run the particle filtering tractography after the the back track distance. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 1 mm. particle_count : int Number of particles to use in the particle filter. Returns ------- streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. """ from colorama import Fore, Style from dipy.tracking import utils from dipy.tracking.streamline import Streamlines, select_by_rois from dipy.tracking.local_tracking import LocalTracking, ParticleFilteringTracking from dipy.direction import ProbabilisticDirectionGetter, BootDirectionGetter, ClosestPeakDirectionGetter, DeterministicMaximumDirectionGetter if waymask: waymask_data = nib.load(waymask).get_fdata().astype('bool') # Commence Ensemble Tractography parcel_vec = list(np.ones(len(parcels)).astype('bool')) streamlines = nib.streamlines.array_sequence.ArraySequence() ix = 0 circuit_ix = 0 stream_counter = 0 while int(stream_counter) < int(target_samples): for curv_thr in curv_thr_list: print("%s%s" % ('Curvature: ', curv_thr)) # Instantiate DirectionGetter if directget == 'prob': dg = ProbabilisticDirectionGetter.from_shcoeff( mod_fit, max_angle=float(curv_thr), sphere=sphere) elif directget == 'boot': dg = BootDirectionGetter.from_data(dwi_data, mod_fit, max_angle=float(curv_thr), sphere=sphere) elif directget == 'clos': dg = ClosestPeakDirectionGetter.from_shcoeff( mod_fit, max_angle=float(curv_thr), sphere=sphere) elif directget == 'det': dg = DeterministicMaximumDirectionGetter.from_shcoeff( mod_fit, max_angle=float(curv_thr), sphere=sphere) else: raise ValueError( 'ERROR: No valid direction getter(s) specified.') for step in step_list: print("%s%s" % ('Step: ', step)) # Perform wm-gm interface seeding, using n_seeds at a time seeds = utils.random_seeds_from_mask( atlas_data_wm_gm_int > 0, seeds_count=n_seeds_per_iter, seed_count_per_voxel=False, affine=np.eye(4)) if len(seeds) == 0: raise RuntimeWarning( 'Warning: No valid seed points found in wm-gm interface...' ) print(seeds) # Perform tracking if track_type == 'local': streamline_generator = LocalTracking( dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), maxlen=int(max_length), step_size=float(step), return_all=True) elif track_type == 'particle': streamline_generator = ParticleFilteringTracking( dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), step_size=float(step), maxlen=int(max_length), pft_back_tracking_dist=pft_back_tracking_dist, pft_front_tracking_dist=pft_front_tracking_dist, particle_count=particle_count, return_all=True) else: raise ValueError( 'ERROR: No valid tracking method(s) specified.') # Filter resulting streamlines by roi-intersection characteristics roi_proximal_streamlines = Streamlines( select_by_rois(streamline_generator, affine=np.eye(4), rois=parcels, include=parcel_vec, mode='any', tol=roi_neighborhood_tol)) print("%s%s" % ('Qualifying Streamlines by node intersection: ', len(roi_proximal_streamlines))) roi_proximal_streamlines = nib.streamlines.array_sequence.ArraySequence( [ s for s in roi_proximal_streamlines if len(s) > float(min_length) ]) print("%s%s" % ('Qualifying Streamlines by minimum length criterion: ', len(roi_proximal_streamlines))) if waymask: roi_proximal_streamlines = roi_proximal_streamlines[ utils.near_roi(roi_proximal_streamlines, np.eye(4), waymask_data, tol=roi_neighborhood_tol, mode='any')] print("%s%s" % ('Qualifying Streamlines by waymask proximity: ', len(roi_proximal_streamlines))) # Repeat process until target samples condition is met ix = ix + 1 for s in roi_proximal_streamlines: stream_counter = stream_counter + len(s) streamlines.append(s) if int(stream_counter) >= int(target_samples): break else: continue # Cleanup memory del seeds, roi_proximal_streamlines, streamline_generator del dg circuit_ix = circuit_ix + 1 print( "%s%s%s%s%s" % ('Completed hyperparameter circuit: ', circuit_ix, '...\nCumulative Streamline Count: ', Fore.CYAN, stream_counter)) print(Style.RESET_ALL) print('\n') return streamlines
def track(dwi_file, bval, bvec, mask_file, stop_val=0.1): # """ # Tracking with basic tensors and basic eudx - experimental # We now force seeding at every voxel in the provided mask for # simplicity. Future functionality will extend these options. # **Positional Arguments:** # dwi_file: # - File (registered) to use for tensor/fiber tracking # mask_file: # - Brain mask to keep tensors inside the brain # gtab: # - dipy formatted bval/bvec Structure # **Optional Arguments:** # stop_val: # - Value to cutoff fiber track # """ #img = nb.load(dwi_file) #data = img.get_data() dwi = dipy.data.load(dwi_file) data = dwi.get_data() #img = nb.load(mask_file) #mask = img.get_data() dwi_mask = dipy.data.load(mask_file) mask = dwi_mask.get_data() gtab = gradient_table(bval, bvec) affine = dwi.affine seed_mask = mask seeds = utils.seeds_from_mask(seed_mask, density=1, affine=affine) # use all points in mask seedIdx = np.where(mask > 0) # seed everywhere not equal to zero seedIdx = np.transpose(seedIdx) sphere = get_sphere('symmetric724') csd_model = ConstrainedSphericalDeconvModel(gtab, None, sh_order=6) csd_fit = csd_model.fit(data, mask=mask) tensor_model = dti.TensorModel(gtab) tenfit = tensor_model.fit(data, mask=mask) FA = fractional_anisotropy(tenfit.evals) classifier = ThresholdTissueClassifier(FA, 0.1) dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=80., sphere=sphere) streamlines_generator = LocalTracking(dg, classifier, seeds, affine, step_size=0.5) streamlines = Streamlines(streamlines_generator) trk_file = save_trk("deterministic_threshold_DDG_samp_data.trk", streamlines, affine=affine, shape=mask.shape)
def run_tracking(step_curv_combinations, recon_path, n_seeds_per_iter, directget, maxcrossing, max_length, pft_back_tracking_dist, pft_front_tracking_dist, particle_count, roi_neighborhood_tol, waymask, min_length, track_type, min_separation_angle, sphere, tiss_class, tissues4d, cache_dir): import gc import os import h5py from dipy.tracking import utils from dipy.tracking.streamline import select_by_rois from dipy.tracking.local_tracking import LocalTracking, \ ParticleFilteringTracking from dipy.direction import (ProbabilisticDirectionGetter, ClosestPeakDirectionGetter, DeterministicMaximumDirectionGetter) from nilearn.image import index_img from pynets.dmri.track import prep_tissues from nibabel.streamlines.array_sequence import ArraySequence from nipype.utils.filemanip import copyfile, fname_presuffix recon_path_tmp_path = fname_presuffix(recon_path, suffix=f"_{step_curv_combinations}", newpath=cache_dir) copyfile(recon_path, recon_path_tmp_path, copy=True, use_hardlink=False) if waymask is not None: waymask_tmp_path = fname_presuffix(waymask, suffix=f"_{step_curv_combinations}", newpath=cache_dir) copyfile(waymask, waymask_tmp_path, copy=True, use_hardlink=False) else: waymask_tmp_path = None tissue_img = nib.load(tissues4d) # Order: B0_mask = index_img(tissue_img, 0) atlas_img = index_img(tissue_img, 1) atlas_data_wm_gm_int = index_img(tissue_img, 2) t1w2dwi = index_img(tissue_img, 3) gm_in_dwi = index_img(tissue_img, 4) vent_csf_in_dwi = index_img(tissue_img, 5) wm_in_dwi = index_img(tissue_img, 6) tiss_classifier = prep_tissues(t1w2dwi, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi, tiss_class, B0_mask) B0_mask_data = np.asarray(B0_mask.dataobj).astype("bool") atlas_data = np.array(atlas_img.dataobj).astype("uint16") atlas_data_wm_gm_int_data = np.asarray( atlas_data_wm_gm_int.dataobj).astype("bool").astype("int16") # Build mask vector from atlas for later roi filtering parcels = [] i = 0 intensities = [i for i in np.unique(atlas_data) if i != 0] for roi_val in intensities: parcels.append(atlas_data == roi_val) i += 1 del atlas_data parcel_vec = list(np.ones(len(parcels)).astype("bool")) with h5py.File(recon_path_tmp_path, 'r+') as hf: mod_fit = hf['reconstruction'][:].astype('float32') hf.close() print("%s%s" % ("Curvature: ", step_curv_combinations[1])) # Instantiate DirectionGetter if directget == "prob" or directget == "probabilistic": dg = ProbabilisticDirectionGetter.from_shcoeff( mod_fit, max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) elif directget == "clos" or directget == "closest": dg = ClosestPeakDirectionGetter.from_shcoeff( mod_fit, max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) elif directget == "det" or directget == "deterministic": maxcrossing = 1 dg = DeterministicMaximumDirectionGetter.from_shcoeff( mod_fit, max_angle=float(step_curv_combinations[1]), sphere=sphere, min_separation_angle=min_separation_angle, ) else: raise ValueError("ERROR: No valid direction getter(s) specified.") print("%s%s" % ("Step: ", step_curv_combinations[0])) # Perform wm-gm interface seeding, using n_seeds at a time seeds = utils.random_seeds_from_mask( atlas_data_wm_gm_int_data > 0, seeds_count=n_seeds_per_iter, seed_count_per_voxel=False, affine=np.eye(4), ) if len(seeds) == 0: print( UserWarning("No valid seed points found in wm-gm " "interface...")) return None # print(seeds) # Perform tracking if track_type == "local": streamline_generator = LocalTracking( dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), maxlen=int(max_length), step_size=float(step_curv_combinations[0]), fixedstep=False, return_all=True, ) elif track_type == "particle": streamline_generator = ParticleFilteringTracking( dg, tiss_classifier, seeds, np.eye(4), max_cross=int(maxcrossing), step_size=float(step_curv_combinations[0]), maxlen=int(max_length), pft_back_tracking_dist=pft_back_tracking_dist, pft_front_tracking_dist=pft_front_tracking_dist, particle_count=particle_count, return_all=True, ) else: try: raise ValueError("ERROR: No valid tracking method(s) specified.") except ValueError: import sys sys.exit(0) # Filter resulting streamlines by those that stay entirely # inside the brain try: roi_proximal_streamlines = utils.target(streamline_generator, np.eye(4), B0_mask_data, include=True) except BaseException: print('No streamlines found inside the brain! ' 'Check registrations.') return None # Filter resulting streamlines by roi-intersection # characteristics try: roi_proximal_streamlines = \ nib.streamlines.array_sequence.ArraySequence( select_by_rois( roi_proximal_streamlines, affine=np.eye(4), rois=parcels, include=parcel_vec, mode="%s" % ("any" if waymask is not None else "both_end"), tol=roi_neighborhood_tol, ) ) print("%s%s" % ("Filtering by: \nNode intersection: ", len(roi_proximal_streamlines))) except BaseException: print('No streamlines found to connect any parcels! ' 'Check registrations.') return None try: roi_proximal_streamlines = nib.streamlines. \ array_sequence.ArraySequence( [ s for s in roi_proximal_streamlines if len(s) >= float(min_length) ] ) print(f"Minimum fiber length >{min_length}mm: " f"{len(roi_proximal_streamlines)}") except BaseException: print('No streamlines remaining after minimal length criterion.') return None if waymask is not None and os.path.isfile(waymask_tmp_path): from nilearn.image import math_img mask = math_img("img > 0.0075", img=nib.load(waymask_tmp_path)) waymask_data = np.asarray(mask.dataobj).astype("bool") try: roi_proximal_streamlines = roi_proximal_streamlines[utils.near_roi( roi_proximal_streamlines, np.eye(4), waymask_data, tol=roi_neighborhood_tol, mode="all")] print("%s%s" % ("Waymask proximity: ", len(roi_proximal_streamlines))) except BaseException: print('No streamlines remaining in waymask\'s vacinity.') return None out_streams = [s.astype("float32") for s in roi_proximal_streamlines] del dg, seeds, roi_proximal_streamlines, streamline_generator, \ atlas_data_wm_gm_int_data, mod_fit, B0_mask_data os.remove(recon_path_tmp_path) gc.collect() try: return ArraySequence(out_streams) except BaseException: return None
mask=mask) #csd_peaks = peaks_from_model(model=csd_model, # data=data, # sphere=default_sphere, # relative_peak_threshold=relative_peak_threshold, # min_separation_angle=min_separation_angle, # mask=mask) streamline_eudx = EuDX(csa_peaks.peak_values, csa_peaks.peak_indices, odf_vertices=default_sphere.vertices, a_low=threshold_tissue_classifier, step_sz=step_size, seeds=seeds) save(streamline_eudx, streamline_eudx.affine, mask.shape, '1.trk', lenght_threshold) detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff(csa_peaks.shm_coeff, max_angle=max_angle, sphere=default_sphere) tensor_model = dti.TensorModel(gtab) dti_fit = tensor_model.fit(data, mask=mask) FA = fractional_anisotropy(dti_fit.evals) classifier = ThresholdTissueClassifier(FA, threshold_tissue_classifier) streamlines_dmdg = LocalTracking(detmax_dg, classifier, seeds, affine, step_size=step_size) save(streamlines_dmdg, streamline_eudx.affine, mask.shape, '1.trk', lenght_threshold) classifier = ThresholdTissueClassifier(csa_peaks.gfa, threshold_tissue_classifier) prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csa_peaks.shm_coeff, max_angle=max_angle, sphere=default_sphere) streamlines_pdg = LocalTracking(prob_dg, classifier, seeds, affine, step_size=step_size) save(streamlines_pdg, streamline_eudx.affine, mask.shape, '1.trk', lenght_threshold) #M, grouping = connectivity_matrix(streamlines, labels, affine=s_affine, symmetric=True, return_mapping=True, mapping_as_streamlines=True)
def test_affine_transformations(): """This tests that the input affine is properly handled by LocalTracking and produces reasonable streamlines in a simple example. """ sphere = HemiSphere.from_sphere(unit_octahedron) # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing pmf_lookup = np.array([[0., 0., 1.], [1., 0., 0.], [0., 1., 0.], [.4, .6, 0.]]) simple_image = np.array([[0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] pmf = pmf_lookup[simple_image] seeds = [np.array([1., 1., 0.]), np.array([2., 4., 0.])] expected = [np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [3., 1., 0.], [4., 1., 0.]]), np.array([[2., 0., 0.], [2., 1., 0.], [2., 2., 0.], [2., 3., 0.], [2., 4., 0.], [2., 5., 0.]])] mask = (simple_image > 0).astype(float) tc = BinaryTissueClassifier(mask) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 60, sphere, pmf_threshold=0.1) # TST- bad affine wrong shape bad_affine = np.eye(3) npt.assert_raises(ValueError, LocalTracking, dg, tc, seeds, bad_affine, 1.) # TST - bad affine with shearing bad_affine = np.eye(4) bad_affine[0, 1] = 1. npt.assert_raises(ValueError, LocalTracking, dg, tc, seeds, bad_affine, 1.) # TST - identity a0 = np.eye(4) # TST - affines with positive/negative offsets a1 = np.eye(4) a1[:3, 3] = [1, 2, 3] a2 = np.eye(4) a2[:3, 3] = [-2, 0, -1] # TST - affine with scaling a3 = np.eye(4) a3[0, 0] = a3[1, 1] = a3[2, 2] = 8 # TST - affine with axes inverting (negative value) a4 = np.eye(4) a4[1, 1] = a4[2, 2] = -1 # TST - combined affines a5 = a1 + a2 + a3 a5[3, 3] = 1 # TST - in vivo affine exemple # Sometimes data have affines with tiny shear components. # For example, the small_101D data-set has some of that: fdata, _, _ = get_data('small_101D') a6 = nib.load(fdata).affine for affine in [a0, a1, a2, a3, a4, a5, a6]: lin = affine[:3, :3] offset = affine[:3, 3] seeds_trans = [np.dot(lin, s) + offset for s in seeds] # We compute the voxel size to ajust the step size to one voxel voxel_size = np.mean(np.sqrt(np.dot(lin, lin).diagonal())) streamlines = LocalTracking(direction_getter=dg, tissue_classifier=tc, seeds=seeds_trans, affine=affine, step_size=voxel_size, return_all=True) # We apply the inverse affine transformation to the generated # streamlines. It should be equals to the expected streamlines # (generated with the identity affine matrix). affine_inv = np.linalg.inv(affine) lin = affine_inv[:3, :3] offset = affine_inv[:3, 3] streamlines_inv = [] for line in streamlines: streamlines_inv.append([np.dot(pts, lin) + offset for pts in line]) npt.assert_equal(len(streamlines_inv[0]), len(expected[0])) npt.assert_(np.allclose(streamlines_inv[0], expected[0], atol=0.3)) npt.assert_equal(len(streamlines_inv[1]), len(expected[1])) npt.assert_(np.allclose(streamlines_inv[1], expected[1], atol=0.3))
def test_affine_transformations(): """This tests that the input affine is properly handled by LocalTracking and produces reasonable streamlines in a simple example. """ sphere = HemiSphere.from_sphere(unit_octahedron) # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing pmf_lookup = np.array([[0., 0., 1.], [1., 0., 0.], [0., 1., 0.], [.4, .6, 0.]]) simple_image = np.array([ [0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] pmf = pmf_lookup[simple_image] seeds = [np.array([1., 1., 0.]), np.array([2., 4., 0.])] expected = [ np.array([[1., 1., 0.], [2., 1., 0.], [3., 1., 0.]]), np.array([[2., 1., 0.], [2., 2., 0.], [2., 3., 0.], [2., 4., 0.]]) ] mask = (simple_image > 0).astype(float) sc = BinaryStoppingCriterion(mask) dg = DeterministicMaximumDirectionGetter.from_pmf(pmf, 60, sphere, pmf_threshold=0.1) # TST- bad affine wrong shape bad_affine = np.eye(3) npt.assert_raises(ValueError, LocalTracking, dg, sc, seeds, bad_affine, 1.) # TST - bad affine with shearing bad_affine = np.eye(4) bad_affine[0, 1] = 1. npt.assert_raises(ValueError, LocalTracking, dg, sc, seeds, bad_affine, 1.) # TST - bad seeds bad_seeds = 1000 npt.assert_raises(ValueError, LocalTracking, dg, sc, bad_seeds, np.eye(4), 1.) # TST - identity a0 = np.eye(4) # TST - affines with positive/negative offsets a1 = np.eye(4) a1[:3, 3] = [1, 2, 3] a2 = np.eye(4) a2[:3, 3] = [-2, 0, -1] # TST - affine with scaling a3 = np.eye(4) a3[0, 0] = a3[1, 1] = a3[2, 2] = 8 # TST - affine with axes inverting (negative value) a4 = np.eye(4) a4[1, 1] = a4[2, 2] = -1 # TST - combined affines a5 = a1 + a2 + a3 a5[3, 3] = 1 # TST - in vivo affine example # Sometimes data have affines with tiny shear components. # For example, the small_101D data-set has some of that: fdata, _, _ = get_fnames('small_101D') a6 = nib.load(fdata).affine for affine in [a0, a1, a2, a3, a4, a5, a6]: lin = affine[:3, :3] offset = affine[:3, 3] seeds_trans = [np.dot(lin, s) + offset for s in seeds] # We compute the voxel size to adjust the step size to one voxel voxel_size = np.mean(np.sqrt(np.dot(lin, lin).diagonal())) streamlines = LocalTracking(direction_getter=dg, stopping_criterion=sc, seeds=seeds_trans, affine=affine, step_size=voxel_size, return_all=True) # We apply the inverse affine transformation to the generated # streamlines. It should be equals to the expected streamlines # (generated with the identity affine matrix). affine_inv = np.linalg.inv(affine) lin = affine_inv[:3, :3] offset = affine_inv[:3, 3] streamlines_inv = [] for line in streamlines: streamlines_inv.append([np.dot(pts, lin) + offset for pts in line]) npt.assert_equal(len(streamlines_inv[0]), len(expected[0])) npt.assert_(np.allclose(streamlines_inv[0], expected[0], atol=0.3)) npt.assert_equal(len(streamlines_inv[1]), len(expected[1])) npt.assert_(np.allclose(streamlines_inv[1], expected[1], atol=0.3))
_, _, img_pve_wm = read_stanford_pve_maps() data = hardi_img.get_data() labels = labels_img.get_data() affine = hardi_img.affine white_matter = img_pve_wm.get_data() seed_mask = (labels == 2) seed_mask[img_pve_wm.get_data() < 0.5] = 0 seeds = utils.seeds_from_mask(seed_mask, density=2, affine=affine) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd_model.fit(data, mask=white_matter) dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) """ Threshold Stopping Criterion ============================ A scalar map can be used to define where the tracking stops. The threshold stopping criterion uses a scalar map to stop the tracking whenever the interpolated scalar value is lower than a fixed threshold. Here, we show an example using the fractional anisotropy (FA) map of the DTI model. The threshold stopping criterion uses a trilinear interpolation at the tracking position. **Parameters** - metric_map: numpy array [:, :, :] - threshold: float
if fodf_pred_sum[i,j,k]>0: pmf[i,j,k,:]/= fodf_pred_sum[i,j,k] pmf_sfm_40= pmf.copy() print('Finished estimating FODF with sfm, time elapsed (minutes): ' + str(int( (time.time()-t1)/60 ) ) ) del odf_sfm, pmf ''' if run_dipy_tractography: print('Running tractography; CSD') t1 = time.time() det_dg = DeterministicMaximumDirectionGetter.from_pmf(pmf_dipy, max_angle=30., sphere=sphere_fod) streamline_generator = LocalTracking(det_dg, stopping_criterion, seeds, affine=affine, step_size=.5) streamlines = Streamlines(streamline_generator) sft = StatefulTractogram(streamlines, FA_img_nii, Space.RASMM) save_trk(sft, dav_dir + "tractogram_dipy_deterministic.trk", bbox_valid_check=False) print('Finished tractography with DIPY, time elapsed (minutes): ' +