def test_calculate_max_order(): """Based on the table in: http://jdtournier.github.io/mrtrix-0.2/tractography/preprocess.html """ orders = [2, 4, 6, 8, 10, 12] n_coeffs_sym = [6, 15, 28, 45, 66, 91] # n = (R + 1)^2 for a full basis n_coeffs_full = [9, 25, 49, 81, 121, 169] for o, n_sym, n_full in zip(orders, n_coeffs_sym, n_coeffs_full): assert_equal(calculate_max_order(n_sym), o) assert_equal(calculate_max_order(n_full, True), o) assert_raises(ValueError, calculate_max_order, 29) assert_raises(ValueError, calculate_max_order, 29, True)
def test_anisotropic_power(): for n_coeffs in [6, 15, 28, 45, 66, 91]: for norm_factor in [0.0005, 0.00001]: # Create some really simple cases: coeffs = np.ones((3, n_coeffs)) max_order = calculate_max_order(coeffs.shape[-1]) # For the case where all coeffs == 1, the ap is simply log of the # number of even orders up to the maximal order: analytic = (np.log(len(range(2, max_order + 2, 2))) - np.log(norm_factor)) answers = [analytic] * 3 apvals = anisotropic_power(coeffs, norm_factor=norm_factor) assert_array_almost_equal(apvals, answers) # Test that this works for single voxel arrays as well: assert_array_almost_equal( anisotropic_power(coeffs[1], norm_factor=norm_factor), answers[1]) # Test that even when we look at an all-zeros voxel, this # avoids a log-of-zero warning: with warnings.catch_warnings(record=True) as w: assert_equal(anisotropic_power(np.zeros(6)), 0) assert len(w) == 0
def test_calculate_max_order(): """Based on the table in: http://jdtournier.github.io/mrtrix-0.2/tractography/preprocess.html """ orders = [2, 4, 6, 8, 10, 12] n_coeffs = [6, 15, 28, 45, 66, 91] for o, n in zip(orders, n_coeffs): assert_equal(calculate_max_order(n), o)
def test_fit_csd(): fdata, fbval, fbvec = dpd.get_data('small_64D') with nbtmp.InTemporaryDirectory() as tmpdir: # Convert from npy to txt: bvals = np.load(fbval) bvecs = np.load(fbvec) np.savetxt(op.join(tmpdir, 'bvals.txt'), bvals) np.savetxt(op.join(tmpdir, 'bvecs.txt'), bvecs) for sh_order in [4, 6]: fname = csd.fit_csd(fdata, op.join(tmpdir, 'bvals.txt'), op.join(tmpdir, 'bvecs.txt'), out_dir=tmpdir, sh_order=sh_order) npt.assert_(op.exists(fname)) sh_coeffs_img = nib.load(fname) npt.assert_equal(sh_order, calculate_max_order(sh_coeffs_img.shape[-1]))
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=30, 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. 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 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(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 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 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, n_chunks=100, backend="threading", engine="dask"): """ 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.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 engine == "serial": return _local_tracking(seeds, dg, threshold_classifier, affine, step_size=step_size) else: if n_chunks < seeds.shape[0]: seeds_list = [] i2 = 0 seeds_per_chunk = seeds.shape[0] // n_chunks for chunk in range(n_chunks - 1): i1 = i2 i2 = seeds_per_chunk * (chunk + 1) seeds_list.append(seeds[i1:i2]) else: seeds_list = seeds ll = parfor(_local_tracking, seeds_list, n_jobs=n_jobs, engine=engine, backend=backend, func_args=[dg, threshold_classifier, affine], func_kwargs=dict(step_size=step_size)) return (list(chain(*ll)))
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())
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)