def test_sf_to_sh(): # Subdividing a hemi_icosahedron twice produces 81 unique points, which # is more than enough to fit a order 8 (45 coefficients) spherical harmonic sphere = hemi_icosahedron.subdivide(2) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]])] odf = multi_tensor_odf(sphere.vertices, [0.5, 0.5], mevals, mevecs) # 1D case with the 3 bases functions odf_sh = sf_to_sh(odf, sphere, 8) odf2 = sh_to_sf(odf_sh, sphere, 8) assert_array_almost_equal(odf, odf2, 2) odf_sh = sf_to_sh(odf, sphere, 8, "mrtrix") odf2 = sh_to_sf(odf_sh, sphere, 8, "mrtrix") assert_array_almost_equal(odf, odf2, 2) odf_sh = sf_to_sh(odf, sphere, 8, "fibernav") odf2 = sh_to_sf(odf_sh, sphere, 8, "fibernav") assert_array_almost_equal(odf, odf2, 2) # 2D case odf2d = np.vstack((odf2, odf)) odf2d_sh = sf_to_sh(odf2d, sphere, 8) odf2d_sf = sh_to_sf(odf2d_sh, sphere, 8) assert_array_almost_equal(odf2d, odf2d_sf, 2)
def test_single_voxel_fit(self): signal, gtab, expected = make_fake_signal() sphere = hemi_icosahedron.subdivide(4) model = self.model(gtab, sh_order=4, min_signal=1e-5, assume_normed=True) fit = model.fit(signal) odf = fit.odf(sphere) assert_equal(odf.shape, sphere.phi.shape) directions, _, _ = peak_directions(odf, sphere) # Check the same number of directions n = len(expected) assert_equal(len(directions), n) # Check directions are unit vectors cos_similarity = (directions * directions).sum(-1) assert_array_almost_equal(cos_similarity, np.ones(n)) # Check the directions == expected or -expected cos_similarity = (directions * expected).sum(-1) assert_array_almost_equal(abs(cos_similarity), np.ones(n)) # Test normalize data model = self.model(gtab, sh_order=4, min_signal=1e-5, assume_normed=False) fit = model.fit(signal * 5) odf_with_norm = fit.odf(sphere) assert_array_almost_equal(odf, odf_with_norm)
def test_hemisphere_find_closest(): hemisphere1 = hemi_icosahedron.subdivide(4) for ii in range(hemisphere1.vertices.shape[0]): nt.assert_equal(hemisphere1.find_closest(hemisphere1.vertices[ii]), ii) nt.assert_equal(hemisphere1.find_closest(-hemisphere1.vertices[ii]), ii) nt.assert_equal(hemisphere1.find_closest(hemisphere1.vertices[ii] * 2), ii)
def test_gfa(self): signal, gtab, expected = make_fake_signal() signal = np.ones((2, 3, 4, 1)) * signal sphere = hemi_icosahedron.subdivide(3) model = self.model(gtab, 6, min_signal=1e-5) fit = model.fit(signal) gfa_shm = fit.gfa gfa_odf = odf.gfa(fit.odf(sphere)) assert_array_almost_equal(gfa_shm, gfa_odf, 3)
def test_real_sph_harm_fibernav(): # This test should do for now # The mrtrix basis should be the same as re-ordering and re-scaling the # fibernav basis new_order = [0, 5, 4, 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, 7, 6] sphere = hemi_icosahedron.subdivide(2) basis, m, n = real_sph_harm_mrtrix(4, sphere.theta, sphere.phi) expected = basis[:, new_order] expected *= np.where(m == 0, 1., np.sqrt(2)) fibernav_basis, m, n = real_sph_harm_fibernav(4, sphere.theta, sphere.phi) assert_array_almost_equal(fibernav_basis, expected)
def test_real_sym_sh_basis(): # This test should do for now # The tournier07 basis should be the same as re-ordering and re-scaling the # descoteaux07 basis new_order = [0, 5, 4, 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, 7, 6] sphere = hemi_icosahedron.subdivide(2) basis, m, n = real_sym_sh_mrtrix(4, sphere.theta, sphere.phi) expected = basis[:, new_order] expected *= np.where(m == 0, 1., np.sqrt(2)) descoteaux07_basis, m, n = real_sym_sh_basis(4, sphere.theta, sphere.phi) assert_array_almost_equal(descoteaux07_basis, expected)
def test_gfa(self): signal, gtab, expected = make_fake_signal() signal = np.ones((2, 3, 4, 1)) * signal sphere = hemi_icosahedron.subdivide(3) model = self.model(gtab, 6, min_signal=1e-5) fit = model.fit(signal) gfa_shm = fit.gfa gfa_odf = odf.gfa(fit.odf(sphere)) assert_array_almost_equal(gfa_shm, gfa_odf, 3) # gfa should be 0 if all coefficients are 0 (masked areas) mask = np.zeros(signal.shape[:-1]) fit = model.fit(signal, mask) assert_array_equal(fit.gfa, 0)
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 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_sf_to_sh(): # Subdividing a hemi_icosahedron twice produces 81 unique points, which # is more than enough to fit a order 8 (45 coefficients) spherical harmonic sphere = hemi_icosahedron.subdivide(2) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (90, 0)] odf = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) # 1D case with the 3 bases functions odf_sh = sf_to_sh(odf, sphere, 8) odf2 = sh_to_sf(odf_sh, sphere, 8) assert_array_almost_equal(odf, odf2, 2) odf_sh = sf_to_sh(odf, sphere, 8, "tournier07") odf2 = sh_to_sf(odf_sh, sphere, 8, "tournier07") assert_array_almost_equal(odf, odf2, 2) # Test the basis naming deprecation with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", DeprecationWarning) odf_sh_mrtrix = sf_to_sh(odf, sphere, 8, "mrtrix") odf2_mrtrix = sh_to_sf(odf_sh_mrtrix, sphere, 8, "mrtrix") assert_array_almost_equal(odf, odf2_mrtrix, 2) assert len(w) != 0 assert issubclass(w[-1].category, DeprecationWarning) warnings.simplefilter("default", DeprecationWarning) odf_sh = sf_to_sh(odf, sphere, 8, "descoteaux07") odf2 = sh_to_sf(odf_sh, sphere, 8, "descoteaux07") assert_array_almost_equal(odf, odf2, 2) # Test the basis naming deprecation with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", DeprecationWarning) odf_sh_fibernav = sf_to_sh(odf, sphere, 8, "fibernav") odf2_fibernav = sh_to_sf(odf_sh_fibernav, sphere, 8, "fibernav") assert_array_almost_equal(odf, odf2_fibernav, 2) assert len(w) != 0 assert issubclass(w[-1].category, DeprecationWarning) warnings.simplefilter("default", DeprecationWarning) # 2D case odf2d = np.vstack((odf2, odf)) odf2d_sh = sf_to_sh(odf2d, sphere, 8) odf2d_sf = sh_to_sf(odf2d_sh, sphere, 8) assert_array_almost_equal(odf2d, odf2d_sf, 2)
def test_sf_to_sh(): # Subdividing a hemi_icosahedron twice produces 81 unique points, which # is more than enough to fit a order 8 (45 coefficients) spherical harmonic hemisphere = hemi_icosahedron.subdivide(2) mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]]) angles = [(0, 0), (60, 0)] odf = multi_tensor_odf(hemisphere.vertices, mevals, angles, [50, 50]) # 1D case with the 2 symmetric bases functions odf_sh = sf_to_sh(odf, hemisphere, 8, "tournier07") odf_reconst = sh_to_sf(odf_sh, hemisphere, 8, "tournier07") assert_array_almost_equal(odf, odf_reconst, 2) odf_sh = sf_to_sh(odf, hemisphere, 8, "descoteaux07") odf_reconst = sh_to_sf(odf_sh, hemisphere, 8, "descoteaux07") assert_array_almost_equal(odf, odf_reconst, 2) # We now create an asymmetric signal # to try out our full SH basis mevals = np.array([[0.0015, 0.0003, 0.0003]]) angles = [(0, 0)] odf2 = multi_tensor_odf(hemisphere.vertices, mevals, angles, [100]) # We simulate our asymmetric signal by using a different ODF # per hemisphere. The sphere used is a concatenation of the # vertices of our hemisphere, for a total of 162 vertices. sphere = Sphere(xyz=np.vstack((hemisphere.vertices, -hemisphere.vertices))) asym_odf = np.append(odf, odf2) # Try out full bases with order 10 (121 coefficients) odf_sh = sf_to_sh(asym_odf, sphere, 10, "tournier07_full") odf_reconst = sh_to_sf(odf_sh, sphere, 10, "tournier07_full") assert_array_almost_equal(odf_reconst, asym_odf, 2) odf_sh = sf_to_sh(asym_odf, sphere, 10, "descoteaux07_full") odf_reconst = sh_to_sf(odf_sh, sphere, 10, "descoteaux07_full") assert_array_almost_equal(odf_reconst, asym_odf, 2) # An invalid basis name should raise an error assert_raises(ValueError, sh_to_sf, odf, hemisphere, basis_type="") assert_raises(ValueError, sf_to_sh, odf_sh, hemisphere, basis_type="") # 2D case odf2d = np.vstack((odf, odf)) odf2d_sh = sf_to_sh(odf2d, hemisphere, 8) odf2d_sf = sh_to_sf(odf2d_sh, hemisphere, 8) assert_array_almost_equal(odf2d, odf2d_sf, 2)
def test_convert_sh_to_legacy(): hemisphere = hemi_icosahedron.subdivide(2) mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]]) angles = [(0, 0), (60, 0)] odf = multi_tensor_odf(hemisphere.vertices, mevals, angles, [50, 50]) sh_coeffs = sf_to_sh(odf, hemisphere, 8, legacy=False) converted_coeffs = convert_sh_to_legacy(sh_coeffs, 'descoteaux07') expected_coeffs = sf_to_sh(odf, hemisphere, 8, legacy=True) assert_array_almost_equal(converted_coeffs, expected_coeffs, 2) sh_coeffs = sf_to_sh(odf, hemisphere, 8, basis_type='tournier07', legacy=False) converted_coeffs = convert_sh_to_legacy(sh_coeffs, 'tournier07') expected_coeffs = sf_to_sh(odf, hemisphere, 8, basis_type='tournier07', legacy=True) assert_array_almost_equal(converted_coeffs, expected_coeffs, 2) # 2D case odfs = np.array([odf, odf]) sh_coeffs = sf_to_sh(odfs, hemisphere, 8, basis_type='tournier07', full_basis=True, legacy=False) converted_coeffs = convert_sh_to_legacy(sh_coeffs, 'tournier07', full_basis=True) expected_coeffs = sf_to_sh(odfs, hemisphere, 8, basis_type='tournier07', legacy=True, full_basis=True) assert_array_almost_equal(converted_coeffs, expected_coeffs, 2) assert_raises(ValueError, convert_sh_to_legacy, sh_coeffs, '', True)
def test_hat_and_lcr(): hemi = hemi_icosahedron.subdivide(3) m, n = sph_harm_ind_list(8) B = real_sph_harm(m, n, hemi.theta[:, None], hemi.phi[:, None]) H = hat(B) B_hat = np.dot(H, B) assert_array_almost_equal(B, B_hat) R = lcr_matrix(H) d = np.arange(len(hemi.theta)) r = d - np.dot(H, d) lev = np.sqrt(1 - H.diagonal()) r /= lev r -= r.mean() r2 = np.dot(R, d) assert_array_almost_equal(r, r2) r3 = np.dot(d, R.T) assert_array_almost_equal(r, r3)
def test_real_full_sh_basis(): vertices = hemi_icosahedron.subdivide(2).vertices mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]]) angles = [(0, 0), (60, 0)] odf = multi_tensor_odf(vertices, mevals, angles, [50, 50]) mevals = np.array([[0.0015, 0.0003, 0.0003]]) angles = [(0, 0)] odf2 = multi_tensor_odf(-vertices, mevals, angles, [100]) sphere = Sphere(xyz=np.vstack((vertices, -vertices))) # Asymmetric spherical function with 162 coefficients sf = np.append(odf, odf2) # In order for our approximation to be precise enough, we # will use a SH basis of orders up to 10 (121 coefficients) B, m, n = real_full_sh_basis(10, sphere.theta, sphere.phi) invB = smooth_pinv(B, L=np.zeros_like(n)) sh_coefs = np.dot(invB, sf) sf_approx = np.dot(B, sh_coefs) assert_array_almost_equal(sf_approx, sf, 2)
def test_convert_sh_to_full_basis(): hemisphere = hemi_icosahedron.subdivide(2) mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]]) angles = [(0, 0), (60, 0)] odf = multi_tensor_odf(hemisphere.vertices, mevals, angles, [50, 50]) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) sh_coeffs = sf_to_sh(odf, hemisphere, 8) full_sh_coeffs = convert_sh_to_full_basis(sh_coeffs) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) odf_reconst = sh_to_sf(full_sh_coeffs, hemisphere, 8, full_basis=True) assert_array_almost_equal(odf, odf_reconst, 2)
def test_smooth_pinv(): hemi = hemi_icosahedron.subdivide(2) m, n = sph_harm_ind_list(4) B = real_sph_harm(m, n, hemi.theta[:, None], hemi.phi[:, None]) L = np.zeros(len(m)) C = smooth_pinv(B, L) D = np.dot(npl.inv(np.dot(B.T, B)), B.T) assert_array_almost_equal(C, D) L = n * (n + 1) * .05 C = smooth_pinv(B, L) L = np.diag(L) D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T) assert_array_almost_equal(C, D) L = np.arange(len(n)) * .05 C = smooth_pinv(B, L) L = np.diag(L) D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T) assert_array_almost_equal(C, D)
def test_real_sh_descoteaux1(): # This test should do for now # The tournier07 basis should be the same as re-ordering and re-scaling the # descoteaux07 basis new_order = [0, 5, 4, 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, 7, 6] sphere = hemi_icosahedron.subdivide(2) with warnings.catch_warnings(): warnings.filterwarnings("ignore") basis, m, n = real_sym_sh_mrtrix(4, sphere.theta, sphere.phi) expected = basis[:, new_order] expected *= np.where(m == 0, 1., np.sqrt(2)) with warnings.catch_warnings(record=True) as w: descoteaux07_basis, m, n = real_sh_descoteaux(4, sphere.theta, sphere.phi) npt.assert_equal(len(w), 1) npt.assert_(issubclass(w[0].category, PendingDeprecationWarning)) npt.assert_(descoteaux07_legacy_msg in str(w[0].message)) assert_array_almost_equal(descoteaux07_basis, expected)
def test_convert_sh_to_legacy(): hemisphere = hemi_icosahedron.subdivide(2) mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]]) angles = [(0, 0), (60, 0)] odf = multi_tensor_odf(hemisphere.vertices, mevals, angles, [50, 50]) sh_coeffs = sf_to_sh(odf, hemisphere, 8, legacy=False) converted_coeffs = convert_sh_to_legacy(sh_coeffs, 'descoteaux07') with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) expected_coeffs = sf_to_sh(odf, hemisphere, 8, legacy=True) assert_array_almost_equal(converted_coeffs, expected_coeffs, 2) sh_coeffs = sf_to_sh(odf, hemisphere, 8, basis_type='tournier07', legacy=False) converted_coeffs = convert_sh_to_legacy(sh_coeffs, 'tournier07') with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=tournier07_legacy_msg, category=PendingDeprecationWarning) expected_coeffs = sf_to_sh(odf, hemisphere, 8, basis_type='tournier07', legacy=True) assert_array_almost_equal(converted_coeffs, expected_coeffs, 2) # 2D case odfs = np.array([odf, odf]) sh_coeffs = sf_to_sh(odfs, hemisphere, 8, basis_type='tournier07', full_basis=True, legacy=False) converted_coeffs = convert_sh_to_legacy(sh_coeffs, 'tournier07', full_basis=True) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=tournier07_legacy_msg, category=PendingDeprecationWarning) expected_coeffs = sf_to_sh(odfs, hemisphere, 8, basis_type='tournier07', legacy=True, full_basis=True) assert_array_almost_equal(converted_coeffs, expected_coeffs, 2) assert_raises(ValueError, convert_sh_to_legacy, sh_coeffs, '', True)