def loc_track(path, default_sphere): data, affine = load_nifti(path + 'data.nii.gz') data[np.isnan(data) == 1] = 0 mask, affine = load_nifti(path + 'nodif_brain_mask.nii.gz') mask[np.isnan(mask) == 1] = 0 mask[:, :, 2:] = 0 gtab = gradient_table(path + 'bvals', path + 'bvecs') if os.path.exists(path + 'grad_dev.nii.gz'): gd, affine_g = load_nifti(path + 'grad_dev.nii.gz') else: gd = None csa_model = CsaOdfModel(gtab, smooth=1, sh_order=12) peaks = peaks_from_model(csa_model, data, default_sphere, relative_peak_threshold=0.99, min_separation_angle=25, mask=mask) seedss = copy.deepcopy(mask) seeds = utils.seeds_from_mask(seedss, affine, [2, 2, 2]) stopping_criterion = ThresholdStoppingCriterion(mask, 0) tracked = tracking(peaks, stopping_criterion, seeds, affine, graddev=gd, sphere=default_sphere) tracked.localTracking() return tracked
def test_eudx_tracker(): """This tests that the Peaks And Metrics 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 peaks_values_lookup = np.array([[0., 0.], [1., 0.], [1., 0.], [0.5, 0.5]]) peaks_indices_lookup = np.array([[-1, -1], [0, -1], [1, -1], [0, 1]]) # EuDXDirectionGetter needs at 3 slices on each axis to work simple_image = np.zeros([5, 6, 3], dtype=int) simple_image[:, :, 1] = np.array([[0, 1, 0, 1, 0, 0], [0, 1, 0, 1, 0, 0], [0, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) dg = PeaksAndMetrics() dg.sphere = sphere dg.peak_values = peaks_values_lookup[simple_image] dg.peak_indices = peaks_indices_lookup[simple_image] dg.ang_thr = 90 mask = (simple_image >= 0).astype(float) sc = ThresholdStoppingCriterion(mask, 0.5) seeds = [np.array([1., 1., 1.]), np.array([2., 4., 1.]), np.array([1., 3., 1.]), np.array([4., 4., 1.])] streamlines = LocalTracking(dg, sc, seeds, np.eye(4), 1.) expected = [np.array([[0., 1., 1.], [1., 1., 1.], [2., 1., 1.], [3., 1., 1.], [4., 1., 1.]]), np.array([[2., 0., 1.], [2., 1., 1.], [2., 2., 1.], [2., 3., 1.], [2., 4., 1.], [2., 5., 1.]]), np.array([[0., 3., 1.], [1., 3., 1.], [2., 3., 1.], [2., 4., 1.], [2., 5., 1.]]), np.array([[4., 4., 1.]])] for i, sl in enumerate(streamlines): npt.assert_(np.allclose(sl, expected[i]))
def probal(Threshold=.2, data_list=None, seed='.', one_node=False, two_node=False): time0 = time.time() print("begin loading data, time:", time.time() - time0) 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'] 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) print("begin tracking, time:", time.time() - time0) 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, img, Space.RASMM) if one_node or two_node: sft.to_vox() streamlines = reduct_seed_ROI(sft.streamlines, seed_mask, one_node, two_node) sft = StatefulTractogram(streamlines, img, Space.VOX) sft._vox_to_rasmm() print("begin saving, time:", time.time() - time0) output = 'tractogram_probabilistic.trk' save_trk(sft, output) print("finished, time:", time.time() - time0)
def track(self): SeedBasedTracker.track(self) if self.streamlines is not None: return roi_r = Config.get_config().getint("CSDTracking", "autoResponseRoiRadius", fallback="10") fa_thr = Config.get_config().getfloat("CSDTracking", "autoResponseFaThreshold", fallback="0.7") response, _ = auto_response_ssst(self.data.gtab, self.data.dwi, roi_radii=roi_r, fa_thr=fa_thr) csd_model = ConstrainedSphericalDeconvModel(self.data.gtab, response) relative_peak_thr = Config.get_config().getfloat("CSDTracking", "relativePeakTreshold", fallback="0.5") min_separation_angle = Config.get_config().getfloat("CSDTracking", "minimumSeparationAngle", fallback="25") direction_getter = peaks_from_model(model=csd_model, data=self.data.dwi, sphere=get_sphere('symmetric724'), mask=self.data.binarymask, relative_peak_threshold=relative_peak_thr, min_separation_angle=min_separation_angle, parallel=False) dti_fit = dti.TensorModel(self.data.gtab, fit_method='LS') dti_fit = dti_fit.fit(self.data.dwi, mask=self.data.binarymask) self._track(ThresholdStoppingCriterion(dti_fit.fa, self.options.fa_threshold), direction_getter) Cache.get_cache().set(self.id, self.streamlines)
def basic_tracking(name=None, data_path=None, output_path='.', Threshold=.20, data_list=None): 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'] 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) from dipy.reconst.csdeconv import auto_response_ssst from dipy.reconst.shm import CsaOdfModel from dipy.data import default_sphere from dipy.direction import peaks_from_model response, ratio = auto_response_ssst(gtab, data, roi_radii=10, fa_thr=0.7) csa_model = CsaOdfModel(gtab, sh_order=6) csa_peaks = peaks_from_model(csa_model, data, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=white_matter) stopping_criterion = ThresholdStoppingCriterion(csa_peaks.gfa, Threshold) print("begin tracking, time:", time.time() - time0) # Initialization of LocalTracking. The computation happens in the next step. streamlines_generator = LocalTracking(csa_peaks, stopping_criterion, seeds, affine=affine, step_size=.5) # Generate streamlines object streamlines = Streamlines(streamlines_generator) print('begin saving, time:', time.time() - time0) from dipy.io.stateful_tractogram import Space, StatefulTractogram from dipy.io.streamline import save_trk sft = StatefulTractogram(streamlines, img, Space.RASMM) output = output_path + '/tractogram_EuDX_' + name + '.trk' save_trk(sft, output, streamlines)
def create_stopping_criterion(self, csa_model): tensor_model = dti.TensorModel(self.gtab) tenfit = tensor_model.fit(self.data, mask=self.white_mask) fa = fractional_anisotropy(tenfit.evals) stopping_criterion = ThresholdStoppingCriterion(fa, 0.18) # gfa = csa_model.fit(self.data, mask=self.white_mask).gfa # stopping_criterion = ThresholdStoppingCriterion(gfa, self.stopping_threshold) return stopping_criterion
def PFT_tracking(name=None, data_path=None, output_path='.', Threshold=.20): time0 = time.time() print("begin loading data, time:", time.time() - time0) data, affine, img, labels, gtab, head_mask = get_data(name, data_path) 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) 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) dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=20., sphere=default_sphere) #seed_mask = (labels == 2) #seed_mask[pve_wm_data < 0.5] = 0 seeds = utils.seeds_from_mask(seed_mask, affine, density=1) #voxel_size = np.average(voxel_size[1:4]) step_size = 0.2 #cmc_criterion = CmcStoppingCriterion.from_pve(pve_wm_data, # pve_gm_data, # pve_csf_data, # step_size=step_size, # average_voxel_size=voxel_size) # Particle Filtering Tractography pft_streamline_generator = ParticleFilteringTracking( dg, stopping_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, img, Space.RASMM) output = output_path + '/tractogram_pft_' + name + '.trk'
def create_fa_classifier(gtab, data, white_matter): import dipy.reconst.dti as dti from dipy.reconst.dti import fractional_anisotropy from dipy.tracking.stopping_criterion import ThresholdStoppingCriterion tensor_model = dti.TensorModel(gtab) tenfit = tensor_model.fit(data, mask=white_matter) fa = fractional_anisotropy(tenfit.evals) classifier = ThresholdStoppingCriterion(fa, 0.18) return fa, classifier
def _fa_sc(self): import dipy.reconst.dti as dti from dipy.reconst.dti import fractional_anisotropy from dipy.tracking.stopping_criterion import ThresholdStoppingCriterion tensor_model = dti.TensorModel(self.gtab) tenfit = tensor_model.fit(self.data, mask=self.tissue_labels == 2) fa = fractional_anisotropy(tenfit.evals) classifier = ThresholdStoppingCriterion(fa, self.parameters_dict['fa_th']) self.classifier = classifier
def test_threshold_stopping_criterion(): """This tests that the thresholdy stopping criterion returns expected streamline statuses. """ tissue_map = np.random.random((4, 4, 4)) ttc = ThresholdStoppingCriterion(tissue_map.astype('float32'), 0.5) # Test voxel center for ind in ndindex(tissue_map.shape): pts = np.array(ind, dtype='float64') state = ttc.check_point(pts) if tissue_map[ind] > 0.5: npt.assert_equal(state, int(StreamlineStatus.TRACKPOINT)) else: npt.assert_equal(state, int(StreamlineStatus.ENDPOINT)) # Test random points in voxel inds = [[0, 1.4, 2.2], [0, 2.3, 2.3], [0, 2.2, 1.3], [0, 0.9, 2.2], [0, 2.8, 1.1], [0, 1.1, 3.3], [0, 2.1, 1.9], [0, 3.1, 3.1], [0, 0.1, 0.1], [0, 0.9, 0.5], [0, 0.9, 0.5], [0, 2.9, 0.1]] for pts in inds: pts = np.array(pts, dtype='float64') state = ttc.check_point(pts) res = scipy.ndimage.map_coordinates(tissue_map, np.reshape(pts, (3, 1)), order=1, mode='nearest') if res > 0.5: npt.assert_equal(state, int(StreamlineStatus.TRACKPOINT)) else: npt.assert_equal(state, int(StreamlineStatus.ENDPOINT)) # Test outside points outside_pts = [[100, 100, 100], [0, -1, 1], [0, 10, 2], [0, 0.5, -0.51], [0, -0.51, 0.1]] for pts in outside_pts: pts = np.array(pts, dtype='float64') state = ttc.check_point(pts) npt.assert_equal(state, int(StreamlineStatus.OUTSIDEIMAGE))
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 ClosestPeak(name=None, data_path=None, output_path='.', Threshold=.20): time0 = time.time() print("begin loading data, time:", time.time() - time0) data, affine, img, labels, gtab, head_mask = get_data(name, data_path) 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) #pmf = csd_fit.odf(small_sphere).clip(min=0) peak_dg = BootDirectionGetter.from_data(data, csd_model, max_angle=30., sphere=small_sphere) 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(peak_dg, stopping_criterion, seeds, affine, step_size=.5) streamlines = Streamlines(streamline_generator) sft = StatefulTractogram(streamlines, img, Space.RASMM) print("begin saving, time:", time.time() - time0) output = output_path + '/tractogram_ClosestPeak_' + name + '.trk' save_trk(sft, output) print("finished, time:", time.time() - time0)
def _core_run(self, stopping_path, use_binary_mask, stopping_thr, seeding_path, seed_density, step_size, direction_getter, out_tract, save_seeds): stop, affine = load_nifti(stopping_path) if use_binary_mask: stopping_criterion = BinaryStoppingCriterion(stop > stopping_thr) else: stopping_criterion = ThresholdStoppingCriterion(stop, stopping_thr) logging.info('stopping criterion 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') tracking_result = LocalTracking(direction_getter, stopping_criterion, seeds, affine, step_size=step_size, save_seeds=save_seeds) logging.info('LocalTracking initiated') if save_seeds: streamlines, seeds = zip(*tracking_result) seeds = {'seeds': seeds} else: streamlines = list(tracking_result) seeds = {} sft = StatefulTractogram(streamlines, seeding_path, Space.RASMM, data_per_streamline=seeds) save_tractogram(sft, out_tract, bbox_valid_check=False) logging.info('Saved {0}'.format(out_tract))
seeds = utils.seeds_from_mask(seed_mask, affine, density=1) # Generalized FA to be used as stopping criterion ''' csa_model = CsaOdfModel(gtab, sh_order=6) gfa = csa_model.fit(d_img, mask=mask).gfa gfa_img= np.transpose(gfa, [2,1,0]) gfa_img= sitk.GetImageFromArray(gfa_img) gfa_img.SetDirection(ref_dir) gfa_img.SetOrigin(ref_org) gfa_img.SetSpacing(ref_spc) sitk.WriteImage(gfa_img, dav_dir + 'gfa.mhd')''' #stopping_criterion = ThresholdStoppingCriterion(gfa, .20) stopping_criterion = ThresholdStoppingCriterion(FA, .15) ########################################################### if run_DL_tractography: # Run the proposed method X = tf.placeholder("float32", [None, n_sig]) Y = tf.placeholder("float32", [None, n_fod]) p_keep_hidden = tf.placeholder("float") Y_p_un = dk_model.davood_reg_net(X, n_feat_vec, p_keep_hidden,
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 track(params_file, directions="det", max_angle=30., sphere=None, seed_mask=None, seed_threshold=0, n_seeds=1, random_seeds=False, rng_seed=None, stop_mask=None, stop_threshold=0, step_size=0.5, min_length=10, max_length=1000, odf_model="DTI", tracker="local"): """ Tractography Parameters ---------- params_file : str, nibabel img. Full path to a nifti file containing CSD spherical harmonic coefficients, or nibabel img with model params. directions : str How tracking directions are determined. One of: {"det" | "prob"} max_angle : float, optional. The maximum turning angle in each step. Default: 30 sphere : Sphere object, optional. The discretization of direction getting. default: dipy.data.default_sphere. seed_mask : array, optional. Float or binary mask describing the ROI within which we seed for tracking. Default to the entire volume (all ones). seed_threshold : float, optional. A value of the seed_mask below which tracking is terminated. Default to 0. n_seeds : int or 2D array, optional. The seeding density: if this is an int, it is is how many seeds in each voxel on each dimension (for example, 2 => [2, 2, 2]). If this is a 2D array, these are the coordinates of the seeds. Unless random_seeds is set to True, in which case this is the total number of random seeds to generate within the mask. random_seeds : bool Whether to generate a total of n_seeds random seeds in the mask. Default: False. rng_seed : int random seed used to generate random seeds if random_seeds is set to True. Default: None stop_mask : array or str, optional. If array: A float or binary mask that determines a stopping criterion (e.g. FA). If tuple: it contains a sequence that is interpreted as: (pve_wm, pve_gm, pve_csf), each item of which is either a string (full path) or a nibabel img to be used in particle filtering tractography. A tuple is required if tracker is set to "pft". Defaults to no stopping (all ones). stop_threshold : float or tuple, optional. If float, this a value of the stop_mask below which tracking is terminated (and stop_mask has to be an array). If str, "CMC" for Continuous Map Criterion [Girard2014]_. "ACT" for Anatomically-constrained tractography [Smith2012]_. A string is required if the tracker is set to "pft". Defaults to 0 (this means that if no stop_mask is passed, we will stop only at the edge of the image). step_size : float, optional. The size (in mm) of a step of tractography. Default: 1.0 min_length: int, optional The miminal length (mm) in a streamline. Default: 10 max_length: int, optional The miminal length (mm) in a streamline. Default: 1000 odf_model : str, optional One of {"DTI", "CSD", "DKI", "MSMT"}. Defaults to use "DTI" tracker : str, optional Which strategy to use in tracking. This can be the standard local tracking ("local") or Particle Filtering Tracking ([Girard2014]_). One of {"local", "pft"}. Default: "local" Returns ------- list of streamlines () References ---------- .. [Girard2014] Girard, G., Whittingstall, K., Deriche, R., & Descoteaux, M. Towards quantitative connectivity analysis: reducing tractography biases. NeuroImage, 98, 266-278, 2014. """ logger = logging.getLogger('AFQ.tractography') logger.info("Loading Image...") if isinstance(params_file, str): params_img = nib.load(params_file) else: params_img = params_file model_params = params_img.get_fdata() affine = params_img.affine odf_model = odf_model.upper() directions = directions.lower() logger.info("Generating Seeds...") if isinstance(n_seeds, int): if seed_mask is None: seed_mask = np.ones(params_img.shape[:3]) elif seed_mask.dtype != 'bool': seed_mask = seed_mask > seed_threshold if random_seeds: seeds = dtu.random_seeds_from_mask(seed_mask, seeds_count=n_seeds, seed_count_per_voxel=False, affine=affine, random_seed=rng_seed) else: seeds = dtu.seeds_from_mask(seed_mask, density=n_seeds, affine=affine) else: # If user provided an array, we'll use n_seeds as the seeds: seeds = n_seeds if sphere is None: sphere = dpd.default_sphere logger.info("Getting Directions...") if directions == "det": dg = DeterministicMaximumDirectionGetter elif directions == "prob": dg = ProbabilisticDirectionGetter if odf_model == "DTI" or odf_model == "DKI" or odf_model == "FWDTI": evals = model_params[..., :3] evecs = model_params[..., 3:12].reshape(params_img.shape[:3] + (3, 3)) odf = tensor_odf(evals, evecs, sphere) dg = dg.from_pmf(odf, max_angle=max_angle, sphere=sphere) elif odf_model == "CSD" or "MSMT": dg = dg.from_shcoeff(model_params, max_angle=max_angle, sphere=sphere) if tracker == "local": if stop_mask is None: stop_mask = np.ones(params_img.shape[:3]) if stop_mask.dtype == 'bool': stopping_criterion = ThresholdStoppingCriterion(stop_mask, 0.5) else: stopping_criterion = ThresholdStoppingCriterion( stop_mask, stop_threshold) my_tracker = VerboseLocalTracking elif tracker == "pft": if not isinstance(stop_threshold, str): raise RuntimeError( "You are using PFT tracking, but did not provide a string ", "'stop_threshold' input. ", "Possible inputs are: 'CMC' or 'ACT'") if not (isinstance(stop_mask, Iterable) and len(stop_mask) == 3): raise RuntimeError( "You are using PFT tracking, but did not provide a length " "3 iterable for `stop_mask`. " "Expected a (pve_wm, pve_gm, pve_csf) tuple.") pves = [] pve_imgs = [] vox_sizes = [] for ii, pve in enumerate(stop_mask): if isinstance(pve, str): img = nib.load(pve) else: img = pve pve_imgs.append(img) pves.append(pve_imgs[-1].get_fdata()) average_voxel_size = np.mean(vox_sizes) pve_wm_img, pve_gm_img, pve_csf_img = pve_imgs pve_wm_data, pve_gm_data, pve_csf_data = pves pve_wm_data = resample(pve_wm_data, model_params[..., 0], pve_wm_img.affine, params_img.affine).get_fdata() pve_gm_data = resample(pve_gm_data, model_params[..., 0], pve_gm_img.affine, params_img.affine).get_fdata() pve_csf_data = resample(pve_csf_data, model_params[..., 0], pve_csf_img.affine, params_img.affine).get_fdata() vox_sizes.append(np.mean(params_img.header.get_zooms()[:3])) my_tracker = VerboseParticleFilteringTracking if stop_threshold == "CMC": stopping_criterion = CmcStoppingCriterion.from_pve( pve_wm_data, pve_gm_data, pve_csf_data, step_size=step_size, average_voxel_size=average_voxel_size) elif stop_threshold == "ACT": stopping_criterion = ActStoppingCriterion.from_pve( pve_wm_data, pve_gm_data, pve_csf_data) logger.info("Tracking...") return _tracking(my_tracker, seeds, dg, stopping_criterion, params_img, step_size=step_size, min_length=min_length, max_length=max_length, random_seed=rng_seed)
def sfm_tracking(name=None, data_path=None, output_path='.', Threshold=.20, data_list=None, return_streamlines=False, save_track=True, 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'] 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) from dipy.reconst.csdeconv import auto_response_ssst from dipy.reconst.shm import CsaOdfModel from dipy.data import default_sphere from dipy.direction import peaks_from_model response, ratio = auto_response_ssst(gtab, data, roi_radii=10, fa_thr=0.7) sphere = get_sphere() sf_model = sfm.SparseFascicleModel(gtab, sphere=sphere, l1_ratio=0.5, alpha=0.001, response=response[0]) pnm = peaks_from_model(sf_model, data, sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=white_matter, parallel=True) stopping_criterion = ThresholdStoppingCriterion(pnm.gfa, Threshold) #seeds = utils.seeds_from_mask(white_matter, affine, density=1) print('begin tracking, time:', time.time() - time0) streamline_generator = LocalTracking(pnm, stopping_criterion, seeds, affine, step_size=.5) streamlines = Streamlines(streamline_generator) print('begin saving, time:', time.time() - time0) from dipy.io.stateful_tractogram import Space, StatefulTractogram from dipy.io.streamline import save_trk if save_track: 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() output = output_path + '/tractogram_sfm_' + name + '.trk' save_trk(sft, output, streamlines) if return_streamlines: return streamlines
def run(context): #################################################### # Get the path to input files and other parameter # #################################################### analysis_data = context.fetch_analysis_data() settings = analysis_data['settings'] postprocessing = settings['postprocessing'] dataset = settings['dataset'] if dataset == "HCPL": dwi_file_handle = context.get_files('input', modality='HARDI')[0] dwi_file_path = dwi_file_handle.download('/root/') bvalues_file_handle = context.get_files( 'input', reg_expression='.*prep.bvalues.hcpl.txt')[0] bvalues_file_path = bvalues_file_handle.download('/root/') bvecs_file_handle = context.get_files( 'input', reg_expression='.*prep.gradients.hcpl.txt')[0] bvecs_file_path = bvecs_file_handle.download('/root/') elif dataset == "DSI": dwi_file_handle = context.get_files('input', modality='DSI')[0] dwi_file_path = dwi_file_handle.download('/root/') bvalues_file_handle = context.get_files( 'input', reg_expression='.*prep.bvalues.txt')[0] bvalues_file_path = bvalues_file_handle.download('/root/') bvecs_file_handle = context.get_files( 'input', reg_expression='.*prep.gradients.txt')[0] bvecs_file_path = bvecs_file_handle.download('/root/') else: context.set_progress(message='Wrong dataset parameter') inject_file_handle = context.get_files( 'input', reg_expression='.*prep.inject.nii.gz')[0] inject_file_path = inject_file_handle.download('/root/') VUMC_ROIs_file_handle = context.get_files( 'input', reg_expression='.*VUMC_ROIs.nii.gz')[0] VUMC_ROIs_file_path = VUMC_ROIs_file_handle.download('/root/') ############################### # _____ _____ _______ __ # # | __ \_ _| __ \ \ / / # # | | | || | | |__) \ \_/ / # # | | | || | | ___/ \ / # # | |__| || |_| | | | # # |_____/_____|_| |_| # # # ############################### ######################################################################################## # _______ _ __ __ _______ _ __ # # |__ __| | | | \/ | |__ __| | | / _| # # | |_ __ __ _ ___| | ___ _| \ / | ___| |_ __ __ _ ___| | _| |_ __ _ ___ ___ # # | | '__/ _` |/ __| |/ / | | | |\/| |/ __| | '__/ _` |/ __| |/ / _/ _` |/ __/ _ \ # # | | | | (_| | (__| <| |_| | | | | (__| | | | (_| | (__| <| || (_| | (_| __/ # # |_|_| \__,_|\___|_|\_\\__, |_| |_|\___|_|_| \__,_|\___|_|\_\_| \__,_|\___\___| # # __/ | # # |___/ # # # # # # IronTract Team # ######################################################################################## ################# # Load the data # ################# dwi_img = nib.load(dwi_file_path) bvals, bvecs = read_bvals_bvecs(bvalues_file_path, bvecs_file_path) gtab = gradient_table(bvals, bvecs) ############################################ # Extract the brain mask from the b0 image # ############################################ _, brain_mask = median_otsu(dwi_img.get_data()[:, :, :, 0], median_radius=2, numpass=1) ################################################################## # Fit the tensor model and compute the fractional anisotropy map # ################################################################## context.set_progress(message='Processing voxel-wise DTI metrics.') tenmodel = TensorModel(gtab) tenfit = tenmodel.fit(dwi_img.get_data(), mask=brain_mask) FA = fractional_anisotropy(tenfit.evals) stopping_criterion = ThresholdStoppingCriterion(FA, 0.2) sphere = get_sphere("repulsion724") seed_mask_img = nib.load(inject_file_path) affine = seed_mask_img.affine seeds = utils.random_seeds_from_mask(seed_mask_img.get_data(), affine, seed_count_per_voxel=True, seeds_count=5000) if dataset == "HCPL": ################################################ # Compute Fiber Orientation Distribution (CSD) # ################################################ context.set_progress(message='Processing voxel-wise FOD estimation.') response, _ = auto_response_ssst(gtab, dwi_img.get_data(), roi_radii=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) csd_fit = csd_model.fit(dwi_img.get_data(), mask=brain_mask) shm = csd_fit.shm_coeff prob_dg = ProbabilisticDirectionGetter.from_shcoeff(shm, max_angle=20., sphere=sphere, pmf_threshold=0.1) elif dataset == "DSI": context.set_progress(message='Processing voxel-wise DSI estimation.') dsmodel = DiffusionSpectrumModel(gtab) dsfit = dsmodel.fit(dwi_img.get_data()) ODFs = dsfit.odf(sphere) prob_dg = ProbabilisticDirectionGetter.from_pmf(ODFs, max_angle=20., sphere=sphere, pmf_threshold=0.01) ########################################### # Compute DIPY Probabilistic Tractography # ########################################### context.set_progress(message='Processing tractography.') streamline_generator = LocalTracking(prob_dg, stopping_criterion, seeds, affine, step_size=.2, max_cross=1) streamlines = Streamlines(streamline_generator) # sft = StatefulTractogram(streamlines, seed_mask_img, Space.RASMM) # streamlines_file_path = "/root/streamlines.trk" # save_trk(sft, streamlines_file_path) ########################################################################### # Compute 3D volumes for the IronTract Challenge. For 'EPFL', we only # # keep streamlines with length > 1mm. We compute the visitation count # # image and apply a small gaussian smoothing. The gaussian smoothing # # is especially usefull to increase voxel coverage of deterministic # # algorithms. The log of the smoothed visitation count map is then # # iteratively thresholded producing 200 volumes/operation points. # # For VUMC, additional streamline filtering is done using anatomical # # priors (keeping only streamlines that intersect with at least one ROI). # ########################################################################### if postprocessing in ["EPFL", "ALL"]: context.set_progress(message='Processing density map (EPFL)') volume_folder = "/root/vol_epfl" output_epfl_zip_file_path = "/root/TrackyMcTrackface_EPFL_example.zip" os.mkdir(volume_folder) lengths = length(streamlines) streamlines = streamlines[lengths > 1] density = utils.density_map(streamlines, affine, seed_mask_img.shape) density = scipy.ndimage.gaussian_filter(density.astype("float32"), 0.5) log_density = np.log10(density + 1) max_density = np.max(log_density) for i, t in enumerate(np.arange(0, max_density, max_density / 200)): nbr = str(i) nbr = nbr.zfill(3) mask = log_density >= t vol_filename = os.path.join(volume_folder, "vol" + nbr + "_t" + str(t) + ".nii.gz") nib.Nifti1Image(mask.astype("int32"), affine, seed_mask_img.header).to_filename(vol_filename) shutil.make_archive(output_epfl_zip_file_path[:-4], 'zip', volume_folder) if postprocessing in ["VUMC", "ALL"]: context.set_progress(message='Processing density map (VUMC)') ROIs_img = nib.load(VUMC_ROIs_file_path) volume_folder = "/root/vol_vumc" output_vumc_zip_file_path = "/root/TrackyMcTrackface_VUMC_example.zip" os.mkdir(volume_folder) lengths = length(streamlines) streamlines = streamlines[lengths > 1] rois = ROIs_img.get_fdata().astype(int) _, grouping = utils.connectivity_matrix(streamlines, affine, rois, inclusive=True, return_mapping=True, mapping_as_streamlines=False) streamlines = streamlines[grouping[(0, 1)]] density = utils.density_map(streamlines, affine, seed_mask_img.shape) density = scipy.ndimage.gaussian_filter(density.astype("float32"), 0.5) log_density = np.log10(density + 1) max_density = np.max(log_density) for i, t in enumerate(np.arange(0, max_density, max_density / 200)): nbr = str(i) nbr = nbr.zfill(3) mask = log_density >= t vol_filename = os.path.join(volume_folder, "vol" + nbr + "_t" + str(t) + ".nii.gz") nib.Nifti1Image(mask.astype("int32"), affine, seed_mask_img.header).to_filename(vol_filename) shutil.make_archive(output_vumc_zip_file_path[:-4], 'zip', volume_folder) ################### # Upload the data # ################### context.set_progress(message='Uploading results...') #context.upload_file(fa_file_path, 'fa.nii.gz') # context.upload_file(fod_file_path, 'fod.nii.gz') # context.upload_file(streamlines_file_path, 'streamlines.trk') if postprocessing in ["EPFL", "ALL"]: context.upload_file(output_epfl_zip_file_path, 'TrackyMcTrackface_' + dataset +'_EPFL.zip') if postprocessing in ["VUMC", "ALL"]: context.upload_file(output_vumc_zip_file_path, 'TrackyMcTrackface_' + dataset +'_VUMC.zip')
def get_csd_streamlines(data_container, random_seeds=False, seeds_count=30000, seeds_per_voxel=False, step_width=1.0, roi_r=10, auto_response_fa_threshold=0.7, fa_threshold=0.15, relative_peak_threshold=0.5, min_separation_angle=25): """ 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 roi_r The radii of the cuboid roi for the automatic estimation of single-shell single-tissue response function using FA. auto_response_fa_threshold The FA threshold for the automatic estimation of single-shell single-tissue response function using FA. fa_threshold The FA threshold to use to stop tracking relative_peak_threshold The relative peak threshold to use to get peaks from the CSDModel min_separation_angle The minimal separation angle of peaks Returns ------- Streamlines A list of Streamlines """ seeds = _get_seeds(data_container, random_seeds, seeds_count, seeds_per_voxel) response, _ = auto_response_ssst(data_container.gtab, data_container.dwi, roi_radii=roi_r, fa_thr=auto_response_fa_threshold) csd_model = ConstrainedSphericalDeconvModel(data_container.gtab, response) direction_getter = peaks_from_model( model=csd_model, data=data_container.dwi, sphere=get_sphere('symmetric724'), mask=data_container.binary_mask, relative_peak_threshold=relative_peak_threshold, min_separation_angle=min_separation_angle, parallel=False) dti_fit = dti.TensorModel(data_container.gtab, fit_method='LS').fit( data_container.dwi, mask=data_container.binary_mask) 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(params_file, directions="det", max_angle=30., sphere=None, seed_mask=None, n_seeds=1, random_seeds=False, stop_mask=None, stop_threshold=0, step_size=0.5, min_length=10, max_length=1000, odf_model="DTI"): """ Tractography Parameters ---------- params_file : str, nibabel img. Full path to a nifti file containing CSD spherical harmonic coefficients, or nibabel img with model params. directions : str How tracking directions are determined. One of: {"deterministic" | "probablistic"} max_angle : float, optional. The maximum turning angle in each step. Default: 30 sphere : Sphere object, optional. The discretization of direction getting. default: dipy.data.default_sphere. seed_mask : array, optional. Binary mask describing the ROI within which we seed for tracking. Default to the entire volume. n_seeds : int or 2D array, optional. The seeding density: if this is an int, it is is how many seeds in each voxel on each dimension (for example, 2 => [2, 2, 2]). If this is a 2D array, these are the coordinates of the seeds. Unless random_seeds is set to True, in which case this is the total number of random seeds to generate within the mask. random_seeds : bool Whether to generate a total of n_seeds random seeds in the mask. Default: XXX. stop_mask : array, optional. A floating point value that determines a stopping criterion (e.g. FA). Default to no stopping (all ones). stop_threshold : float, optional. A value of the stop_mask below which tracking is terminated. Default to 0 (this means that if no stop_mask is passed, we will stop only at the edge of the image) step_size : float, optional. The size (in mm) of a step of tractography. Default: 1.0 min_length: int, optional The miminal length (mm) in a streamline. Default: 10 max_length: int, optional The miminal length (mm) in a streamline. Default: 250 odf_model : str, optional One of {"DTI", "CSD"}. Defaults to use "DTI" Returns ------- list of streamlines () """ logger = logging.getLogger('AFQ.tractography') logger.info("Loading Image...") if isinstance(params_file, str): params_img = nib.load(params_file) else: params_img = params_file model_params = params_img.get_fdata() affine = params_img.affine logger.info("Generating Seeds...") if isinstance(n_seeds, int): if seed_mask is None: seed_mask = np.ones(params_img.shape[:3]) if random_seeds: seeds = dtu.random_seeds_from_mask(seed_mask, seeds_count=n_seeds, seed_count_per_voxel=False, affine=affine) else: seeds = dtu.seeds_from_mask(seed_mask, density=n_seeds, affine=affine) else: # If user provided an array, we'll use n_seeds as the seeds: seeds = n_seeds if sphere is None: sphere = dpd.default_sphere logger.info("Getting Directions...") if directions == "det": dg = DeterministicMaximumDirectionGetter elif directions == "prob": dg = ProbabilisticDirectionGetter if odf_model == "DTI" or odf_model == "DKI": evals = model_params[..., :3] evecs = model_params[..., 3:12].reshape(params_img.shape[:3] + (3, 3)) odf = tensor_odf(evals, evecs, sphere) dg = dg.from_pmf(odf, max_angle=max_angle, sphere=sphere) elif odf_model == "CSD": dg = dg.from_shcoeff(model_params, max_angle=max_angle, sphere=sphere) if stop_mask is None: stop_mask = np.ones(params_img.shape[:3]) threshold_classifier = ThresholdStoppingCriterion(stop_mask, stop_threshold) logger.info("Tracking...") return _local_tracking(seeds, dg, threshold_classifier, params_img, step_size=step_size, min_length=min_length, max_length=max_length)
def tracking(image, bvecs, bvals, wm, seeds, fibers, prune_length=3, rseed=42, plot=False, proba=False, verbose=False): # Pipelines transcribed from: # https://dipy.org/documentation/1.1.1./examples_built/tracking_introduction_eudx/#example-tracking-introduction-eudx # https://dipy.org/documentation/1.1.1./examples_built/tracking_probabilistic/ # Load Images dwi_loaded = nib.load(image) dwi_data = dwi_loaded.get_fdata() wm_loaded = nib.load(wm) wm_data = wm_loaded.get_fdata() seeds_loaded = nib.load(seeds) seeds_data = seeds_loaded.get_fdata() seeds = utils.seeds_from_mask(seeds_data, dwi_loaded.affine, density=2) # Load B-values & B-vectors # NB. Use aligned b-vecs if providing eddy-aligned data bvals, bvecs = read_bvals_bvecs(bvals, bvecs) gtab = gradient_table(bvals, bvecs) csa_model = CsaOdfModel(gtab, sh_order=6) # Set stopping criterion gfa = csa_model.fit(dwi_data, mask=wm_data).gfa stop_criterion = ThresholdStoppingCriterion(gfa, .25) if proba: # Establish ODF model response, ratio = auto_response(gtab, dwi_data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(dwi_data, mask=wm_data) # Create Probabilisitic direction getter fod = csd_fit.odf(default_sphere) pmf = fod.clip(min=0) prob_dg = ProbabilisticDirectionGetter.from_pmf(pmf, max_angle=30., sphere=default_sphere) # Use the probabilisitic direction getter as the dg dg = prob_dg else: # Establish ODF model csa_peaks = peaks_from_model(csa_model, dwi_data, default_sphere, relative_peak_threshold=0.8, min_separation_angle=45, mask=wm_data) # Use the CSA peaks as the dg dg = csa_peaks # Create generator and perform tracing s_generator = LocalTracking(dg, stop_criterion, seeds, dwi_loaded.affine, 0.5, random_seed=rseed) streamlines = Streamlines(s_generator) # Prune streamlines streamlines = ArraySequence( [strline for strline in streamlines if len(strline) > prune_length]) sft = StatefulTractogram(streamlines, dwi_loaded, Space.RASMM) # Save streamlines save_trk(sft, fibers + ".trk") # Visualize fibers if plot and has_fury: from dipy.viz import window, actor, colormap as cmap # Create the 3D display. r = window.Renderer() r.add(actor.line(streamlines, cmap.line_colors(streamlines))) window.record(r, out_path=fibers + '.png', size=(800, 800))
hardi_img, gtab, labels_img = read_stanford_labels() data = hardi_img.get_data() labels = labels_img.get_data() affine = hardi_img.affine white_matter = (labels == 1) | (labels == 2) csa_model = CsaOdfModel(gtab, sh_order=6) csa_peaks = peaks_from_model(csa_model, data, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=white_matter) stopping_criterion = ThresholdStoppingCriterion(csa_peaks.gfa, .25) seed_mask = labels == 2 seeds = utils.seeds_from_mask(seed_mask, affine, density=[1, 1, 1]) # Initialization of LocalTracking. The computation happens in the next step. streamlines = LocalTracking(csa_peaks, stopping_criterion, seeds, affine, step_size=2) # Compute streamlines and store as a list. streamlines = Streamlines(streamlines) """ We will create a streamline actor from the 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]))
def test_probabilistic_odf_weighted_tracker(): """This tests that the Probabalistic 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.], [.6, .4, 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 = ProbabilisticDirectionGetter.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.]]) ] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y) path = [False, False] for sl in streamlines: if allclose(sl, expected[0]): path[0] = True elif allclose(sl, expected[1]): path[1] = True else: raise AssertionError() npt.assert_(all(path)) # The first path is not possible if 90 degree turns are excluded dg = ProbabilisticDirectionGetter.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])) # The first path is not possible if pmf_threshold > 0.67 # 0.4/0.6 < 2/3, multiplying the pmf should not change the ratio dg = ProbabilisticDirectionGetter.from_pmf(10 * pmf, 90, sphere, pmf_threshold=0.67) streamlines = LocalTracking(dg, sc, seeds, np.eye(4), 1.) for sl in streamlines: npt.assert_(np.allclose(sl, expected[1])) # Test non WM seed position seeds = [[0, 0, 0], [5, 5, 5]] streamlines = LocalTracking(dg, sc, seeds, np.eye(4), 0.2, max_cross=1, return_all=True) streamlines = Streamlines(streamlines) npt.assert_(len(streamlines[0]) == 1) # INVALIDPOINT npt.assert_(len(streamlines[1]) == 1) # OUTSIDEIMAGE # Test that all points are within the image volume seeds = seeds_from_mask(np.ones(mask.shape), np.eye(4), density=2) streamline_generator = LocalTracking(dg, sc, seeds, np.eye(4), 0.5, return_all=True) streamlines = Streamlines(streamline_generator) for s in streamlines: npt.assert_(np.all((s + 0.5).astype(int) >= 0)) npt.assert_(np.all((s + 0.5).astype(int) < mask.shape)) # Test that the number of streamline return with return_all=True equal the # number of seeds places npt.assert_(np.array([len(streamlines) == len(seeds)])) # Test reproducibility tracking_1 = Streamlines( LocalTracking(dg, sc, seeds, np.eye(4), 0.5, random_seed=0))._data tracking_2 = Streamlines( LocalTracking(dg, sc, seeds, np.eye(4), 0.5, random_seed=0))._data npt.assert_equal(tracking_1, tracking_2)
def tracking(folder): print('Tracking in ' + folder) output_folder = folder + 'dipy_out/' # make a folder to save new data into try: Path(output_folder).mkdir(parents=True, exist_ok=True) except OSError: print('Could not create output dir. Aborting...') return # load data print('Loading data...') img = nib.load(folder + 'data.nii.gz') dmri = np.asarray(img.dataobj) affine = img.affine mask, _ = load_nifti(folder + 'nodif_brain_mask.nii.gz') bvals, bvecs = read_bvals_bvecs(folder + 'bvals', folder + 'bvecs') gtab = gradient_table(bvals, bvecs) # extract peaksoutput_folder + 'peak_vals.nii.gz' if Path(output_folder + 'peaks.pam5').exists(): peaks = load_peaks(output_folder + 'peaks.pam5') else: print('Extracting peaks...') response, ration = auto_response(gtab, dmri, roi_radius=10, fa_thr=.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) peaks = peaks_from_model(model=csd_model, data=dmri, sphere=default_sphere, relative_peak_threshold=.5, min_separation_angle=25, parallel=True) save_peaks(output_folder + 'peaks.pam5', peaks, affine) scaled = peaks.peak_dirs * np.repeat( np.expand_dims(peaks.peak_values, -1), 3, -1) cropped = scaled[:, :, :, :3, :].reshape(dmri.shape[:3] + (9, )) save_nifti(output_folder + 'peaks.nii.gz', cropped, affine) #save_nifti(output_folder + 'peak_dirs.nii.gz', peaks.peak_dirs, affine) #save_nifti(output_folder + 'peak_vals.nii.gz', peaks.peak_values, affine) # tracking print('Tracking...') maskdata, mask = median_otsu(dmri, vol_idx=range(0, dmri.shape[3]), median_radius=3, numpass=1, autocrop=True, dilate=2) tensor_model = TensorModel(gtab, fit_method='WLS') tensor_fit = tensor_model.fit(maskdata) fa = fractional_anisotropy(tensor_fit.evals) fa[np.isnan(fa)] = 0 bla = np.average(fa) tissue_classifier = ThresholdStoppingCriterion(fa, .1) seeds = random_seeds_from_mask(fa > 1e-5, affine, seeds_count=1) streamline_generator = LocalTracking(direction_getter=peaks, stopping_criterion=tissue_classifier, seeds=seeds, affine=affine, step_size=.5) streamlines = Streamlines(streamline_generator) save_trk(StatefulTractogram(streamlines, img, Space.RASMM), output_folder + 'whole_brain.trk')
- 'ENDPOINT': stops at a position where metric_map < threshold; the streamline reached the target stopping area. - 'OUTSIDEIMAGE': stops at a position outside of metric_map; the streamline reached an area outside the image where no direction data is available. - 'TRACKPOINT': stops at a position because no direction is available; the streamline is stopping where metric_map >= threshold, but there is no valid direction to follow. - 'INVALIDPOINT': N/A. """ tensor_model = TensorModel(gtab) tenfit = tensor_model.fit(data, mask=labels > 0) FA = fractional_anisotropy(tenfit.evals) threshold_criterion = ThresholdStoppingCriterion(FA, .2) fig = plt.figure() mask_fa = FA.copy() mask_fa[mask_fa < 0.2] = 0 plt.xticks([]) plt.yticks([]) plt.imshow(mask_fa[:, :, data.shape[2] // 2].T, cmap='gray', origin='lower', interpolation='nearest') fig.tight_layout() fig.savefig('threshold_fa.png') """ .. figure:: threshold_fa.png :align: center
sphere=sphere) rumba_fit = rumba.fit(data, mask=white_matter) odf = rumba_fit.odf() # fODF f_wm = rumba_fit.f_wm # white matter volume fractions """ To establish stopping criterion, a common technique is to use the Generalized Fractional Anisotropy (GFA). One point of caution is that RUMBA-SD by default separates the fODF from an isotropic compartment. This can bias GFA results computed on the fODF, although it will still generally be an effective criterion. However, an alternative stopping criterion that takes advantage of this feature is to use RUMBA-SD's white matter volume fraction map. """ stopping_criterion = ThresholdStoppingCriterion(f_wm, .25) """ We can visualize a slice of this mask. """ import matplotlib.pyplot as plt sli = f_wm.shape[2] // 2 plt.figure() plt.subplot(1, 2, 1).set_axis_off() plt.imshow(f_wm[:, :, sli].T, cmap='gray', origin='lower') plt.subplot(1, 2, 2).set_axis_off() plt.imshow((f_wm[:, :, sli] > 0.25).T, cmap='gray', origin='lower')
seed_mask = (labels == 2) white_matter = (labels == 1) | (labels == 2) seeds = utils.seeds_from_mask(seed_mask, affine, density=1) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) """ We use the GFA of the CSA model to build a stopping criterion. """ from dipy.reconst.shm import CsaOdfModel csa_model = CsaOdfModel(gtab, sh_order=6) gfa = csa_model.fit(data, mask=white_matter).gfa stopping_criterion = ThresholdStoppingCriterion(gfa, .25) """ The Fiber Orientation Distribution (FOD) of the CSD model estimates the distribution of small fiber bundles within each voxel. We can use this distribution for probabilistic fiber tracking. One way to do this is to represent the FOD using a discrete sphere. This discrete FOD can be used by the ``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.stateful_tractogram import Space, StatefulTractogram from dipy.io.streamline import save_trk
def QCSA_tractmake(data, affine, vox_size, gtab, mask, masktype, header, step_size, peak_processes, outpathtrk, subject='NA', ratio=1, overwrite=False, get_params=False, doprune=False, figspath=None, verbose=None): # Compute odfs in Brain Mask t2 = time() if os.path.isfile(outpathtrk) and not overwrite: txt = "Subject already saved at "+outpathtrk print(txt) streamlines_generator = None params = None return outpathtrk, streamlines_generator, params csa_model = CsaOdfModel(gtab, 6) if peak_processes == 1: parallel = False else: parallel = True if verbose: send_mail("Starting calculation of Constant solid angle model for subject " + subject,subject="CSA model start") wholemask = np.where(mask == 0, False, True) print(f"There are {peak_processes} and {parallel} here") csa_peaks = peaks_from_model(model=csa_model, data=data, sphere=peaks.default_sphere, # issue with complete sphere mask=wholemask, relative_peak_threshold=.5, min_separation_angle=25, parallel=parallel, nbr_processes=peak_processes) duration = time() - t2 if verbose: print(subject + ' CSA duration %.3f' % (duration,)) t3 = time() if verbose: send_mail('Computing classifier for local tracking for subject ' + subject + ',it has been ' + str(round(duration)) + 'seconds since the start of tractmaker',subject="Seed computation" ) print('Computing classifier for local tracking for subject ' + subject) if masktype == "FA": #tensor_model = dti.TensorModel(gtab) #tenfit = tensor_model.fit(data, mask=labels > 0) #FA = fractional_anisotropy(tenfit.evals) FA_threshold = 0.05 classifier = ThresholdStoppingCriterion(mask, FA_threshold) if figspath is not None: fig = plt.figure() mask_fa = mask.copy() mask_fa[mask_fa < FA_threshold] = 0 plt.xticks([]) plt.yticks([]) plt.imshow(mask_fa[:, :, data.shape[2] // 2].T, cmap='gray', origin='lower', interpolation='nearest') fig.tight_layout() fig.savefig(figspath + 'threshold_fa.png') else: classifier = BinaryStoppingCriterion(wholemask) # generates about 2 seeds per voxel # seeds = utils.random_seeds_from_mask(fa > .2, seeds_count=2, # affine=np.eye(4)) # generates about 2 million streamlines # seeds = utils.seeds_from_mask(fa > .2, density=1, # affine=np.eye(4)) if verbose: print('Computing seeds') seeds = utils.seeds_from_mask(wholemask, density=1, affine=np.eye(4)) #streamlines_generator = local_tracking.local_tracker(csa_peaks,classifier,seeds,affine=np.eye(4),step_size=step_size) if verbose: print('Computing the local tracking') duration = time() - t2 send_mail('Start of the local tracking ' + ',it has been ' + str(round(duration)) + 'seconds since the start of tractmaker', subject="Seed computation") #stepsize = 2 #(by default) stringstep = str(step_size) stringstep = stringstep.replace(".", "_") if verbose: print("stringstep is "+stringstep) streamlines_generator = LocalTracking(csa_peaks, classifier, seeds, affine=np.eye(4), step_size=step_size) if verbose: duration = time() - t2 txt = 'About to save streamlines at ' + outpathtrk + ',it has been ' + str(round(duration)) + \ 'seconds since the start of tractmaker', send_mail(txt,subject="Tract saving" ) cutoff = 2 if doprune: streamlines_generator = prune_streamlines(list(streamlines_generator), data[:, :, :, 0], cutoff=cutoff, verbose=verbose) myheader = create_tractogram_header(outpathtrk, *header) sg = lambda: (s for i, s in enumerate(streamlines_generator) if i % ratio == 0) save_trk_heavy_duty(outpathtrk, streamlines=sg, affine=affine, header=myheader, shape=mask.shape, vox_size=vox_size) else: sg = lambda: (s for i, s in enumerate(streamlines_generator) if i % ratio == 0) myheader = create_tractogram_header(outpathtrk, *header) save_trk_heavy_duty(outpathtrk, streamlines=sg, affine=affine, header=myheader, shape=mask.shape, vox_size=vox_size) if verbose: duration = time() - t2 txt = "Tract files were saved at "+outpathtrk + ',it has been ' + str(round(duration)) + \ 'seconds since the start of tractmaker' print(txt) send_mail(txt,subject="Tract saving" ) # save everything - will generate a 20+ GBytes of data - hard to manipulate # possibly add parameter in csv file or other to decide whether to save large tractogram file # outpathfile=outpath+subject+"bmCSA_detr"+stringstep+".trk" # myheader=create_tractogram_header(outpathfile,*get_reference_info(fdwi)) duration3 = time() - t2 if verbose: print(duration3) print(subject + ' Tracking duration %.3f' % (duration3,)) send_mail("Finished file save at "+outpathtrk+" with tracking duration of " + str(duration3) + "seconds", subject="file save update" ) if get_params: numtracts, minlength, maxlength, meanlength, stdlength = get_trk_params(streamlines_generator, verbose) params = [numtracts, minlength, maxlength, meanlength, stdlength] if verbose: print("For subject " + str(subject) + " the number of tracts is " + str(numtracts) + ", the minimum length is " + str(minlength) + ", the maximum length is " + str(maxlength) + ", the mean length is " + str(meanlength) + ", the std is " + str(stdlength)) else: params = None return outpathtrk, streamlines_generator, params