def tracking_prob(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 = ProbabilisticDirectionGetter.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_prob_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 track(model, data, sphere=None, step_size=1, angle_limit=20, seeds=None, density=[2,2,2], voxel_size=[1,1,1]): """ Interface for tracking based on fiber ODF models `model` needs to have a `fit` method, such that model.fit(data).odf(sphere) is a legitimate ODF (that is has dimensions (x,y,z, n_vertices), where n_vertices refers to the vertices of the provided sphere. """ # If no sphere is provided, we will use the dipy symmetrical sphere with # 724 vertcies. That should be enough if sphere is None: sphere = dpd.get_sphere('symmetric724') stepper = dpt.FixedSizeStepper(step_size) interpolator = dpt.NearestNeighborInterpolator(data, voxel_size) if seeds is None: seeds = dpu.seeds_from_mask(mask, density, voxel_size) pwt = dpt.ProbabilisticOdfWeightedTracker(model, interpolator, mask, stepper, angle_limit, seeds, sphere) pwt_streamlines = list(pwt) fibers = [] for f in pwt_streamlines: fibers.append(ozf.Fiber(f))
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_seeds_from_mask(): mask = np.random.random_integers(0, 1, size=(10, 10, 10)) seeds = seeds_from_mask(mask, density=1) assert_equal(mask.sum(), len(seeds)) assert_array_equal(np.argwhere(mask), seeds) mask[:] = False mask[3, 3, 3] = True seeds = seeds_from_mask(mask, density=[3, 4, 5]) assert_equal(len(seeds), 3 * 4 * 5) assert_true(np.all((seeds > 2.5) & (seeds < 3.5))) mask[4, 4, 4] = True seeds = seeds_from_mask(mask, density=[3, 4, 5]) assert_equal(len(seeds), 2 * 3 * 4 * 5) assert_true(np.all((seeds > 2.5) & (seeds < 4.5))) in_333 = ((seeds > 2.5) & (seeds < 3.5)).all(1) assert_equal(in_333.sum(), 3 * 4 * 5) in_444 = ((seeds > 3.5) & (seeds < 4.5)).all(1) assert_equal(in_444.sum(), 3 * 4 * 5)
def runStream(csd_peaks, roi_file, roi_label=1, ang_thr=45., a_low=0.2, step_size=0.1, seeds_per_voxel=30, out_name=None): img = nib.load(roi_file) affine = img.get_affine() mask_data = img.get_data() p = np.asarray(np.where(mask_data == roi_label)) p = p.transpose() # seed_points = None # for i in p: # points = np.random.uniform(size=[seeds_per_voxel,3]) + (i-0.5) # if seed_points is None: # seed_points = points # else: # seed_points = np.concatenate([seed_points, points], axis=0) import dipy.tracking.utils as utils seeds = utils.seeds_from_mask(mask_data==1, density=seeds_per_voxel) print '# of seeds: ',len(seeds) sphere = get_sphere('symmetric724') print "seed eudx tractography" eu = EuDX(csd_peaks.peak_values, csd_peaks.peak_indices, odf_vertices=sphere.vertices, step_sz=step_size, seeds=seeds, ang_thr=ang_thr, a_low=a_low) csa_streamlines_mult_peaks = [streamline for streamline in eu] out_file = 'tracts.dipy' if out_name: out_file = out_name+'_'+out_file from dipy.io.trackvis import save_trk save_trk(out_file, csa_streamlines_mult_peaks, affine, mask.shape) dpw = Dpy(out_file, 'w') dpw.write_tracks(csa_streamlines_mult_peaks) print 'write tracts to %s' % out_file return (csa_streamlines_mult_peaks, out_file)
def simple_tracking_function(data, fa, bval, bvec, seed_mask, start_steps, voxel_size, density): """An example of a simple traking function using the tools in dipy This tracking function uses the SlowAdcOpdfModel to fit diffusion data. By using the ClosestPeakSelector, the function tracks along the peak of Opdf closest to the incoming direction. It also uses the BoundryIntegrator to integrate the streamlines and NearestNeighborInterpolator to interpolate the data. The ResidualBootstrap means the tracks are probabilistic, not deterministic. """ #the interpolator allows us to index the dwi data in continous space data_mask = fa > .2 normalized_data = normalize_data(data, bval) interpolator = NearestNeighborInterpolator(normalized_data, voxel_size, data_mask) #the model fits the dwi data, this model can resolve crossing fibers #see documentation of SlowAdcOpdfModel for more info model = SlowAdcOpdfModel(6, bval, bvec, .006) vert, edges, faces = create_half_unit_sphere(4) model.set_sampling_points(vert, edges) #this residual bootstrap wrapper returns a sample from the bootstrap #distribution istead of returning the raw data min_signal = normalized_data.min() B = model.B wrapped_interp = ResidualBootstrapWrapper(interpolator, B, min_signal) #the peakselector returns the closest peak to the incoming direction when #in voxels with multiple peaks peak_finder = ClosestPeakSelector(model, wrapped_interp) peak_finder.angle_limit = 60 seeds = seeds_from_mask(seed_mask, density, voxel_size) #the propagator is used to integrate the streamlines propogator = BoundryIntegrator(voxel_size) tracks = generate_streamlines(peak_finder, propogator, seeds, start_steps) return tracks
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 _core_run(self, stopping_path, stopping_thr, seeding_path, seed_density, direction_getter, 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') 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))
stopping_thr = 0.25 pam = load_peaks(fpeaks) ffa = dname + "fa.nii.gz" fa, fa_affine = load_nifti(ffa) classifier = ThresholdTissueClassifier(fa, stopping_thr) seed_density = 1 seed_mask = fa > 0.4 seeds = utils.seeds_from_mask(seed_mask, density=seed_density, affine=affine) # if use_sh: # detmax_dg = \ # DeterministicMaximumDirectionGetter.from_shcoeff( # pam.shm_coeff, # max_angle=30., # sphere=pam.sphere) # # streamlines = \ # LocalTracking(detmax_dg, classifier, seeds, affine, # step_size=.5) # # else: streamlines = LocalTracking(pam, classifier, seeds, affine=affine, step_size=0.5)
def fiber_tracking(peaks, mask): print "Start Fibertracking" seeds = utils.seeds_from_mask(mask, density=[2, 2, 2]) streamline_generator = EuDX(peaks.peak_values, peaks.peak_indices, odf_vertices=peaks.sphere.vertices, a_low=.05, step_sz=.5, seeds=seeds) streamlines = list(streamline_generator) return streamlines
stepper = FixedSizeStepper(1) """ Read the voxel size from the image header: """ zooms = img.get_header().get_zooms()[:3] """ Randomly select some seed points from the mask: """ seeds = seeds_from_mask(mask, [1, 1, 1], zooms) seeds = seeds[:2000] interpolator = NearestNeighborInterpolator(maskdata, zooms) pwt = ProbabilisticOdfWeightedTracker(csamodel, interpolator, mask, stepper, 20, seeds, sphere) csa_streamlines = list(pwt) """ Now that we have our streamlines in memory we can save the results to disk. For this purpose we can use the TrackVis format (``*.trk``). First, we need to create a header. """ import nibabel as nib
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 ProbabilisticDirectionGetter prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=45., sphere=default_sphere) # Tracking from dipy.tracking.local import LocalTracking streamlines = LocalTracking(prob_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 + '_CSDprob.trk', streamlines, affine, fa.shape) return runtime
""" A ThresholdTissueClassifier object is used to segment the data to track only through areas in which the Generalized Fractional Anisotropy (GFA) is sufficiently high. """ from dipy.tracking.local import ThresholdTissueClassifier classifier = ThresholdTissueClassifier(pnm.gfa, .25) """ Tracking will be started from a set of seeds evenly distributed in the white matter: """ from dipy.tracking import utils seeds = utils.seeds_from_mask(white_matter, density=[2, 2, 2], affine=affine) """ For the sake of brevity, we will take only the first 1000 seeds, generating only 1000 streamlines. Remove this line to track from many more points in all of the white matter """ seeds = seeds[:1000] """ We now have the necessary components to construct a tracking pipeline and execute the tracking """ from dipy.tracking.local import LocalTracking
def track(dname, fdwi, fbval, fbvec, fmask=None, seed_density = 1, show=False): data, affine = load_nifti(fdwi) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs, b0_threshold=50) if fmask is None: from dipy.segment.mask import median_otsu b0_mask, mask = median_otsu(data) # TODO: check parameters to improve the mask else: mask, mask_affine = load_nifti(fmask) mask = np.squeeze(mask) #fix mask dimensions # compute DTI model from dipy.reconst.dti import TensorModel tenmodel = TensorModel(gtab)#, fit_method='OLS') #, min_signal=5000) # fit the dti model tenfit = tenmodel.fit(data, mask=mask) # save fa ffa = dname + 'tensor_fa.nii.gz' fa_img = nib.Nifti1Image(tenfit.fa.astype(np.float32), affine) nib.save(fa_img, ffa) sh_order = 8 #TODO: check what that does if data.shape[-1] < 15: raise ValueError('You need at least 15 unique DWI volumes to ' 'compute fiber ODFs. You currently have: {0}' ' DWI volumes.'.format(data.shape[-1])) elif data.shape[-1] < 30: sh_order = 6 # compute the response equation ? from dipy.reconst.csdeconv import auto_response response, ratio = auto_response(gtab, data) response = list(response) peaks_sphere = get_sphere('symmetric362') #TODO: check what that does peaks_csd = peaks_from_model(model=tenmodel, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, #.5 min_separation_angle=25, mask=mask, return_sh=True, sh_order=sh_order, normalize_peaks=True, parallel=False) peaks_csd.affine = affine fpeaks = dname + 'peaks.npz' save_peaks(fpeaks, peaks_csd) from dipy.io.trackvis import save_trk from dipy.tracking import utils from dipy.tracking.local import (ThresholdTissueClassifier, LocalTracking) stopping_thr = 0.25 #0.25 pam = load_peaks(fpeaks) #ffa = dname + 'tensor_fa_nomask.nii.gz' fa, fa_affine = load_nifti(ffa) classifier = ThresholdTissueClassifier(fa, stopping_thr) # seeds seed_mask = fa > 0.4 #0.4 #TODO: check this parameter seeds = utils.seeds_from_mask( seed_mask, density=seed_density, affine=affine) # tractography, if affine then in world coordinates streamlines = LocalTracking(pam, classifier, seeds, affine=affine, step_size=.5) # Compute streamlines and store as a list. streamlines = list(streamlines) ftractogram = dname + 'tractogram.trk' #save .trk save_trk_old_style(ftractogram, streamlines, affine, fa.shape) if show: #render show_results(data,streamlines, fa, fa_affine)
def track(params_file, directions="det", max_angle=30., sphere=None, seed_mask=None, seeds=1, stop_mask=None, stop_threshold=0, step_size=1.0, min_length=10, max_length=250): """ 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. seed : 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. 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 Returns ------- list of streamlines () """ if isinstance(params_file, str): params_img = nib.load(params_file) else: params_img = params_file model_params = params_img.get_data() affine = params_img.affine if isinstance(seeds, int): if seed_mask is None: seed_mask = np.ones(params_img.shape[:3]) seeds = dtu.seeds_from_mask(seed_mask, density=seeds, affine=affine) if sphere is None: sphere = dpd.default_sphere if directions == "det": dg = DeterministicMaximumDirectionGetter elif directions == "prob": dg = ProbabilisticDirectionGetter # These are models that have ODFs (there might be others in the future...) if model_params.shape[-1] == 12 or model_params.shape[-1] == 27: model = "ODF" # Could this be an SHM model? If the max order is a whole even number, it # might be: elif shm.calculate_max_order(model_params.shape[-1]) % 2 == 0: model = "SHM" if model == "SHM": dg = dg.from_shcoeff(model_params, max_angle=max_angle, sphere=sphere) elif model == "ODF": 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) if stop_mask is None: stop_mask = np.ones(params_img.shape[:3]) threshold_classifier = ThresholdTissueClassifier(stop_mask, stop_threshold) return _local_tracking(seeds, dg, threshold_classifier, affine, step_size=step_size, min_length=min_length, max_length=max_length)
def tracking_eudx4csd(dir_src, dir_out, verbose=False,gwmi_seeds=False): # Load data fbval = pjoin(dir_src, 'bvals_' + par_b_tag) fbvec = pjoin(dir_src, 'bvecs_' + par_b_tag) fdwi = pjoin(dir_src, 'data_' + par_b_tag + '_' + par_dim_tag + '.nii.gz') #fmask = pjoin(dir_src, 'nodif_brain_mask_' + par_dim_tag + '.nii.gz') fmask = pjoin(dir_src, 'wm_mask_' + par_b_tag + '_' + par_dim_tag + '.nii.gz') bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs, b0_threshold=par_b0_threshold) data, affine = load_nifti(fdwi, verbose) mask, _ = load_nifti(fmask, verbose) sphere = get_sphere('symmetric724') response, ratio = auto_response(gtab, data, roi_radius=par_ar_radius, fa_thr=par_ar_fa_th) # print('Response function', response) if gwmi_seeds: gwmi_mask_file = dir_src + '/wm_mask_b1k_2mm_add_gwmi.nii.gz' # dir_src + '/gwmi_' + par_dim_tag + '.nii.gz' gwmi_mask_img = nib.load(gwmi_mask_file) gwmi_mask_aff = gwmi_mask_img.get_affine() gwmi_mask_dat = gwmi_mask_img.get_data() seeds = seeds_from_mask(gwmi_mask_dat>0,density=30,affine=gwmi_mask_aff) gwmi_tag = '_gwmi_seeds_den30' else: seeds = par_eudx_seeds gwmi_tag = '' # Model fitting csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_peaks = peaks_from_model(csd_model, data, sphere, relative_peak_threshold=.5, min_separation_angle=25, parallel=False) # Computation of streamlines streamlines = EuDX(csd_peaks.peak_values, csd_peaks.peak_indices, seeds=seeds, odf_vertices= sphere.vertices, a_low=par_eudx_threshold) # Saving tractography voxel_size = (par_dim_vox,) * 3 dims = mask.shape[:3] hdr = nib.trackvis.empty_header() hdr['voxel_size'] = voxel_size hdr['voxel_order'] = 'LAS' hdr['dim'] = dims hdr['vox_to_ras'] = affine strm = ((sl, None, None) for sl in streamlines) trk_name = 'tractogram_' + par_b_tag + '_' + par_dim_tag + '_' + par_csd_tag + '_' + par_eudx_tag + gwmi_tag + '.trk' trk_out = os.path.join(dir_out, trk_name) nib.trackvis.write(trk_out, strm, hdr, points_space='voxel') dpy_out = trk_out.replace('.trk', '.dpy') dpy = Dpy(dpy_out, 'w') dpy.write_tracks(streamlines) dpy.close()
def deterministic(diffusion_file, bvecs_file, bvals_file, outdir, mask_file=None, order=4, nb_seeds_per_voxel=1, step=0.5, fmt="%.4f"): """ Compute a deterministic tractography using an ODF model. Parameters ---------- diffusion_file: str (mandatory) a file containing the preprocessed diffusion data. bvecs_file: str (mandatory) a file containing the diffusion gradient directions. bvals_file: str (mandatory) a file containing the diffusion b-values. outdir: str (mandatory) the output directory. mask_file: str (optional, default None) an image used to mask the diffusion data during the tractography. If not set, all the image voxels are considered. order: int (optional, default 4) the order of the ODF model. nb_seeds_per_voxel: int (optional, default 1) the number of seeds per voxel used during the propagation. step: float (optional, default 0.5) the integration step in voxel fraction used during the propagation. fmt: str (optional, default '%.4f') the saved track elements format. Returns ------- track_file: str a determinist model of the white matter organization. """ # Read diffusion sequence bvals, bvecs = read_bvals_bvecs(bvals_file, bvecs_file) gtab = gradient_table(bvals, bvecs) diffusion_array = nibabel.load(diffusion_file).get_data() if mask_file is not None: mask_array = nibabel.load(mask_file).get_data() else: mask_array = numpy.ones(diffusion_array.shape[:3], dtype=numpy.uint8) # Estimate ODF model csamodel = shm.CsaOdfModel(gtab, order) csapeaks = peaks.peaks_from_model( model=csamodel, data=diffusion_array, sphere=peaks.default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=mask_array) # Compute deterministic tractography in voxel space so affine is equal # to identity seeds = utils.seeds_from_mask(mask_array, density=nb_seeds_per_voxel) streamline_generator = EuDX( csapeaks.peak_values, csapeaks.peak_indices, odf_vertices=peaks.default_sphere.vertices, a_low=.05, step_sz=step, seeds=seeds) affine = streamline_generator.affine streamlines = list(streamline_generator) # Save the tracks track_file = os.path.join(outdir, "fibers.txt") savetxt(track_file, streamlines, fmt=fmt) return track_file
def track(params_file, directions="det", max_angle=30., sphere=None, seed_mask=None, seeds=2, stop_mask=None, stop_threshold=0.2, step_size=0.5, n_jobs=-1, backend="multiprocessing", engine="dask"): """ Deterministic tracking using CSD 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. seed : 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. 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.2. step_size : float, optional. Returns ------- LocalTracking object. """ if isinstance(params_file, str): params_img = nib.load(params_file) else: params_img = params_file model_params = params_img.get_data() affine = params_img.get_affine() if isinstance(seeds, int): if seed_mask is None: seed_mask = np.ones(params_img.shape[:3]) seeds = dtu.seeds_from_mask(seed_mask, density=seeds, affine=affine) if sphere is None: sphere = dpd.default_sphere if directions == "det": dg = DeterministicMaximumDirectionGetter elif directions == "prob": dg = ProbabilisticDirectionGetter # These are models that have ODFs (there might be others in the future...) if model_params.shape[-1] == 12 or model_params.shape[-1] == 27: model = "ODF" # Could this be an SHM model? If the max order is a whole even number, it # might be: elif shm.calculate_max_order(model_params.shape[-1]) % 2 == 0: model = "SHM" if model == "SHM": dg = dg.from_shcoeff(model_params, max_angle=max_angle, sphere=sphere) elif model == "ODF": 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) if stop_mask is None: stop_mask = np.ones(params_img.shape[:3]) threshold_classifier = ThresholdTissueClassifier(stop_mask, stop_threshold) if n_jobs == 1: engine = "serial" tracker = ParallelLocalTracking(dg, threshold_classifier, seeds, affine, step_size=step_size, return_all=True, n_jobs=n_jobs, backend=backend, engine=engine) return list(tracker.generate_streamlines())
csamodel = shm.CsaOdfModel(gtab, 6) csapeaks = peaks.peaks_from_model(model=csamodel, data=data, sphere=peaks.default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=white_matter) """ Now we can use EuDX to track all of the white matter. To keep things reasonably fast we use 1 seed per voxel. We'll set ``a_low`` (the parameter which determines the threshold of FA/QA under which tracking stops) to be very low because we've already applied a white matter mask. """ seeds = utils.seeds_from_mask(white_matter, density=2) streamline_generator = EuDX(csapeaks.peak_values, csapeaks.peak_indices, odf_vertices=peaks.default_sphere.vertices, a_low=.05, step_sz=.5, seeds=seeds) affine = streamline_generator.affine streamlines = list(streamline_generator) """ The first of the tracking utilities we'll cover here is ``target``. This function takes a set of streamlines and a region of interest (ROI) and returns only those streamlines that pass though the ROI. The ROI should be an array such that the voxels that belong to the ROI are ``True`` and all other voxels are ``False`` (this type of binary array is sometimes called a mask). This function can also exclude all the streamlines that pass though an ROI by setting the ``include`` flag to ``False``. In this example we'll target the streamlines of the corpus callosum. Our ``labels`` array has a sagittal slice
sphere=default_sphere) """ The optic radiation is reconstructed by tracking fibers from the calcarine sulcus (visual cortex V1) to the lateral geniculate nucleus (LGN). We seed from the calcarine sulcus by selecting a region-of-interest (ROI) cube of dimensions 3x3x3 voxels. """ # Set a seed region region for tractography. from dipy.tracking import utils mask = np.zeros(data.shape[:-1], 'bool') rad = 3 mask[26-rad:26+rad, 29-rad:29+rad, 31-rad:31+rad] = True seeds = utils.seeds_from_mask(mask, density=[4, 4, 4], affine=affine) """ Local Tracking is used for probabilistic tractography which takes the direction getter along with the classifier and seeds as input. """ # Perform tracking using Local Tracking from dipy.tracking.local import LocalTracking streamlines = LocalTracking(prob_dg, classifier, seeds, affine, step_size=.5) # Compute streamlines and store as a list. streamlines = list(streamlines) """
def deterministic(diffusion_file, bvecs_file, bvals_file, trackfile, mask_file=None, order=4, nb_seeds_per_voxel=1, step=0.5): """ Compute a deterministic tractography using an ODF model. Parameters ---------- diffusion_file: str (mandatory) a file containing the preprocessed diffusion data. bvecs_file: str (mandatory) a file containing the diffusion gradient directions. bvals_file: str (mandatory) a file containing the diffusion b-values. trackfile: str (mandatory) a file path where the fibers will be saved in trackvis format. mask_file: str (optional, default None) an image used to mask the diffusion data during the tractography. If not set, all the image voxels are considered. order: int (optional, default 4) the order of the ODF model. nb_seeds_per_voxel: int (optional, default 1) the number of seeds per voxel used during the propagation. step: float (optional, default 0.5) the integration step in voxel fraction used during the propagation. Returns ------- streamlines: tuple of 3-uplet the computed fiber tracks in trackvis format (points: ndarray shape (N,3) where N is the number of points, scalars: None or ndarray shape (N, M) where M is the number of scalars per point, properties: None or ndarray shape (P,) where P is the number of properties). hdr: structured array structured array with trackvis header fields (voxel size, voxel order, dim). """ # Read diffusion sequence bvals, bvecs = read_bvals_bvecs(bvals_file, bvecs_file) gtab = gradient_table(bvals, bvecs) diffusion_image = nibabel.load(diffusion_file) diffusion_array = diffusion_image.get_data() if mask_file is not None: mask_array = nibabel.load(mask_file).get_data() else: mask_array = numpy.ones(diffusion_array.shape[:3], dtype=numpy.uint8) # Estimate ODF model csamodel = shm.CsaOdfModel(gtab, order) csapeaks = peaks.peaks_from_model( model=csamodel, data=diffusion_array, sphere=peaks.default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=mask_array) # Compute deterministic tractography in voxel space so affine is equal # to identity seeds = utils.seeds_from_mask(mask_array, density=nb_seeds_per_voxel) streamline_generator = EuDX( csapeaks.peak_values, csapeaks.peak_indices, odf_vertices=peaks.default_sphere.vertices, a_low=.05, step_sz=step, seeds=seeds) affine = streamline_generator.affine # Save the tracks in trackvis format hdr = nibabel.trackvis.empty_header() hdr["voxel_size"] = diffusion_image.get_header().get_zooms()[:3] hdr["voxel_order"] = "LAS" hdr["dim"] = diffusion_array.shape[:3] streamlines = [track for track in streamline_generator] random.shuffle(streamlines) streamlines = ((track, None, None) for track in streamlines) nibabel.trackvis.write(trackfile, streamlines, hdr, points_space="voxel") return streamlines, hdr
from dipy.tracking.local import CmcTissueClassifier from dipy.tracking.streamline import Streamlines voxel_size = np.average(img_pve_wm.get_header()['pixdim'][1:4]) step_size = 0.2 cmc_classifier = CmcTissueClassifier.from_pve(img_pve_wm.get_data(), img_pve_gm.get_data(), img_pve_csf.get_data(), step_size=step_size, average_voxel_size=voxel_size) # seeds are place in voxel of the corpus callosum containing only white matter 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) # Particle Filtering Tractography pft_streamline_generator = ParticleFilteringTracking(dg, cmc_classifier, seeds, affine, max_cross=1, step_size=step_size, maxlen=1000, pft_back_tracking_dist=2, pft_front_tracking_dist=1, particle_count=15, return_all=False) #streamlines = list(pft_streamline_generator)
# Track all of white matter using EuDX #============================================================================= if not os.path.exists(Msym_file) and not os.path.exists(Mdir_file): print '\tCalculating peaks' csamodel = shm.CsaOdfModel(gtab, 6) csapeaks = peaks.peaks_from_model(model=csamodel, data=dwi_data, sphere=peaks.default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=wm_data_bin) print '\tTracking' seeds = utils.seeds_from_mask(parcellation_wm_data, density=2) condition_seeds = condition_seeds(seeds, np.eye(4), csapeaks.peak_values.shape[:3]) streamline_generator = EuDX(csapeaks.peak_values, csapeaks.peak_indices, odf_vertices=peaks.default_sphere.vertices, a_low=.05, step_sz=.5, seeds=condition_seeds) affine = streamline_generator.affine streamlines = list(streamline_generator) else: print '\tTracking already complete' #============================================================================= # Create two connectivity matrices - symmetric and directional #============================================================================= if not os.path.exists(Msym_file) and not os.path.exists(Mdir_file):
def test_particle_filtering_tractography(): """This tests that the ParticleFilteringTracking produces more streamlines connecting the gray matter than LocalTracking. """ sphere = get_sphere('repulsion100') step_size = 0.2 # Simple tissue masks simple_wm = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0]]) simple_wm = np.dstack([np.zeros(simple_wm.shape), simple_wm, simple_wm, simple_wm, np.zeros(simple_wm.shape)]) simple_gm = np.array([[1, 1, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0]]) simple_gm = np.dstack([np.zeros(simple_gm.shape), simple_gm, simple_gm, simple_gm, np.zeros(simple_gm.shape)]) simple_csf = np.ones(simple_wm.shape) - simple_wm - simple_gm tc = ActTissueClassifier.from_pve(simple_wm, simple_gm, simple_csf) seeds = seeds_from_mask(simple_wm, density=2) # Random pmf in every voxel shape_img = list(simple_wm.shape) shape_img.extend([sphere.vertices.shape[0]]) np.random.seed(0) # Random number generator initialization pmf = np.random.random(shape_img) # Test that PFT recover equal or more streamlines than localTracking dg = ProbabilisticDirectionGetter.from_pmf(pmf, 60, sphere) local_streamlines_generator = LocalTracking(dg, tc, seeds, np.eye(4), step_size, max_cross=1, return_all=False) local_streamlines = Streamlines(local_streamlines_generator) pft_streamlines_generator = ParticleFilteringTracking( dg, tc, seeds, np.eye(4), step_size, max_cross=1, return_all=False, pft_back_tracking_dist=1, pft_front_tracking_dist=0.5) pft_streamlines = Streamlines(pft_streamlines_generator) npt.assert_(np.array([len(pft_streamlines) > 0])) npt.assert_(np.array([len(pft_streamlines) >= len(local_streamlines)])) # Test that all points are equally spaced for l in [1, 2, 5, 10, 100]: pft_streamlines = ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, max_cross=1, return_all=True, maxlen=l) for s in pft_streamlines: for i in range(len(s) - 1): npt.assert_almost_equal(np.linalg.norm(s[i] - s[i + 1]), step_size) # Test that all points are within the image volume seeds = seeds_from_mask(np.ones(simple_wm.shape), density=1) pft_streamlines_generator = ParticleFilteringTracking( dg, tc, seeds, np.eye(4), step_size, max_cross=1, return_all=True) pft_streamlines = Streamlines(pft_streamlines_generator) for s in pft_streamlines: npt.assert_(np.all((s + 0.5).astype(int) >= 0)) npt.assert_(np.all((s + 0.5).astype(int) < simple_wm.shape)) # Test that the number of streamline return with return_all=True equal the # number of seeds places npt.assert_(np.array([len(pft_streamlines) == len(seeds)])) # Test non WM seed position seeds = [[0, 5, 4], [0, 0, 1], [50, 50, 50]] pft_streamlines_generator = ParticleFilteringTracking( dg, tc, seeds, np.eye(4), step_size, max_cross=1, return_all=True) pft_streamlines = Streamlines(pft_streamlines_generator) npt.assert_equal(len(pft_streamlines[0]), 3) # INVALIDPOINT npt.assert_equal(len(pft_streamlines[1]), 3) # ENDPOINT npt.assert_equal(len(pft_streamlines[2]), 1) # OUTSIDEIMAGE # Test with wrong tissueclassifier type tc_bin = BinaryTissueClassifier(simple_wm) npt.assert_raises(ValueError, lambda: ParticleFilteringTracking(dg, tc_bin, seeds, np.eye(4), step_size)) # Test with invalid back/front tracking distances npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, pft_back_tracking_dist=0, pft_front_tracking_dist=0)) npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, pft_back_tracking_dist=-1)) npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, pft_back_tracking_dist=0, pft_front_tracking_dist=-2)) # Test with invalid affine shape npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(3), step_size)) # Test with invalid maxlen npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, maxlen=0)) npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, maxlen=-1)) # Test with invalid particle count npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, particle_count=0)) npt.assert_raises( ValueError, lambda: ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, particle_count=-1)) # Test reproducibility tracking_1 = Streamlines(ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, random_seed=0)).data tracking_2 = Streamlines(ParticleFilteringTracking(dg, tc, seeds, np.eye(4), step_size, random_seed=0)).data npt.assert_equal(tracking_1, tracking_2)
csa_peaks = peaks_from_model(csa_model, data, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=white_matter) classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) """ We will use a slice of the anatomically-based corpus callosum ROI as our seed mask to demonstrate the method. """ # Make a corpus callosum seed mask for tracking seed_mask = labels == 2 seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine) # Make a streamline bundle model of the corpus callosum ROI connectivity streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, step_size=2) streamlines = Streamlines(streamlines) """ We do not want our results inflated by short streamlines, so we remove streamlines shorter than 40mm prior to calculating the CCI. """ lengths = list(length(streamlines)) long_streamlines = Streamlines() for i, sl in enumerate(streamlines): if lengths[i] > 40:
def run(self, pam_files, wm_files, gm_files, csf_files, seeding_files, step_size=0.2, seed_density=1, pmf_threshold=0.1, max_angle=20., pft_back=2, pft_front=1, pft_count=15, out_dir='', out_tractogram='tractogram.trk'): """Workflow for Particle Filtering Tracking. This workflow use a saved peaks and metrics (PAM) file as input. Parameters ---------- pam_files : string Path to the peaks and metrics files. This path may contain wildcards to use multiple masks at once. wm_files : string Path to white matter partial volume estimate for tracking (CMC). gm_files : string Path to grey matter partial volume estimate for tracking (CMC). csf_files : string Path to cerebrospinal fluid partial volume estimate for tracking (CMC). seeding_files : string A binary image showing where we need to seed for tracking. step_size : float, optional Step size used for tracking (default 0.2mm). seed_density : int, optional Number of seeds per dimension inside voxel (default 1). For example, seed_density of 2 means 8 regularly distributed points in the voxel. And seed density of 1 means 1 point at the center of the voxel. pmf_threshold : float, optional Threshold for ODF functions (default 0.1). max_angle : float, optional Maximum angle between streamline segments (range [0, 90], default 20). pft_back : float, optional Distance in mm to back track before starting the particle filtering tractography (defaul 2mm). The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. pft_front : float, optional Distance in mm to run the particle filtering tractography after the the back track distance (default 1mm). The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. pft_count : int, optional Number of particles to use in the particle filter (default 15). out_dir : string, optional Output directory (default input file directory) out_tractogram : string, optional Name of the tractogram file to be saved (default 'tractogram.trk') References ---------- Girard, G., Whittingstall, K., Deriche, R., & Descoteaux, M. Towards quantitative connectivity analysis: reducing tractography biases. NeuroImage, 98, 266-278, 2014. """ io_it = self.get_io_iterator() for pams_path, wm_path, gm_path, csf_path, seeding_path, out_tract \ in io_it: logging.info('Particle Filtering tracking on {0}' .format(pams_path)) pam = load_peaks(pams_path, verbose=False) wm, affine, voxel_size = load_nifti(wm_path, return_voxsize=True) gm, _ = load_nifti(gm_path) csf, _ = load_nifti(csf_path) avs = sum(voxel_size) / len(voxel_size) # average_voxel_size classifier = CmcTissueClassifier.from_pve(wm, gm, csf, step_size=step_size, average_voxel_size=avs) 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') dg = ProbabilisticDirectionGetter direction_getter = dg.from_shcoeff(pam.shm_coeff, max_angle=max_angle, sphere=pam.sphere, pmf_threshold=pmf_threshold) streamlines_generator = ParticleFilteringTracking( direction_getter, classifier, seeds, affine, step_size=step_size, pft_back_tracking_dist=pft_back, pft_front_tracking_dist=pft_front, pft_max_trial=20, particle_count=pft_count) logging.info('ParticleFilteringTracking initiated') tractogram = Tractogram(streamlines_generator, affine_to_rasmm=np.eye(4)) save(tractogram, out_tract) logging.info('Saved {0}'.format(out_tract))
classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) """ 3. Before we can begin tracking is to specify where to "seed" (begin) the fiber tracking. Generally, the seeds chosen will depend on the pathways one is interested in modeling. In this example, we'll use a $2 \times 2 \times 2$ grid of seeds per voxel, in a sagittal slice of the corpus callosum. Tracking from this region will give us a model of the corpus callosum tract. This slice has label value ``2`` in the labels image. """ from dipy.tracking import utils import numpy as np seed_mask = labels == 2 seeds = utils.seeds_from_mask(seed_mask, density=[2, 2, 2], affine=np.eye(4)) """ Finally, we can bring it all together using ``LocalTracking``. We will then display the resulting streamlines using the ``dipy.viz`` package. """ from dipy.tracking.local import LocalTracking from dipy.viz import window, actor, colormap as cmap, have_fury from dipy.tracking.streamline import Streamlines # Enables/disables interactive visualization interactive = False # Initialization of LocalTracking. The computation happens in the next step. streamlines_generator = LocalTracking(csa_peaks, classifier, seeds,
def test_contour_from_roi(): # Render volume renderer = window.renderer() data = np.zeros((50, 50, 50)) data[20:30, 25, 25] = 1. data[25, 20:30, 25] = 1. affine = np.eye(4) surface = actor.contour_from_roi(data, affine, color=np.array([1, 0, 1]), opacity=.5) renderer.add(surface) renderer.reset_camera() renderer.reset_clipping_range() # window.show(renderer) # Test binarization renderer2 = window.renderer() data2 = np.zeros((50, 50, 50)) data2[20:30, 25, 25] = 1. data2[35:40, 25, 25] = 1. affine = np.eye(4) surface2 = actor.contour_from_roi(data2, affine, color=np.array([0, 1, 1]), opacity=.5) renderer2.add(surface2) renderer2.reset_camera() renderer2.reset_clipping_range() # window.show(renderer2) arr = window.snapshot(renderer, 'test_surface.png', offscreen=True) arr2 = window.snapshot(renderer2, 'test_surface2.png', offscreen=True) report = window.analyze_snapshot(arr, find_objects=True) report2 = window.analyze_snapshot(arr2, find_objects=True) npt.assert_equal(report.objects, 1) npt.assert_equal(report2.objects, 2) # test on real streamlines using tracking example from dipy.data import read_stanford_labels from dipy.reconst.shm import CsaOdfModel from dipy.data import default_sphere from dipy.direction import peaks_from_model from dipy.tracking.local import ThresholdTissueClassifier from dipy.tracking import utils from dipy.tracking.local import LocalTracking from dipy.viz.colormap import line_colors hardi_img, gtab, labels_img = read_stanford_labels() data = hardi_img.get_data() labels = labels_img.get_data() affine = hardi_img.get_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) classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) seed_mask = labels == 2 seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine) # Initialization of LocalTracking. # The computation happens in the next step. streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, step_size=2) # Compute streamlines and store as a list. streamlines = list(streamlines) # Prepare the display objects. streamlines_actor = actor.line(streamlines, line_colors(streamlines)) seedroi_actor = actor.contour_from_roi(seed_mask, affine, [0, 1, 1], 0.5) # Create the 3d display. r = window.ren() r2 = window.ren() r.add(streamlines_actor) arr3 = window.snapshot(r, 'test_surface3.png', offscreen=True) report3 = window.analyze_snapshot(arr3, find_objects=True) r2.add(streamlines_actor) r2.add(seedroi_actor) arr4 = window.snapshot(r2, 'test_surface4.png', offscreen=True) report4 = window.analyze_snapshot(arr4, find_objects=True) # assert that the seed ROI rendering is not far # away from the streamlines (affine error) npt.assert_equal(report3.objects, report4.objects)
classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) """ 3. Before we can begin tracking is to specify where to "seed" (begin) the fiber tracking. Generally, the seeds chosen will depend on the pathways one is interested in modeling. In this example, we'll use a $2 \times 2 \times 2$ grid of seeds per voxel, in a sagittal slice of the corpus callosum. Tracking from this region will give us a model of the corpus callosum tract. This slice has label value ``2`` in the labels image. """ from dipy.tracking import utils seed_mask = labels == 2 seeds = utils.seeds_from_mask(seed_mask, density=[2, 2, 2], affine=affine) """ Finally, we can bring it all together using ``LocalTracking``. We will then display the resulting streamlines using the ``dipy.viz`` package. """ from dipy.tracking.local import LocalTracking from dipy.viz import window, actor from dipy.viz.colormap import line_colors from dipy.tracking.streamline import Streamlines # Enables/disables interactive visualization interactive = False # Initialization of LocalTracking. The computation happens in the next step.
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) tc = ThresholdTissueClassifier(mask, .5) dg = ProbabilisticDirectionGetter.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.], [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) 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, tc, 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, tc, 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, tc, seeds, np.eye(4), 0.2, max_cross=1, return_all=True) streamlines = Streamlines(streamlines) npt.assert_(len(streamlines[0]) == 3) # 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), density=2) streamline_generator = LocalTracking(dg, tc, 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, tc, seeds, np.eye(4), 0.5, random_seed=0)).data tracking_2 = Streamlines(LocalTracking(dg, tc, seeds, np.eye(4), 0.5, random_seed=0)).data npt.assert_equal(tracking_1, tracking_2)