def test_multi_tensor(): sphere = get_sphere('symmetric724') vertices = sphere.vertices mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) e0 = np.array([np.sqrt(2) / 2., np.sqrt(2) / 2., 0]) e1 = np.array([0, np.sqrt(2) / 2., np.sqrt(2) / 2.]) mevecs = [all_tensor_evecs(e0), all_tensor_evecs(e1)] # odf = multi_tensor_odf(vertices, [0.5, 0.5], mevals, mevecs) # assert_(odf.shape == (len(vertices),)) # assert_(np.all(odf <= 1) & np.all(odf >= 0)) fimg, fbvals, fbvecs = get_data('small_101D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) s1 = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) s2 = single_tensor(gtab, 100, mevals[1], mevecs[1], snr=None) Ssingle = 0.5*s1 + 0.5*s2 S, sticks = MultiTensor(gtab, mevals, S0=100, angles=[(90, 45), (45, 90)], fractions=[50, 50], snr=None) assert_array_almost_equal(S, Ssingle)
def generate( self, out_path, aux, idx_in, idx_out ) : scheme_high = amico.lut.create_high_resolution_scheme( self.scheme, b_scale=1 ) gtab = gradient_table( scheme_high.b, scheme_high.raw[:,0:3] ) nATOMS = 1 + len(self.ICVFs) + len(self.d_ISOs) progress = ProgressBar( n=nATOMS, prefix=" ", erase=True ) # Stick signal = single_tensor( gtab, evals=[0, 0, self.d_par] ) lm = amico.lut.rotate_kernel( signal, aux, idx_in, idx_out, False ) np.save( pjoin( out_path, 'A_001.npy' ), lm ) progress.update() # Zeppelin(s) for d in [ self.d_par*(1.0-ICVF) for ICVF in self.ICVFs] : signal = single_tensor( gtab, evals=[d, d, self.d_par] ) lm = amico.lut.rotate_kernel( signal, aux, idx_in, idx_out, False ) np.save( pjoin( out_path, 'A_%03d.npy'%progress.i ), lm ) progress.update() # Ball(s) for d in self.d_ISOs : signal = single_tensor( gtab, evals=[d, d, d] ) lm = amico.lut.rotate_kernel( signal, aux, idx_in, idx_out, True ) np.save( pjoin( out_path, 'A_%03d.npy'%progress.i ), lm ) progress.update()
def two_fiber_signal(bvals, bvecs, angle, w=[0.5, 0.5], SNR=0): R0 = rotation_around_axis([0, 1, 0], 0) R1 = rotation_around_axis([0, 1, 0], np.deg2rad(angle)) E = w[0] * single_tensor(gradients=bvecs, bvals=bvals, S0=1, evecs=R0, snr=SNR) E += w[1] * single_tensor(gradients=bvecs, bvals=bvals, S0=1, evecs=R1, snr=SNR) return E
def make_fake_signal(): hemisphere = hemi_icosahedron.subdivide(2) bvecs = np.concatenate(([[0, 0, 0]], hemisphere.vertices)) bvals = np.zeros(len(bvecs)) + 2000 bvals[0] = 0 gtab = gradient_table(bvals, bvecs) evals = np.array([[2.1, .2, .2], [.2, 2.1, .2]]) * 10 ** -3 evecs0 = np.eye(3) evecs1 = evecs0 a = evecs0[0] b = evecs1[1] S1 = single_tensor(gtab, .55, evals[0], evecs0) S2 = single_tensor(gtab, .45, evals[1], evecs1) return S1 + S2, gtab, np.vstack([a, b])
def test_bdg_initial_direction(): """This test the number of inital direction." """ hsph_updated = HemiSphere.from_sphere(unit_icosahedron).subdivide(2) vertices = hsph_updated.vertices bvecs = vertices bvals = np.ones(len(vertices)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) # test that we get one direction when we have a single tensor voxel = single_tensor(gtab).reshape([1, 1, 1, -1]) dti_model = dti.TensorModel(gtab) boot_dg = BootDirectionGetter.from_data(voxel, dti_model, 30, sh_order=6) initial_direction = boot_dg.initial_direction(np.zeros(3)) npt.assert_equal(len(initial_direction), 1) npt.assert_allclose(initial_direction[0], [1, 0, 0], atol=0.1) # test that we get multiple directions when we have a multi-tensor mevals = np.array([[1.5, 0.4, 0.4], [1.5, 0.4, 0.4]]) * 1e-3 fracs = [60, 40] voxel, primary_evecs = multi_tensor(gtab, mevals, fractions=fracs, snr=None) voxel = voxel.reshape([1, 1, 1, -1]) response = (np.array([0.0015, 0.0004, 0.0004]), 1) csd_model = ConstrainedSphericalDeconvModel(gtab, response=response, sh_order=4) boot_dg = BootDirectionGetter.from_data(voxel, csd_model, 30) initial_direction = boot_dg.initial_direction(np.zeros(3)) npt.assert_equal(len(initial_direction), 2) npt.assert_allclose(initial_direction, primary_evecs, atol=0.1)
def test_mapmri_metrics_isotropic(radial_order=6): gtab = get_gtab_taiwan_dsi() l1, l2, l3 = [0.0003, 0.0003, 0.0003] # isotropic diffusivities S = single_tensor(gtab, evals=np.r_[l1, l2, l3]) # test MAPMRI q-space indices mapm = MapmriModel(gtab, radial_order=radial_order, laplacian_regularization=False, anisotropic_scaling=False) mapfit = mapm.fit(S) tau = 1 / (4 * np.pi ** 2) # ground truth indices estimated from the DTI tensor rtpp_gt = 1. / (2 * np.sqrt(np.pi * l1 * tau)) rtap_gt = ( 1. / (2 * np.sqrt(np.pi * l2 * tau)) * 1. / (2 * np.sqrt(np.pi * l3 * tau)) ) rtop_gt = rtpp_gt * rtap_gt msd_gt = 2 * (l1 + l2 + l3) * tau qiv_gt = ( (64 * np.pi ** (7 / 2.) * (l1 * l2 * l3 * tau ** 3) ** (3 / 2.)) / ((l2 * l3 + l1 * (l2 + l3)) * tau ** 2) ) assert_almost_equal(mapfit.rtap(), rtap_gt, 5) assert_almost_equal(mapfit.rtpp(), rtpp_gt, 5) assert_almost_equal(mapfit.rtop(), rtop_gt, 4) assert_almost_equal(mapfit.msd(), msd_gt, 5) assert_almost_equal(mapfit.qiv(), qiv_gt, 5)
def test_predict(): """ Test model prediction API """ psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[1, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]])] S = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) assert_array_almost_equal(dmfit.predict(gtab, S0=100), S) assert_array_almost_equal(dm.predict(dmfit.model_params, S0=100), S) fdata, fbvals, fbvecs = get_data() data = nib.load(fdata).get_data() # Make the data cube a bit larger: data = np.tile(data.T, 2).T gtab = grad.gradient_table(fbvals, fbvecs) dtim = dti.TensorModel(gtab) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape)
def test_mapmri_laplacian_isotropic(radial_order=6): gtab = get_gtab_taiwan_dsi() l1, l2, l3 = [0.0003, 0.0003, 0.0003] # isotropic diffusivities S = single_tensor(gtab, evals=np.r_[l1, l2, l3]) mapm = MapmriModel(gtab, radial_order=radial_order, laplacian_regularization=False, anisotropic_scaling=False) mapfit = mapm.fit(S) tau = 1 / (4 * np.pi ** 2) # ground truth norm of laplacian of tensor norm_of_laplacian_gt = ( (3 * (l1 ** 2 + l2 ** 2 + l3 ** 2) + 2 * l2 * l3 + 2 * l1 * (l2 + l3)) * (np.pi ** (5 / 2.) * tau) / (np.sqrt(2 * l1 * l2 * l3 * tau)) ) # check if estimated laplacian corresponds with ground truth laplacian_matrix = mapmri.mapmri_isotropic_laplacian_reg_matrix( radial_order, mapfit.mu[0]) coef = mapfit._mapmri_coef norm_of_laplacian = np.dot(np.dot(coef, laplacian_matrix), coef) assert_almost_equal(norm_of_laplacian, norm_of_laplacian_gt)
def test_diffusivities(): psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]])] S = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) md = mean_diffusivity(dmfit.evals) Trace = trace(dmfit.evals) rd = radial_diffusivity(dmfit.evals) ad = axial_diffusivity(dmfit.evals) lin = linearity(dmfit.evals) plan = planarity(dmfit.evals) spher = sphericity(dmfit.evals) assert_almost_equal(md, (0.0015 + 0.0003 + 0.0001) / 3) assert_almost_equal(Trace, (0.0015 + 0.0003 + 0.0001)) assert_almost_equal(ad, 0.0015) assert_almost_equal(rd, (0.0003 + 0.0001) / 2) assert_almost_equal(lin, (0.0015 - 0.0003)/Trace) assert_almost_equal(plan, 2 * (0.0003 - 0.0001)/Trace) assert_almost_equal(spher, (3 * 0.0001)/Trace)
def test_csd_xval(): # First, let's see that it works with some data: data = nib.load(fdata).get_data()[1:3, 1:3, 1:3] # Make it *small* gtab = gt.gradient_table(fbval, fbvec) S0 = np.mean(data[..., gtab.b0s_mask]) response = ([0.0015, 0.0003, 0.0001], S0) csdm = csd.ConstrainedSphericalDeconvModel(gtab, response) kf_xval = xval.kfold_xval(csdm, data, 2, response, sh_order=2) # In simulation, it should work rather well (high COD): psphere = dpd.get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = gt.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array( [ [1, 0, 0], [0, 1, 0], [0, 0, 1] ] ), np.array( [ [0, 0, 1], [0, 1, 0], [1, 0, 0] ] ) ] S0 = 100 S = sims.single_tensor( gtab, S0, mevals[0], mevecs[0], snr=None ) sm = csd.ConstrainedSphericalDeconvModel(gtab, response) smfit = sm.fit(S) np.random.seed(12345) response = ([0.0015, 0.0003, 0.0001], S0) kf_xval = xval.kfold_xval(sm, S, 2, response, sh_order=2) # Because of the regularization, COD is not going to be perfect here: cod = xval.coeff_of_determination(S, kf_xval) # We'll just test for regressions: csd_cod = 97 # pre-computed by hand for this random seed # We're going to be really lenient here: npt.assert_array_almost_equal(np.round(cod), csd_cod)
def test_dti_xval(): """ Test k-fold cross-validation """ data = nib.load(fdata).get_data() gtab = gt.gradient_table(fbval, fbvec) dm = dti.TensorModel(gtab, "LS") # The data has 102 directions, so will not divide neatly into 10 bits npt.assert_raises(ValueError, xval.kfold_xval, dm, data, 10) # But we can do this with 2 folds: kf_xval = xval.kfold_xval(dm, data, 2) # In simulation with no noise, COD should be perfect: psphere = dpd.get_sphere("symmetric362") bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = gt.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]])] S = sims.single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, "LS") kf_xval = xval.kfold_xval(dm, S, 2) cod = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(cod, np.ones(kf_xval.shape[:-1]) * 100) # Test with 2D data for use of a mask S = np.array([[S, S], [S, S]]) mask = np.ones(S.shape[:-1], dtype=bool) mask[1, 1] = 0 kf_xval = xval.kfold_xval(dm, S, 2, mask=mask) cod2d = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(np.round(cod2d[0, 0]), cod)
def test_eig_from_lo_tri(): psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]])] S = np.array([[single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None), single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None)]]) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) lo_tri = lower_triangular(dmfit.quadratic_form) assert_array_almost_equal(dti.eig_from_lo_tri(lo_tri), dmfit.model_params)
def generate( self, out_path, aux, idx_in, idx_out ) : scheme_high = amico.lut.create_high_resolution_scheme( self.scheme, b_scale=1 ) gtab = gradient_table( scheme_high.b, scheme_high.raw[:,0:3] ) nATOMS = len(self.d_perps) + len(self.d_isos) progress = ProgressBar( n=nATOMS, prefix=" ", erase=True ) # Tensor compartment(s) for d in self.d_perps : signal = single_tensor( gtab, evals=[d, d, self.d_par] ) lm = amico.lut.rotate_kernel( signal, aux, idx_in, idx_out, False ) np.save( pjoin( out_path, 'A_%03d.npy'%progress.i ), lm ) progress.update() # Isotropic compartment(s) for d in self.d_isos : signal = single_tensor( gtab, evals=[d, d, d] ) lm = amico.lut.rotate_kernel( signal, aux, idx_in, idx_out, True ) np.save( pjoin( out_path, 'A_%03d.npy'%progress.i ), lm ) progress.update()
def test_snr(): np.random.seed(1978) s = single_tensor(gtab) # For reasonably large SNR, var(signal) ~= sigma**2, where sigma = 1/SNR for snr in [5, 10, 20]: sigma = 1.0 / snr for j in range(1000): s_noise = add_noise(s, snr, 1, noise_type='rician') assert_array_almost_equal(np.var(s_noise - s), sigma**2, decimal=2)
def generate(self, out_path, aux, idx_in, idx_out): scheme_high = amico.lut.create_high_resolution_scheme(self.scheme, b_scale=1) gtab = gradient_table(scheme_high.b, scheme_high.raw[:, 0:3]) nATOMS = len(self.d_perps) + len(self.d_isos) progress = ProgressBar(n=nATOMS, prefix=" ", erase=True) # Tensor compartment(s) for d in self.d_perps: signal = single_tensor(gtab, evals=[d, d, self.d_par]) lm = amico.lut.rotate_kernel(signal, aux, idx_in, idx_out, False) np.save(pjoin(out_path, 'A_%03d.npy' % progress.i), lm) progress.update() # Isotropic compartment(s) for d in self.d_isos: signal = single_tensor(gtab, evals=[d, d, d]) lm = amico.lut.rotate_kernel(signal, aux, idx_in, idx_out, True) np.save(pjoin(out_path, 'A_%03d.npy' % progress.i), lm) progress.update()
def test_single_tensor(): evals = np.array([1.4, .35, .35]) * 10**(-3) evecs = np.eye(3) S = single_tensor(gtab, 100, evals, evecs, snr=None) assert_array_almost_equal(S[gtab.b0s_mask], 100) assert_(np.mean(S[~gtab.b0s_mask]) < 100) from dipy.reconst.dti import TensorModel m = TensorModel(gtab) t = m.fit(S) assert_array_almost_equal(t.fa, 0.707, decimal=3)
def test_eig_from_lo_tri(): psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ] S = np.array([[ single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None), single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) ]]) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) lo_tri = lower_triangular(dmfit.quadratic_form) npt.assert_array_almost_equal(dti.eig_from_lo_tri(lo_tri), dmfit.model_params)
def setup_module(): """Module-level setup""" global gtab, gtab_2s, mevals, model_params_mv global DWI, FAref, GTF, MDref, FAdti, MDdti _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) # FW model requires multishell data bvals_2s = np.concatenate((bvals, bvals * 1.5), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = gradient_table(bvals_2s, bvecs_2s) # Simulation a typical DT and DW signal for no water contamination S0 = np.array(100) dt = np.array([0.0017, 0, 0.0003, 0, 0, 0.0003]) evals, evecs = decompose_tensor(from_lower_triangular(dt)) S_tissue = single_tensor(gtab_2s, S0=100, evals=evals, evecs=evecs, snr=None) dm = dti.TensorModel(gtab_2s, 'WLS') dtifit = dm.fit(S_tissue) FAdti = dtifit.fa MDdti = dtifit.md dtiparams = dtifit.model_params # Simulation of 8 voxels tested DWI = np.zeros((2, 2, 2, len(gtab_2s.bvals))) FAref = np.zeros((2, 2, 2)) MDref = np.zeros((2, 2, 2)) # Diffusion of tissue and water compartments are constant for all voxel mevals = np.array([[0.0017, 0.0003, 0.0003], [0.003, 0.003, 0.003]]) # volume fractions GTF = np.array([[[0.06, 0.71], [0.33, 0.91]], [[0., 0.], [0., 0.]]]) # S0 multivoxel S0m = 100 * np.ones((2, 2, 2)) # model_params ground truth (to be fill) model_params_mv = np.zeros((2, 2, 2, 13)) for i in range(2): for j in range(2): gtf = GTF[0, i, j] S, p = multi_tensor(gtab_2s, mevals, S0=100, angles=[(90, 0), (90, 0)], fractions=[(1-gtf) * 100, gtf*100], snr=None) DWI[0, i, j] = S FAref[0, i, j] = FAdti MDref[0, i, j] = MDdti R = all_tensor_evecs(p[0]) R = R.reshape((9)) model_params_mv[0, i, j] = \ np.concatenate(([0.0017, 0.0003, 0.0003], R, [gtf]), axis=0)
def test_csd_xval(): # First, let's see that it works with some data: data = load_nifti_data(fdata)[1:3, 1:3, 1:3] # Make it *small* gtab = gt.gradient_table(fbval, fbvec) S0 = np.mean(data[..., gtab.b0s_mask]) response = ([0.0015, 0.0003, 0.0001], S0) # In simulation, it should work rather well (high COD): psphere = dpd.get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = gt.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ] S0 = 100 S = sims.single_tensor(gtab, S0, mevals[0], mevecs[0], snr=None) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) sm = csd.ConstrainedSphericalDeconvModel(gtab, response) np.random.seed(12345) response = ([0.0015, 0.0003, 0.0001], S0) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) kf_xval = xval.kfold_xval(sm, S, 2, response, sh_order=2) # Because of the regularization, COD is not going to be perfect here: cod = xval.coeff_of_determination(S, kf_xval) # We'll just test for regressions: csd_cod = 97 # pre-computed by hand for this random seed # We're going to be really lenient here: npt.assert_array_almost_equal(np.round(cod), csd_cod) # Test for sD data with more than one voxel for use of a mask: S = np.array([[S, S], [S, S]]) mask = np.ones(S.shape[:-1], dtype=bool) mask[1, 1] = 0 with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) kf_xval = xval.kfold_xval(sm, S, 2, response, sh_order=2, mask=mask) cod = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(np.round(cod[0]), csd_cod)
def get_test_data(): gtab = get_3shell_gtab() evals_list = [np.array([1.7E-3, 0.4E-3, 0.4E-3]), np.array([6.0E-4, 4.0E-4, 4.0E-4]), np.array([3.0E-3, 3.0E-3, 3.0E-3])] s0 = [0.8, 1, 4] signals = [single_tensor(gtab, x[0], x[1]) for x in zip(s0, evals_list)] tissues = [0, 0, 2, 0, 1, 0, 0, 1, 2] # wm=0, gm=1, csf=2 data = [add_noise(signals[tissue], 80, s0[0]) for tissue in tissues] data = np.asarray(data).reshape((3, 3, 1, len(signals[0]))) tissues = np.asarray(tissues).reshape((3, 3, 1)) masks = [np.where(tissues == x, 1, 0) for x in range(3)] responses = [np.concatenate((x[0], [x[1]])) for x in zip(evals_list, s0)] return gtab, data, masks, responses
def test_multi_tensor_btens(): """ Testing multi tensor simulations when a btensor is given """ mevals = np.array(([0.003, 0.0002, 0.0002], [0.0015, 0.0003, 0.0003])) e0 = np.array([np.sqrt(2) / 2., np.sqrt(2) / 2., 0]) e1 = np.array([0, np.sqrt(2) / 2., np.sqrt(2) / 2.]) mevecs = [all_tensor_evecs(e0), all_tensor_evecs(e1)] gtab_ste = gradient_table(gtab.bvals, gtab.bvecs, btens='STE') s1 = single_tensor(gtab_ste, 100, mevals[0], mevecs[0], snr=None) s2 = single_tensor(gtab_ste, 100, mevals[1], mevecs[1], snr=None) Ssingle = 0.5 * s1 + 0.5 * s2 S, _ = multi_tensor(gtab_ste, mevals, S0=100, angles=[(90, 45), (45, 90)], fractions=[50, 50], snr=None) assert_array_almost_equal(S, Ssingle)
def test_boot_pmf(): # This tests the local model used for the bootstrapping. hsph_updated = HemiSphere.from_sphere(unit_octahedron) vertices = hsph_updated.vertices bvecs = vertices bvals = np.ones(len(vertices)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) voxel = single_tensor(gtab) data = np.tile(voxel, (3, 3, 3, 1)) point = np.array([1., 1., 1.]) tensor_model = TensorModel(gtab) boot_pmf_gen = BootPmfGen(data, model=tensor_model, sphere=hsph_updated) no_boot_pmf = boot_pmf_gen.get_pmf_no_boot(point) model_pmf = tensor_model.fit(voxel).odf(hsph_updated) npt.assert_equal(len(hsph_updated.vertices), no_boot_pmf.shape[0]) npt.assert_array_almost_equal(no_boot_pmf, model_pmf) # test model spherical harmonic order different than bootstrap order with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", category=UserWarning) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) # Tests that the first catched warning comes from # the CSD model constructor npt.assert_(issubclass(w[0].category, UserWarning)) npt.assert_("Number of parameters required " in str(w[0].message)) # Tests that additionnal warnings are raised for outdated SH basis npt.assert_(len(w) > 1) boot_pmf_gen_sh4 = BootPmfGen(data, model=csd_model, sphere=hsph_updated, sh_order=4) pmf_sh4 = boot_pmf_gen_sh4.get_pmf(point) npt.assert_equal(len(hsph_updated.vertices), pmf_sh4.shape[0]) npt.assert_(np.sum(pmf_sh4.shape) > 0) boot_pmf_gen_sh8 = BootPmfGen(data, model=csd_model, sphere=hsph_updated, sh_order=8) pmf_sh8 = boot_pmf_gen_sh8.get_pmf(point) npt.assert_equal(len(hsph_updated.vertices), pmf_sh8.shape[0]) npt.assert_(np.sum(pmf_sh8.shape) > 0)
def test_mapmri_isotropic_static_scale_factor(radial_order=6): gtab = get_gtab_taiwan_dsi() D = 0.7e-3 tau = 1 / (4 * np.pi**2) mu = np.sqrt(D * 2 * tau) l1, l2, l3 = [D, D, D] S = single_tensor(gtab, evals=np.r_[l1, l2, l3]) S_array = np.tile(S, (5, 1)) stat_weight = 0.1 mapm_scale_stat_reg_stat = MapmriModel(gtab, radial_order=radial_order, anisotropic_scaling=False, dti_scale_estimation=False, static_diffusivity=D, laplacian_regularization=True, laplacian_weighting=stat_weight) mapm_scale_adapt_reg_stat = MapmriModel(gtab, radial_order=radial_order, anisotropic_scaling=False, dti_scale_estimation=True, laplacian_regularization=True, laplacian_weighting=stat_weight) start = time.time() mapf_scale_stat_reg_stat = mapm_scale_stat_reg_stat.fit(S_array) time_scale_stat_reg_stat = time.time() - start start = time.time() mapf_scale_adapt_reg_stat = mapm_scale_adapt_reg_stat.fit(S_array) time_scale_adapt_reg_stat = time.time() - start # test if indeed the scale factor is fixed now assert_equal(np.all(mapf_scale_stat_reg_stat.mu == mu), True) # test if computation time is shorter (except on Windows): if not platform.system() == "Windows": assert_equal( time_scale_stat_reg_stat < time_scale_adapt_reg_stat, True, "mapf_scale_stat_reg_stat ({0}s) slower than " "mapf_scale_adapt_reg_stat ({1}s). It should be the" " opposite.".format(time_scale_stat_reg_stat, time_scale_adapt_reg_stat)) # check if the fitted signal is the same assert_almost_equal(mapf_scale_stat_reg_stat.fitted_signal(), mapf_scale_adapt_reg_stat.fitted_signal())
def test_sticks_and_ball(): d = 0.0015 S, sticks = sticks_and_ball(gtab, d=d, S0=1, angles=[ (0, 0), ], fractions=[100], snr=None) assert_array_equal(sticks, [[0, 0, 1]]) S_st = single_tensor(gtab, 1, evals=[d, 0, 0], evecs=[[0, 0, 0], [0, 0, 0], [1, 0, 0]]) assert_array_almost_equal(S, S_st)
def test_bdg_initial_direction(): """This test the number of inital direction." """ hsph_updated = HemiSphere.from_sphere(unit_icosahedron).subdivide(2) vertices = hsph_updated.vertices bvecs = vertices bvals = np.ones(len(vertices)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) # test that we get one direction when we have a single tensor sphere = HemiSphere.from_sphere(get_sphere('symmetric724')) voxel = single_tensor(gtab).reshape([1, 1, 1, -1]) dti_model = dti.TensorModel(gtab) boot_dg = BootDirectionGetter.from_data(voxel, dti_model, 30, sphere=sphere, sh_order=6) initial_direction = boot_dg.initial_direction(np.zeros(3)) npt.assert_equal(len(initial_direction), 1) npt.assert_allclose(initial_direction[0], [1, 0, 0], atol=0.1) # test that we get multiple directions when we have a multi-tensor mevals = np.array([[1.5, 0.4, 0.4], [1.5, 0.4, 0.4]]) * 1e-3 fracs = [60, 40] voxel, primary_evecs = multi_tensor(gtab, mevals, fractions=fracs, snr=None) voxel = voxel.reshape([1, 1, 1, -1]) response = (np.array([0.0015, 0.0004, 0.0004]), 1) csd_model = ConstrainedSphericalDeconvModel(gtab, response=response, sh_order=4) boot_dg = BootDirectionGetter.from_data( voxel, csd_model, 30, sphere=sphere, ) initial_direction = boot_dg.initial_direction(np.zeros(3)) npt.assert_equal(len(initial_direction), 2) npt.assert_allclose(initial_direction, primary_evecs, atol=0.1)
def test_predict(): """ Test model prediction API """ psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[1, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ] S = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) assert_array_almost_equal(dmfit.predict(gtab, S0=100), S) assert_array_almost_equal(dm.predict(dmfit.model_params, S0=100), S) fdata, fbvals, fbvecs = get_data() data = nib.load(fdata).get_data() # Make the data cube a bit larger: data = np.tile(data.T, 2).T gtab = grad.gradient_table(fbvals, fbvecs) dtim = dti.TensorModel(gtab) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # Use a smaller step in predicting: dtim = dti.TensorModel(gtab, step=2) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # And with a scalar S0: S0 = 1 p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # Assign the step through kwarg: p = dtif.predict(gtab, S0, step=1) assert_equal(p.shape, data.shape)
def test_mapmri_isotropic_static_scale_factor(radial_order=6): gtab = get_gtab_taiwan_dsi() D = 0.7e-3 tau = 1 / (4 * np.pi ** 2) mu = np.sqrt(D * 2 * tau) l1, l2, l3 = [D, D, D] S = single_tensor(gtab, evals=np.r_[l1, l2, l3]) S_array = np.tile(S, (5, 1)) stat_weight = 0.1 mapm_scale_stat_reg_stat = MapmriModel(gtab, radial_order=radial_order, anisotropic_scaling=False, dti_scale_estimation=False, static_diffusivity=D, laplacian_regularization=True, laplacian_weighting=stat_weight) mapm_scale_adapt_reg_stat = MapmriModel(gtab, radial_order=radial_order, anisotropic_scaling=False, dti_scale_estimation=True, laplacian_regularization=True, laplacian_weighting=stat_weight) start = time.time() mapf_scale_stat_reg_stat = mapm_scale_stat_reg_stat.fit(S_array) time_scale_stat_reg_stat = time.time() - start start = time.time() mapf_scale_adapt_reg_stat = mapm_scale_adapt_reg_stat.fit(S_array) time_scale_adapt_reg_stat = time.time() - start # test if indeed the scale factor is fixed now assert_equal(np.all(mapf_scale_stat_reg_stat.mu == mu), True) # test if computation time is shorter (except on Windows): if not platform.system() == "Windows": assert_equal(time_scale_stat_reg_stat < time_scale_adapt_reg_stat, True) # check if the fitted signal is the same assert_almost_equal(mapf_scale_stat_reg_stat.fitted_signal(), mapf_scale_adapt_reg_stat.fitted_signal())
def test_boot_pmf(): """This tests the local model used for the bootstrapping. """ hsph_updated = HemiSphere.from_sphere(unit_octahedron) vertices = hsph_updated.vertices bvecs = vertices bvals = np.ones(len(vertices)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) voxel = single_tensor(gtab) data = np.tile(voxel, (3, 3, 3, 1)) point = np.array([1., 1., 1.]) tensor_model = TensorModel(gtab) boot_pmf_gen = BootPmfGen(data, model=tensor_model, sphere=hsph_updated) no_boot_pmf = boot_pmf_gen.get_pmf_no_boot(point) model_pmf = tensor_model.fit(voxel).odf(hsph_updated) npt.assert_equal(len(hsph_updated.vertices), no_boot_pmf.shape[0]) npt.assert_array_almost_equal(no_boot_pmf, model_pmf) # test model spherical harmonic order different than bootstrap order with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", category=UserWarning) csd_model = ConstrainedSphericalDeconvModel(gtab, None, sh_order=6) assert_greater( len([lw for lw in w if issubclass(lw.category, UserWarning)]), 0) boot_pmf_gen_sh4 = BootPmfGen(data, model=csd_model, sphere=hsph_updated, sh_order=4) pmf_sh4 = boot_pmf_gen_sh4.get_pmf(point) npt.assert_equal(len(hsph_updated.vertices), pmf_sh4.shape[0]) npt.assert_(np.sum(pmf_sh4.shape) > 0) boot_pmf_gen_sh8 = BootPmfGen(data, model=csd_model, sphere=hsph_updated, sh_order=8) pmf_sh8 = boot_pmf_gen_sh8.get_pmf(point) npt.assert_equal(len(hsph_updated.vertices), pmf_sh8.shape[0]) npt.assert_(np.sum(pmf_sh8.shape) > 0)
def estimate_response(gtab, evals, S0): """ Estimate single fiber response function Parameters ---------- gtab : GradientTable evals : ndarray S0 : float non diffusion weighted Returns ------- S : estimated signal """ evecs = np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) return single_tensor(gtab, S0, evals, evecs, snr=None)
def get_test_data(): _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) evals_list = [np.array([1.7E-3, 0.4E-3, 0.4E-3]), np.array([4.0E-4, 4.0E-4, 4.0E-4]), np.array([3.0E-3, 3.0E-3, 3.0E-3])] s0 = [0.8, 1, 4] signals = [single_tensor(gtab, x[0], x[1]) for x in zip(s0, evals_list)] tissues = [0, 0, 2, 0, 1, 0, 0, 1, 2] data = [signals[tissue] for tissue in tissues] data = np.asarray(data).reshape((3, 3, 1, len(signals[0]))) evals = [evals_list[tissue] for tissue in tissues] evals = np.asarray(evals).reshape((3, 3, 1, 3)) tissues = np.asarray(tissues).reshape((3, 3, 1)) mask = np.where(tissues == 0, 1, 0) response = (evals_list[0], s0[0]) fa = fractional_anisotropy(evals) return (gtab, data, mask, response, fa)
def test_boot_pmf(): """This tests the local model used for the bootstrapping. """ hsph_updated = HemiSphere.from_sphere(unit_octahedron) vertices = hsph_updated.vertices bvecs = vertices bvals = np.ones(len(vertices)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) voxel = single_tensor(gtab) data = np.tile(voxel, (3, 3, 3, 1)) point = np.array([1., 1., 1.]) tensor_model = TensorModel(gtab) boot_pmf_gen = BootPmfGen(data, model=tensor_model, sphere=hsph_updated) no_boot_pmf = boot_pmf_gen.get_pmf_no_boot(point) model_pmf = tensor_model.fit(voxel).odf(hsph_updated) npt.assert_equal(len(hsph_updated.vertices), no_boot_pmf.shape[0]) npt.assert_array_almost_equal(no_boot_pmf, model_pmf) # test model sherical harminic order different than bootstrap order with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", category=UserWarning) csd_model = ConstrainedSphericalDeconvModel(gtab, None, sh_order=6) assert_greater(len([lw for lw in w if issubclass(lw.category, UserWarning)]), 0) boot_pmf_gen_sh4 = BootPmfGen(data, model=csd_model, sphere=hsph_updated, sh_order=4) pmf_sh4 = boot_pmf_gen_sh4.get_pmf(point) npt.assert_equal(len(hsph_updated.vertices), pmf_sh4.shape[0]) npt.assert_(np.sum(pmf_sh4.shape) > 0) boot_pmf_gen_sh8 = BootPmfGen(data, model=csd_model, sphere=hsph_updated, sh_order=8) pmf_sh8 = boot_pmf_gen_sh8.get_pmf(point) npt.assert_equal(len(hsph_updated.vertices), pmf_sh8.shape[0]) npt.assert_(np.sum(pmf_sh8.shape) > 0)
def test_dti_xval(): """ Test k-fold cross-validation """ data = nib.load(fdata).get_data() gtab = gt.gradient_table(fbval, fbvec) dm = dti.TensorModel(gtab, 'LS') # The data has 102 directions, so will not divide neatly into 10 bits npt.assert_raises(ValueError, xval.kfold_xval, dm, data, 10) # But we can do this with 2 folds: kf_xval = xval.kfold_xval(dm, data, 2) # In simulation with no noise, COD should be perfect: psphere = dpd.get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = gt.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ] S = sims.single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') kf_xval = xval.kfold_xval(dm, S, 2) cod = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(cod, np.ones(kf_xval.shape[:-1]) * 100) # Test with 2D data for use of a mask S = np.array([[S, S], [S, S]]) mask = np.ones(S.shape[:-1], dtype=bool) mask[1, 1] = 0 kf_xval = xval.kfold_xval(dm, S, 2, mask=mask) cod2d = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(np.round(cod2d[0, 0]), cod)
def make_dti_data(out_fbval, out_fbvec, out_fdata, out_shape=(5, 6, 7)): """ Create a synthetic data-set with a single shell acquisition out_fbval, out_fbvec, out_fdata : str Full paths to generated data and bval/bvec files out_shape : tuple The 3D shape of the output volum """ fimg, fbvals, fbvecs = dpd.get_data('small_64D') img = nib.load(fimg) bvals, bvecs = dio.read_bvals_bvecs(fbvals, fbvecs) gtab = dpg.gradient_table(bvals, bvecs) # Simulate a signal based on the DTI model: signal = single_tensor(gtab, S0=100) DWI = np.zeros(out_shape + (len(gtab.bvals), )) DWI[:] = signal nib.save(nib.Nifti1Image(DWI, img.affine), out_fdata) np.savetxt(out_fbval, bvals) np.savetxt(out_fbvec, bvecs)
def test_mapmri_metrics_isotropic(radial_order=6): gtab = get_gtab_taiwan_dsi() l1, l2, l3 = [0.0003, 0.0003, 0.0003] # isotropic diffusivities S = single_tensor(gtab, evals=np.r_[l1, l2, l3]) # test MAPMRI q-space indices with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) mapm = MapmriModel(gtab, radial_order=radial_order, laplacian_regularization=False, anisotropic_scaling=False) mapfit = mapm.fit(S) tau = 1 / (4 * np.pi**2) # ground truth indices estimated from the DTI tensor rtpp_gt = 1. / (2 * np.sqrt(np.pi * l1 * tau)) rtap_gt = (1. / (2 * np.sqrt(np.pi * l2 * tau)) * 1. / (2 * np.sqrt(np.pi * l3 * tau))) rtop_gt = rtpp_gt * rtap_gt msd_gt = 2 * (l1 + l2 + l3) * tau qiv_gt = ((64 * np.pi**(7 / 2.) * (l1 * l2 * l3 * tau**3)**(3 / 2.)) / ((l2 * l3 + l1 * (l2 + l3)) * tau**2)) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) assert_almost_equal(mapfit.rtap(), rtap_gt, 5) assert_almost_equal(mapfit.rtpp(), rtpp_gt, 5) assert_almost_equal(mapfit.rtop(), rtop_gt, 4) assert_almost_equal(mapfit.msd(), msd_gt, 5) assert_almost_equal(mapfit.qiv(), qiv_gt, 5)
def test_predict(): """ Test model prediction API """ psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[1, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array( [ [1, 0, 0], [0, 1, 0], [0, 0, 1] ] ), np.array( [ [0, 0, 1], [0, 1, 0], [1, 0, 0] ] ) ] S = single_tensor( gtab, 100, mevals[0], mevecs[0], snr=None ) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) assert_array_almost_equal(dmfit.predict(gtab, S0=100), S) assert_array_almost_equal(dm.predict(dmfit.model_params, S0=100), S) data, gtab = dsi_voxels() dtim = dti.TensorModel(gtab) dtif = dtim.fit(data) S0 = np.mean(data[...,gtab.b0s_mask], -1) p = dtif.predict(gtab, S0)
def sfm_design_matrix(gtab, sphere, response, mode='signal'): """ Construct the SFM design matrix Parameters ---------- gtab : GradientTable or Sphere Sets the rows of the matrix, if the mode is 'signal', this should be a GradientTable. If mode is 'odf' this should be a Sphere sphere : Sphere Sets the columns of the matrix response : list of 3 elements The eigenvalues of a tensor which will serve as a kernel function. mode : str {'signal' | 'odf'}, optional Choose the (default) 'signal' for a design matrix containing predicted signal in the measurements defined by the gradient table for putative fascicles oriented along the vertices of the sphere. Otherwise, choose 'odf' for an odf convolution matrix, with values of the odf calculated from a tensor with the provided response eigenvalues, evaluated at the b-vectors in the gradient table, for the tensors with prinicipal diffusion directions along the vertices of the sphere. Returns ------- mat : ndarray A design matrix that can be used for one of the following operations: when the 'signal' mode is used, each column contains the putative signal in each of the bvectors of the `gtab` if a fascicle is oriented in the direction encoded by the sphere vertex corresponding to this column. This is used for deconvolution with a measured DWI signal. If the 'odf' mode is chosen, each column instead contains the values of the tensor ODF for a tensor with a principal diffusion direction corresponding to this vertex. This is used to generate odfs from the fits of the SFM for the purpose of tracking. Examples -------- >>> import dipy.data as dpd >>> data, gtab = dpd.dsi_voxels() >>> sphere = dpd.get_sphere() >>> from dipy.reconst.sfm import sfm_design_matrix A canonical tensor approximating corpus-callosum voxels [Rokem2014]_: >>> tensor_matrix=sfm_design_matrix(gtab, sphere, [0.0015, 0.0005, 0.0005]) A 'stick' function ([Behrens2007]_): >>> stick_matrix = sfm_design_matrix(gtab, sphere, [0.001, 0, 0]) Notes ----- .. [Rokem2014] Ariel Rokem, Jason D. Yeatman, Franco Pestilli, Kendrick N. Kay, Aviv Mezer, Stefan van der Walt, Brian A. Wandell (2014). Evaluating the accuracy of diffusion MRI models in white matter. http://arxiv.org/abs/1411.0721 .. [Behrens2007] Behrens TEJ, Berg HJ, Jbabdi S, Rushworth MFS, Woolrich MW (2007): Probabilistic diffusion tractography with multiple fibre orientations: What can we gain? Neuroimage 34:144-55. """ # Each column of the matrix is the signal in each measurement, as # predicted by a "canonical", symmetrical tensor rotated towards this # vertex of the sphere: canonical_tensor = np.diag(response) if mode == 'signal': mat_gtab = grad.gradient_table(gtab.bvals[~gtab.b0s_mask], gtab.bvecs[~gtab.b0s_mask]) # Preallocate: mat = np.empty((np.sum(~gtab.b0s_mask), sphere.vertices.shape[0])) elif mode == 'odf': mat = np.empty((gtab.x.shape[0], sphere.vertices.shape[0])) # Calculate column-wise: for ii, this_dir in enumerate(sphere.vertices): # Rotate the canonical tensor towards this vertex and calculate the # signal you would have gotten in the direction rot_matrix = geo.vec2vec_rotmat(np.array([1, 0, 0]), this_dir) this_tensor = np.dot(rot_matrix, canonical_tensor) evals, evecs = dti.decompose_tensor(this_tensor) if mode == 'signal': sig = sims.single_tensor(mat_gtab, evals=response, evecs=evecs) mat[:, ii] = sig - np.mean(sig) elif mode == 'odf': # Stick function if response[1] == 0 or response[2] == 0: jj = sphere.find_closest(evecs[0]) mat[jj, ii] = 1 else: odf = sims.single_tensor_odf(gtab.vertices, evals=response, evecs=evecs) mat[:, ii] = odf return mat
def test_bootstap_peak_tracker(): """This tests that the Bootstrat Peak Direction Getter plays nice LocalTracking and produces reasonable streamlines in a simple example. """ sphere = get_sphere('repulsion100') # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing simple_image = np.array([ [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [2, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] bvecs = sphere.vertices bvals = np.ones(len(bvecs)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) angles = [(90, 90), (90, 0)] fracs = [50, 50] mevals = np.array([[1.5, 0.4, 0.4], [1.5, 0.4, 0.4]]) * 1e-3 mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) ] voxel1 = single_tensor(gtab, 1, mevals[0], mevecs[0], snr=None) voxel2 = single_tensor(gtab, 1, mevals[0], mevecs[1], snr=None) voxel3, _ = multi_tensor(gtab, mevals, fractions=fracs, angles=angles, snr=None) data = np.tile(voxel3, [5, 6, 1, 1]) data[simple_image == 1] = voxel1 data[simple_image == 2] = voxel2 response = (np.array(mevals[1]), 1) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) seeds = [np.array([0., 1., 0.]), np.array([2., 4., 0.])] sc = BinaryStoppingCriterion((simple_image > 0).astype(float)) sphere = HemiSphere.from_sphere(get_sphere('symmetric724')) boot_dg = BootDirectionGetter.from_data(data, csd_model, 60, sphere=sphere) streamlines_generator = LocalTracking(boot_dg, sc, seeds, np.eye(4), 1.) streamlines = Streamlines(streamlines_generator) expected = [ np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [3., 1., 0.], [4., 1., 0.]]), np.array([ [2., 4., 0.], [2., 3., 0.], [2., 2., 0.], [2., 1., 0.], [2., 0., 0.], ]) ] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y, atol=0.5) if not allclose(streamlines[0], expected[0]): raise AssertionError() if not allclose(streamlines[1], expected[1]): raise AssertionError()
def test_csdeconv(): SNR = 100 S0 = 1 _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs, b0_threshold=0) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric362') odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) assert_equal(csd_fit.shm_coeff[0] > 0, True) fodf = csd_fit.odf(sphere) directions, _, _ = peak_directions(odf_gt, sphere) directions2, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions, directions2) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) assert_equal(directions2.shape[0], 2) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", category=UserWarning) _ = ConstrainedSphericalDeconvModel(gtab, response, sh_order=10) assert_greater(len([lw for lw in w if issubclass(lw.category, UserWarning)]), 0) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", category=UserWarning) ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) assert_equal(len([lw for lw in w if issubclass(lw.category, UserWarning)]), 0) mevecs = [] for s in sticks: mevecs += [all_tensor_evecs(s).T] S2 = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) big_S = np.zeros((10, 10, 10, len(S2))) big_S[:] = S2 aresponse, aratio = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) assert_almost_equal(aresponse[1], 100) assert_almost_equal(aratio, response[0][1] / response[0][0]) auto_response(gtab, big_S, roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) _, _, nvoxels = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=30, fa_thr=0.5, return_number_of_voxels=True) assert_equal(nvoxels, 1000) _, _, nvoxels = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=30, fa_thr=1, return_number_of_voxels=True) assert_equal(nvoxels, 0)
from dipy.data import get_data fimg, fbvals, fbvecs = get_data('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) # FW model requires multishell data bvals_2s = np.concatenate((bvals, bvals * 1.5), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = gradient_table(bvals_2s, bvecs_2s) # Simulation a typical DT and DW signal for no water contamination S0 = np.array(100) dt = np.array([0.0017, 0, 0.0003, 0, 0, 0.0003]) evals, evecs = decompose_tensor(from_lower_triangular(dt)) S_tissue = single_tensor(gtab_2s, S0=100, evals=evals, evecs=evecs, snr=None) dm = dti.TensorModel(gtab_2s, 'WLS') dtifit = dm.fit(S_tissue) FAdti = dtifit.fa MDdti = dtifit.md dtiparams = dtifit.model_params # Simulation of 8 voxels tested DWI = np.zeros((2, 2, 2, len(gtab_2s.bvals))) FAref = np.zeros((2, 2, 2)) MDref = np.zeros((2, 2, 2)) # Diffusion of tissue and water compartments are constant for all voxel mevals = np.array([[0.0017, 0.0003, 0.0003], [0.003, 0.003, 0.003]]) # volume fractions GTF = np.array([[[0.06, 0.71], [0.33, 0.91]], [[0., 0.], [0., 0.]]]) # S0 multivoxel
def generate_kernel(gtab, sphere, wm_response, gm_response, csf_response): ''' Generate deconvolution kernel Compute kernel mapping orientation densities of white matter fiber populations (along each vertex of the sphere) and isotropic volume fractions to a diffusion weighted signal. Parameters ---------- gtab : GradientTable sphere : Sphere Sphere with which to sample discrete fiber orientations in order to construct kernel wm_response : 1d ndarray or 2d ndarray or AxSymShResponse, optional Tensor eigenvalues as a (3,) ndarray, multishell eigenvalues as a (len(unique_bvals_tolerance(gtab.bvals))-1, 3) ndarray in order of smallest to largest b-value, or an AxSymShResponse. gm_response : float, optional Mean diffusivity for GM compartment. If `None`, then grey matter compartment set to all zeros. csf_response : float, optional Mean diffusivity for CSF compartment. If `None`, then CSF compartment set to all zeros. Returns ------- kernel : 2d ndarray (N, M) Computed kernel; can be multiplied with a vector consisting of volume fractions for each of M-2 fiber populations as well as GM and CSF fractions to produce a diffusion weighted signal. ''' # Coordinates of sphere vertices sticks = sphere.vertices n_grad = len(gtab.gradients) # number of gradient directions n_wm_comp = sticks.shape[0] # number of fiber populations n_comp = n_wm_comp + 2 # plus isotropic compartments kernel = np.zeros((n_grad, n_comp)) # White matter compartments list_bvals = unique_bvals_tolerance(gtab.bvals) n_bvals = len(list_bvals) - 1 # number of unique b-values if isinstance(wm_response, AxSymShResponse): # Data-driven response where_dwi = lazy_index(~gtab.b0s_mask) gradients = gtab.gradients[where_dwi] gradients = gradients / np.linalg.norm(gradients, axis=1)[..., None] S0 = wm_response.S0 for i in range(n_wm_comp): # Response oriented along [0, 0, 1], so must rotate sticks[i] rot_mat = vec2vec_rotmat(sticks[i], np.array([0, 0, 1])) rot_gradients = np.dot(rot_mat, gradients.T).T rot_sphere = Sphere(xyz=rot_gradients) # Project onto rotated sphere and scale rot_response = wm_response.on_sphere(rot_sphere) / S0 kernel[where_dwi, i] = rot_response # Set b0 components kernel[gtab.b0s_mask, :] = 1 elif wm_response.shape == (n_bvals, 3): # Multi-shell response bvals = gtab.bvals bvecs = gtab.bvecs for n, bval in enumerate(list_bvals[1:]): indices = get_bval_indices(bvals, bval) with warnings.catch_warnings(): # extract relevant b-value warnings.simplefilter("ignore") gtab_sub = gradient_table(bvals[indices], bvecs[indices]) for i in range(n_wm_comp): # Signal generated by WM-fiber for each gradient direction S = single_tensor(gtab_sub, evals=wm_response[n], evecs=all_tensor_evecs(sticks[i])) kernel[indices, i] = S # Set b0 components b0_indices = get_bval_indices(bvals, list_bvals[0]) kernel[b0_indices, :] = 1 else: # Single-shell response for i in range(n_wm_comp): # Signal generated by WM-fiber for each gradient direction S = single_tensor(gtab, evals=wm_response, evecs=all_tensor_evecs(sticks[i])) kernel[:, i] = S # Set b0 components kernel[gtab.b0s_mask, :] = 1 # GM compartment if gm_response is None: S_gm = np.zeros((n_grad)) else: S_gm = \ single_tensor(gtab, evals=np.array( [gm_response, gm_response, gm_response])) if csf_response is None: S_csf = np.zeros((n_grad)) else: S_csf = \ single_tensor(gtab, evals=np.array( [csf_response, csf_response, csf_response])) kernel[:, n_comp - 2] = S_gm kernel[:, n_comp - 1] = S_csf return kernel
def test_recursive_response_calibration(): """ Test the recursive response calibration method. """ SNR = 100 S0 = 1 _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) sphere = default_sphere gtab = gradient_table(bvals, bvecs) evals = np.array([0.0015, 0.0003, 0.0003]) evecs = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]).T mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (90, 0)] where_dwi = lazy_index(~gtab.b0s_mask) S_cross, _ = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) S_single = single_tensor(gtab, S0, evals, evecs, snr=SNR) data = np.concatenate((np.tile(S_cross, (8, 1)), np.tile(S_single, (2, 1))), axis=0) odf_gt_cross = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) odf_gt_single = single_tensor_odf(sphere.vertices, evals, evecs) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) response = recursive_response(gtab, data, mask=None, sh_order=8, peak_thr=0.01, init_fa=0.05, init_trace=0.0021, iter=8, convergence=0.001, parallel=False) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(data) assert_equal(np.all(csd_fit.shm_coeff[:, 0] >= 0), True) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) fodf = csd_fit.odf(sphere) directions_gt_single, _, _ = peak_directions(odf_gt_single, sphere) directions_gt_cross, _, _ = peak_directions(odf_gt_cross, sphere) directions_single, _, _ = peak_directions(fodf[8, :], sphere) directions_cross, _, _ = peak_directions(fodf[0, :], sphere) ang_sim = angular_similarity(directions_cross, directions_gt_cross) assert_equal(ang_sim > 1.9, True) assert_equal(directions_cross.shape[0], 2) assert_equal(directions_gt_cross.shape[0], 2) ang_sim = angular_similarity(directions_single, directions_gt_single) assert_equal(ang_sim > 0.9, True) assert_equal(directions_single.shape[0], 1) assert_equal(directions_gt_single.shape[0], 1) with warnings.catch_warnings(record=True) as w: sphere = Sphere(xyz=gtab.gradients[where_dwi]) npt.assert_equal(len(w), 1) npt.assert_(issubclass(w[0].category, UserWarning)) npt.assert_("Vertices are not on the unit sphere" in str(w[0].message)) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) sf = response.on_sphere(sphere) S = np.concatenate(([response.S0], sf)) tenmodel = TensorModel(gtab, min_signal=0.001) tenfit = tenmodel.fit(S) FA = fractional_anisotropy(tenfit.evals) FA_gt = fractional_anisotropy(evals) assert_almost_equal(FA, FA_gt, 1)
from dipy.data import get_data fimg, fbvals, fbvecs = get_data('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) # FW model requires multishell data bvals_2s = np.concatenate((bvals, bvals * 1.5), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = gradient_table(bvals_2s, bvecs_2s) # Simulation a typical DT and DW signal for no water contamination S0 = np.array(100) dt = np.array([0.0017, 0, 0.0003, 0, 0, 0.0003]) evals, evecs = decompose_tensor(from_lower_triangular(dt)) S_tissue = single_tensor(gtab_2s, S0=100, evals=evals, evecs=evecs, snr=None) dm = dti.TensorModel(gtab_2s, 'WLS') dtifit = dm.fit(S_tissue) FAdti = dtifit.fa MDdti = dtifit.md dtiparams = dtifit.model_params # Simulation of 8 voxels tested DWI = np.zeros((2, 2, 2, len(gtab_2s.bvals))) FAref = np.zeros((2, 2, 2)) MDref = np.zeros((2, 2, 2)) # Diffusion of tissue and water compartments are constant for all voxel mevals = np.array([[0.0017, 0.0003, 0.0003], [0.003, 0.003, 0.003]]) # volume fractions GTF = np.array([[[0.06, 0.71], [0.33, 0.91]], [[0., 0.], [0., 0.]]])
def test_recursive_response_calibration(): """ Test the recursive response calibration method. """ SNR = 100 S0 = 1 sh_order = 8 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) sphere = get_sphere('symmetric724') gtab = gradient_table(bvals, bvecs) evals = np.array([0.0015, 0.0003, 0.0003]) evecs = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]).T mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (90, 0)] where_dwi = lazy_index(~gtab.b0s_mask) S_cross, sticks_cross = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) S_single = single_tensor(gtab, S0, evals, evecs, snr=SNR) data = np.concatenate((np.tile(S_cross, (8, 1)), np.tile(S_single, (2, 1))), axis=0) odf_gt_cross = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) odf_gt_single = single_tensor_odf(sphere.vertices, evals, evecs) response = recursive_response(gtab, data, mask=None, sh_order=8, peak_thr=0.01, init_fa=0.05, init_trace=0.0021, iter=8, convergence=0.001, parallel=False) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(data) assert_equal(np.all(csd_fit.shm_coeff[:, 0] >= 0), True) fodf = csd_fit.odf(sphere) directions_gt_single, _, _ = peak_directions(odf_gt_single, sphere) directions_gt_cross, _, _ = peak_directions(odf_gt_cross, sphere) directions_single, _, _ = peak_directions(fodf[8, :], sphere) directions_cross, _, _ = peak_directions(fodf[0, :], sphere) ang_sim = angular_similarity(directions_cross, directions_gt_cross) assert_equal(ang_sim > 1.9, True) assert_equal(directions_cross.shape[0], 2) assert_equal(directions_gt_cross.shape[0], 2) ang_sim = angular_similarity(directions_single, directions_gt_single) assert_equal(ang_sim > 0.9, True) assert_equal(directions_single.shape[0], 1) assert_equal(directions_gt_single.shape[0], 1) sphere = Sphere(xyz=gtab.gradients[where_dwi]) sf = response.on_sphere(sphere) S = np.concatenate(([response.S0], sf)) tenmodel = dti.TensorModel(gtab, min_signal=0.001) tenfit = tenmodel.fit(S) FA = fractional_anisotropy(tenfit.evals) FA_gt = fractional_anisotropy(evals) assert_almost_equal(FA, FA_gt, 1)
def sfm_design_matrix(gtab, sphere, response, mode='signal'): """ Construct the SFM design matrix Parameters ---------- gtab : GradientTable or Sphere Sets the rows of the matrix, if the mode is 'signal', this should be a GradientTable. If mode is 'odf' this should be a Sphere sphere : Sphere Sets the columns of the matrix response : list of 3 elements The eigenvalues of a tensor which will serve as a kernel function. mode : str {'signal' | 'odf'}, optional Choose the (default) 'signal' for a design matrix containing predicted signal in the measurements defined by the gradient table for putative fascicles oriented along the vertices of the sphere. Otherwise, choose 'odf' for an odf convolution matrix, with values of the odf calculated from a tensor with the provided response eigenvalues, evaluated at the b-vectors in the gradient table, for the tensors with prinicipal diffusion directions along the vertices of the sphere. Returns ------- mat : ndarray A design matrix that can be used for one of the following operations: when the 'signal' mode is used, each column contains the putative signal in each of the bvectors of the `gtab` if a fascicle is oriented in the direction encoded by the sphere vertex corresponding to this column. This is used for deconvolution with a measured DWI signal. If the 'odf' mode is chosen, each column instead contains the values of the tensor ODF for a tensor with a principal diffusion direction corresponding to this vertex. This is used to generate odfs from the fits of the SFM for the purpose of tracking. Examples -------- >>> import dipy.data as dpd >>> data, gtab = dpd.dsi_voxels() >>> sphere = dpd.get_sphere() >>> from dipy.reconst.sfm import sfm_design_matrix A canonical tensor approximating corpus-callosum voxels [Rokem2014]_: >>> tensor_matrix = sfm_design_matrix(gtab, sphere, ... [0.0015, 0.0005, 0.0005]) A 'stick' function ([Behrens2007]_): >>> stick_matrix = sfm_design_matrix(gtab, sphere, [0.001, 0, 0]) Notes ----- .. [Rokem2015] Ariel Rokem, Jason D. Yeatman, Franco Pestilli, Kendrick N. Kay, Aviv Mezer, Stefan van der Walt, Brian A. Wandell (2015). Evaluating the accuracy of diffusion MRI models in white matter. PLoS ONE 10(4): e0123272. doi:10.1371/journal.pone.0123272 .. [Rokem2014] Ariel Rokem, Kimberly L. Chan, Jason D. Yeatman, Franco Pestilli, Brian A. Wandell (2014). Evaluating the accuracy of diffusion models at multiple b-values with cross-validation. ISMRM 2014. .. [Behrens2007] Behrens TEJ, Berg HJ, Jbabdi S, Rushworth MFS, Woolrich MW (2007): Probabilistic diffusion tractography with multiple fibre orientations: What can we gain? Neuroimage 34:144-55. """ if mode == 'signal': mat_gtab = grad.gradient_table(gtab.bvals[~gtab.b0s_mask], gtab.bvecs[~gtab.b0s_mask]) # Preallocate: mat = np.empty((np.sum(~gtab.b0s_mask), sphere.vertices.shape[0])) elif mode == 'odf': mat = np.empty((gtab.x.shape[0], sphere.vertices.shape[0])) # Calculate column-wise: for ii, this_dir in enumerate(sphere.vertices): # Rotate the canonical tensor towards this vertex and calculate the # signal you would have gotten in the direction evecs = sims.all_tensor_evecs(this_dir) if mode == 'signal': sig = sims.single_tensor(mat_gtab, evals=response, evecs=evecs) # For regressors based on the single tensor, remove $e^{-bD}$ iso_sig = np.exp(-mat_gtab.bvals * np.mean(response)) mat[:, ii] = sig - iso_sig elif mode == 'odf': # Stick function if response[1] == 0 or response[2] == 0: jj = sphere.find_closest(evecs[0]) mat[jj, ii] = 1 else: odf = sims.single_tensor_odf(gtab.vertices, evals=response, evecs=evecs) mat[:, ii] = odf return mat
We can also add Rician noise with a specific SNR. """ signal_noisy, dt, kt = multi_tensor_dki(gtab, mevals, S0=200, angles=angles, fractions=fractions, snr=10) """ For comparison purposes, we also compute the DW signal if only the diffusion tensor components are taken into account. For this we use DIPY's function ``single_tensor`` which requires that dt is decomposed into its eigenvalues and eigenvectors. """ dt_evals, dt_evecs = decompose_tensor(from_lower_triangular(dt)) signal_dti = single_tensor(gtab, S0=200, evals=dt_evals, evecs=dt_evecs, snr=None) """ Finally, we can visualize the values of the different version of simulated signals for all assumed gradient directions and bvalues. """ plt.plot(signal_dti, label='noiseless dti') plt.plot(signal_dki, label='noiseless dki') plt.plot(signal_noisy, label='with noise') plt.legend() plt.show() plt.savefig('simulated_dki_signal.png') """
def test_predict(): """ Test model prediction API """ psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[1, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]])] S = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS', return_S0_hat=True) dmfit = dm.fit(S) assert_array_almost_equal(dmfit.predict(gtab, S0=100), S) assert_array_almost_equal(dmfit.predict(gtab), S) assert_array_almost_equal(dm.predict(dmfit.model_params, S0=100), S) fdata, fbvals, fbvecs = get_data() data = nib.load(fdata).get_data() # Make the data cube a bit larger: data = np.tile(data.T, 2).T gtab = grad.gradient_table(fbvals, fbvecs) dtim = dti.TensorModel(gtab) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # Predict using S0_hat: dtim = dti.TensorModel(gtab, return_S0_hat=True) dtif = dtim.fit(data) p = dtif.predict(gtab) assert_equal(p.shape, data.shape) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # Test iter_fit_tensor with S0_hat dtim = dti.TensorModel(gtab, step=2, return_S0_hat=True) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # Use a smaller step in predicting: dtim = dti.TensorModel(gtab, step=2) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # And with a scalar S0: S0 = 1 p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape) # Assign the step through kwarg: p = dtif.predict(gtab, S0, step=1) assert_equal(p.shape, data.shape) # And without S0: p = dtif.predict(gtab, step=1) assert_equal(p.shape, data.shape)
mevals, S0=200, angles=angles, fractions=fractions, snr=10) """ For comparison purposes, we also compute the DW signal if only the diffusion tensor components are taken into account. For this we use Dipy's function single_tensor which requires that dt is decomposed into its eigenvalues and eigenvectors. """ dt_evals, dt_evecs = decompose_tensor(from_lower_triangular(dt)) signal_dti = single_tensor(gtab, S0=200, evals=dt_evals, evecs=dt_evecs, snr=None) """ Finally, we can visualize the values of the different version of simulated signals for all assumed gradient directions and bvalues. """ plt.plot(signal_dti, label='noiseless dti') plt.plot(signal_dki, label='noiseless dki') plt.plot(signal_noisy, label='with noise') plt.legend() plt.show() plt.savefig('simulated_dki_signal.png') """ .. figure:: simulated_dki_signal.png
def multi_shell_fiber_response(sh_order, bvals, wm_rf, gm_rf, csf_rf, sphere=None, tol=20): """Fiber response function estimation for multi-shell data. Parameters ---------- sh_order : int Maximum spherical harmonics order. bvals : ndarray Array containing the b-values. Must be unique b-values, like outputed by `dipy.core.gradients.unique_bvals_tolerance`. wm_rf : (4, len(bvals)) ndarray Response function of the WM tissue, for each bvals. gm_rf : (4, len(bvals)) ndarray Response function of the GM tissue, for each bvals. csf_rf : (4, len(bvals)) ndarray Response function of the CSF tissue, for each bvals. sphere : `dipy.core.Sphere` instance, optional Sphere where the signal will be evaluated. Returns ------- MultiShellResponse MultiShellResponse object. """ NUMPY_1_14_PLUS = LooseVersion(np.__version__) >= LooseVersion('1.14.0') rcond_value = None if NUMPY_1_14_PLUS else -1 bvals = np.array(bvals, copy=True) evecs = np.zeros((3, 3)) z = np.array([0, 0, 1.]) evecs[:, 0] = z evecs[:2, 1:] = np.eye(2) n = np.arange(0, sh_order + 1, 2) m = np.zeros_like(n) if sphere is None: sphere = default_sphere big_sphere = sphere.subdivide() theta, phi = big_sphere.theta, big_sphere.phi B = shm.real_sh_descoteaux_from_index(m, n, theta[:, None], phi[:, None]) A = shm.real_sh_descoteaux_from_index(0, 0, 0, 0) response = np.empty([len(bvals), len(n) + 2]) if bvals[0] < tol: gtab = GradientTable(big_sphere.vertices * 0) wm_response = single_tensor(gtab, wm_rf[0, 3], wm_rf[0, :3], evecs, snr=None) response[0, 2:] = np.linalg.lstsq(B, wm_response, rcond=rcond_value)[0] response[0, 1] = gm_rf[0, 3] / A response[0, 0] = csf_rf[0, 3] / A for i, bvalue in enumerate(bvals[1:]): gtab = GradientTable(big_sphere.vertices * bvalue) wm_response = single_tensor(gtab, wm_rf[i, 3], wm_rf[i, :3], evecs, snr=None) response[i + 1, 2:] = np.linalg.lstsq(B, wm_response, rcond=rcond_value)[0] response[i + 1, 1] = gm_rf[i, 3] * np.exp(-bvalue * gm_rf[i, 0]) / A response[i + 1, 0] = csf_rf[i, 3] * np.exp(-bvalue * csf_rf[i, 0]) / A S0 = [csf_rf[0, 3], gm_rf[0, 3], wm_rf[0, 3]] else: warnings.warn("""No b0 given. Proceeding either way.""", UserWarning) for i, bvalue in enumerate(bvals): gtab = GradientTable(big_sphere.vertices * bvalue) wm_response = single_tensor(gtab, wm_rf[i, 3], wm_rf[i, :3], evecs, snr=None) response[i, 2:] = np.linalg.lstsq(B, wm_response, rcond=rcond_value)[0] response[i, 1] = gm_rf[i, 3] * np.exp(-bvalue * gm_rf[i, 0]) / A response[i, 0] = csf_rf[i, 3] * np.exp(-bvalue * csf_rf[i, 0]) / A S0 = [csf_rf[0, 3], gm_rf[0, 3], wm_rf[0, 3]] return MultiShellResponse(response, sh_order, bvals, S0=S0)
def test_bootstap_peak_tracker(): """This tests that the Bootstrat Peak Direction Getter plays nice LocalTracking and produces reasonable streamlines in a simple example. """ sphere = get_sphere('repulsion100') # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing simple_image = np.array([[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [2, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] bvecs = sphere.vertices bvals = np.ones(len(bvecs)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) angles = [(90, 90), (90, 0)] fracs = [50, 50] mevals = np.array([[1.5, 0.4, 0.4], [1.5, 0.4, 0.4]]) * 1e-3 mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]])] voxel1 = single_tensor(gtab, 1, mevals[0], mevecs[0], snr=None) voxel2 = single_tensor(gtab, 1, mevals[0], mevecs[1], snr=None) voxel3, _ = multi_tensor(gtab, mevals, fractions=fracs, angles=angles, snr=None) data = np.tile(voxel3, [5, 6, 1, 1]) data[simple_image == 1] = voxel1 data[simple_image == 2] = voxel2 response = (np.array(mevals[1]), 1) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) seeds = [np.array([0., 1., 0.]), np.array([2., 4., 0.])] tc = BinaryTissueClassifier((simple_image > 0).astype(float)) boot_dg = BootDirectionGetter.from_data(data, csd_model, 60) streamlines_generator = LocalTracking(boot_dg, tc, seeds, np.eye(4), 1.) streamlines = Streamlines(streamlines_generator) expected = [np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [3., 1., 0.], [4., 1., 0.]]), np.array([[2., 5., 0.], [2., 4., 0.], [2., 3., 0.], [2., 2., 0.], [2., 1., 0.], [2., 0., 0.], ])] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y, atol=0.5) if not allclose(streamlines[0], expected[0]): raise AssertionError() if not allclose(streamlines[1], expected[1]): raise AssertionError()
def orbital_phantom(gtab=None, evals=diffusion_evals, func=None, t=np.linspace(0, 2 * np.pi, 1000), datashape=(64, 64, 64, 65), origin=(32, 32, 32), scale=(25, 25, 25), angles=np.linspace(0, 2 * np.pi, 32), radii=np.linspace(0.2, 2, 6), S0=100., snr=None): """Create a phantom based on a 3-D orbit ``f(t) -> (x,y,z)``. Parameters ----------- gtab : GradientTable Gradient table of measurement directions. evals : array, shape (3,) Tensor eigenvalues. func : user defined function f(t)->(x,y,z) It could be desirable for ``-1=<x,y,z <=1``. If None creates a circular orbit. t : array, shape (K,) Represents time for the orbit. Default is ``np.linspace(0, 2 * np.pi, 1000)``. datashape : array, shape (X,Y,Z,W) Size of the output simulated data origin : tuple, shape (3,) Define the center for the volume scale : tuple, shape (3,) Scale the function before applying to the grid angles : array, shape (L,) Density angle points, always perpendicular to the first eigen vector Default np.linspace(0, 2 * np.pi, 32). radii : array, shape (M,) Thickness radii. Default ``np.linspace(0.2, 2, 6)``. angles and radii define the total thickness options S0 : double, optional Maximum simulated signal. Default 100. snr : float, optional The signal to noise ratio set to apply Rician noise to the data. Default is to not add noise at all. Returns ------- data : array, shape (datashape) See Also -------- add_noise Examples --------- >>> def f(t): ... x = np.sin(t) ... y = np.cos(t) ... z = np.linspace(-1, 1, len(x)) ... return x, y, z >>> data = orbital_phantom(func=f) """ if gtab is None: fimg, fbvals, fbvecs = get_fnames('small_64D') gtab = gradient_table(fbvals, fbvecs) if func is None: x = np.sin(t) y = np.cos(t) z = np.zeros(t.shape) else: x, y, z = func(t) dx = np.diff(x) dy = np.diff(y) dz = np.diff(z) x = scale[0] * x + origin[0] y = scale[1] * y + origin[1] z = scale[2] * z + origin[2] bx = np.zeros(len(angles)) by = np.sin(angles) bz = np.cos(angles) # The entire volume is considered to be inside the brain. # Voxels without a fiber crossing through them are taken # to be isotropic with signal = S0. vol = np.zeros(datashape) + S0 for i in range(len(dx)): evecs, R = diff2eigenvectors(dx[i], dy[i], dz[i]) S = single_tensor(gtab, S0, evals, evecs, snr=None) vol[int(x[i]), int(y[i]), int(z[i]), :] += S for r in radii: for j in range(len(angles)): rb = np.dot(R, np.array([bx[j], by[j], bz[j]])) ix = int(x[i] + r * rb[0]) iy = int(y[i] + r * rb[1]) iz = int(z[i] + r * rb[2]) vol[ix, iy, iz] = vol[ix, iy, iz] + S vol = vol / np.max(vol, axis=-1)[..., np.newaxis] vol *= S0 if snr is not None: vol = add_noise(vol, snr, S0=S0, noise_type='rician') return vol
def test_csdeconv(): SNR = 100 S0 = 1 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric362') odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) assert_equal(csd_fit.shm_coeff[0] > 0, True) fodf = csd_fit.odf(sphere) directions, _, _ = peak_directions(odf_gt, sphere) directions2, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions, directions2) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) assert_equal(directions2.shape[0], 2) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=10) assert_equal(len(w) > 0, True) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) assert_equal(len(w) > 0, False) mevecs = [] for s in sticks: mevecs += [all_tensor_evecs(s).T] S2 = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) big_S = np.zeros((10, 10, 10, len(S2))) big_S[:] = S2 aresponse, aratio = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) assert_almost_equal(aresponse[1], 100) assert_almost_equal(aratio, response[0][1]/response[0][0]) aresponse2, aratio2 = auto_response(gtab, big_S, roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0])