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_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, "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_r2_term_odf_sharp(): SNR = None S0 = 1 angle = 75 _, fbvals, fbvecs = get_data('small_64D') #get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) sphere = get_sphere('symmetric724') gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) S, sticks = multi_tensor(gtab, mevals, S0, angles=[(0, 0), (angle, 0)], fractions=[50, 50], snr=SNR) mevecs = [all_tensor_evecs(sticks[0]).T, all_tensor_evecs(sticks[1]).T] odf_gt = multi_tensor_odf(sphere.vertices, [0.5, 0.5], mevals, mevecs) odfs_sh = sf_to_sh(odf_gt, sphere, sh_order=8, basis_type=None) fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=0.1, r2_term=True) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions_gt, _, _ = peak_directions(odf_gt, sphere) directions, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions_gt, directions) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2)
def test_normalization(): """ Test the normalization routine applied after a convolution""" # create kernel D33 = 1.0 D44 = 0.04 t = 1 num_orientations = 5 k = EnhancementKernel(D33, D44, t, orientations=num_orientations, force_recompute=True) # create a constant dataset numorientations = k.get_orientations().shape[0] spike = np.ones((7, 7, 7, numorientations), dtype=np.float64) # convert dataset to SH spike_sh = sf_to_sh(spike, k.get_sphere(), sh_order=8) # convolve kernel with delta spike and apply normalization csd_enh = convolve(spike_sh, k, sh_order=8, test_mode=True, normalize=True) # convert dataset to DSF csd_enh_dsf = sh_to_sf(csd_enh, k.get_sphere(), sh_order=8, basis_type=None) # test if the normalization is performed correctly npt.assert_almost_equal(np.amax(csd_enh_dsf), np.amax(spike))
def test_odf_sh_to_sharp(): SNR = None S0 = 1 _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) S, _ = multi_tensor(gtab, mevals, S0, angles=[(10, 0), (100, 0)], fractions=[50, 50], snr=SNR) sphere = default_sphere with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) qb = QballModel(gtab, sh_order=8, assume_normed=True) qbfit = qb.fit(S) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) odf_gt = qbfit.odf(sphere) Z = np.linalg.norm(odf_gt) odfs_gt = np.zeros((3, 1, 1, odf_gt.shape[0])) odfs_gt[:, :, :] = odf_gt[:] with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) odfs_sh = sf_to_sh(odfs_gt, sphere, sh_order=8, basis_type=None) odfs_sh /= Z with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=0.1) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions2, _, _ = peak_directions(fodf[0, 0, 0], sphere) assert_equal(directions2.shape[0], 2)
def create_odf_slicer(sh_fodf, mask, sphere, nb_subdivide, sh_order, sh_basis, full_basis, orientation, scale, radial_scale, norm, colormap): """ Create a ODF slicer actor displaying a fODF slice. The input volume is a 3-dimensional grid containing the SH coefficients of the fODF for each voxel at each voxel, with the grid dimension having a size of 1 along the axis corresponding to the selected orientation. """ # Subdivide the spheres if nb_subdivide is provided if nb_subdivide is not None: sphere = sphere.subdivide(nb_subdivide) # Convert SH coefficients to SF coefficients fodf = sh_to_sf(sh_fodf, sphere, sh_order, sh_basis, full_basis=full_basis) # Get mask if supplied, otherwise create a mask discarding empty voxels if mask is None: mask = np.linalg.norm(fodf, axis=-1) > 0. odf_actor = actor.odf_slicer(fodf, mask=mask, norm=norm, radial_scale=radial_scale, sphere=sphere, colormap=colormap, scale=scale) set_display_extent(odf_actor, orientation, fodf.shape) return odf_actor
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_mapmri_odf(radial_order=6): gtab = get_gtab_taiwan_dsi() # load repulsion 724 sphere sphere = default_sphere # load icosahedron sphere l1, l2, l3 = [0.0015, 0.0003, 0.0003] data, golden_directions = generate_signal_crossing(gtab, l1, l2, l3, angle2=90) mapmod = MapmriModel(gtab, radial_order=radial_order, laplacian_regularization=True, laplacian_weighting=0.01) # repulsion724 sphere2 = create_unit_sphere(5) mapfit = mapmod.fit(data) odf = mapfit.odf(sphere) directions, _, _ = peak_directions(odf, sphere, .35, 25) assert_equal(len(directions), 2) assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1) # 5 subdivisions odf = mapfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) assert_equal(len(directions), 2) assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1) sb_dummies = sticks_and_ball_dummies(gtab) for sbd in sb_dummies: data, golden_directions = sb_dummies[sbd] asmfit = mapmod.fit(data) odf = asmfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) if len(directions) <= 3: assert_equal(len(directions), len(golden_directions)) if len(directions) > 3: assert_equal(gfa(odf) < 0.1, True) # for the isotropic implementation check if the odf spherical harmonics # actually represent the discrete sphere function. mapmod = MapmriModel(gtab, radial_order=radial_order, laplacian_regularization=True, laplacian_weighting=0.01, anisotropic_scaling=False) mapfit = mapmod.fit(data) odf = mapfit.odf(sphere) odf_sh = mapfit.odf_sh() odf_from_sh = sh_to_sf(odf_sh, sphere, radial_order, basis_type=None) assert_almost_equal(odf, odf_from_sh, 10)
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]) sh_coeffs = sf_to_sh(odf, hemisphere, 8) full_sh_coeffs = convert_sh_to_full_basis(sh_coeffs) odf_reconst = sh_to_sf(full_sh_coeffs, hemisphere, 8, full_basis=True) assert_array_almost_equal(odf, odf_reconst, 2)
def test_r2_term_odf_sharp(): SNR = None S0 = 1 angle = 45 # 45 degrees is a very tight angle to disentangle _, fbvals, fbvecs = get_data('small_64D') # get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) sphere = get_sphere('symmetric724') gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (angle, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) odfs_sh = sf_to_sh(odf_gt, sphere, sh_order=8, basis_type=None) fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=0.1, r2_term=True) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions_gt, _, _ = peak_directions(odf_gt, sphere) directions, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions_gt, directions) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) # This should pass as well sdt_model = ConstrainedSDTModel(gtab, ratio=3 / 15., sh_order=8) sdt_fit = sdt_model.fit(S) fodf = sdt_fit.odf(sphere) directions_gt, _, _ = peak_directions(odf_gt, sphere) directions, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions_gt, directions) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2)
def test_shore_odf(): gtab = get_isbi2013_2shell_gtab() # load repulsion 724 sphere sphere = default_sphere # load icosahedron sphere sphere2 = create_unit_sphere(5) data, golden_directions = sticks_and_ball(gtab, d=0.0015, S0=100, angles=[(0, 0), (90, 0)], fractions=[50, 50], snr=None) asm = ShoreModel(gtab, radial_order=6, zeta=700, lambdaN=1e-8, lambdaL=1e-8) # repulsion724 asmfit = asm.fit(data) odf = asmfit.odf(sphere) odf_sh = asmfit.odf_sh() odf_from_sh = sh_to_sf(odf_sh, sphere, 6, basis_type=None, legacy=True) npt.assert_almost_equal(odf, odf_from_sh, 10) expected_phi = shore_matrix(radial_order=6, zeta=700, gtab=gtab) npt.assert_array_almost_equal(np.dot(expected_phi, asmfit.shore_coeff), asmfit.fitted_signal()) directions, _, _ = peak_directions(odf, sphere, .35, 25) npt.assert_equal(len(directions), 2) npt.assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1) # 5 subdivisions odf = asmfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) npt.assert_equal(len(directions), 2) npt.assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1) sb_dummies = sticks_and_ball_dummies(gtab) for sbd in sb_dummies: data, golden_directions = sb_dummies[sbd] asmfit = asm.fit(data) odf = asmfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) if len(directions) <= 3: npt.assert_equal(len(directions), len(golden_directions)) if len(directions) > 3: npt.assert_equal(gfa(odf) < 0.1, True)
def test_mapmri_odf(radial_order=6): gtab = get_gtab_taiwan_dsi() # load symmetric 724 sphere sphere = get_sphere('symmetric724') # load icosahedron sphere l1, l2, l3 = [0.0015, 0.0003, 0.0003] data, golden_directions = generate_signal_crossing(gtab, l1, l2, l3, angle2=90) mapmod = MapmriModel(gtab, radial_order=radial_order, laplacian_regularization=True, laplacian_weighting=0.01) # symmetric724 sphere2 = create_unit_sphere(5) mapfit = mapmod.fit(data) odf = mapfit.odf(sphere) directions, _, _ = peak_directions(odf, sphere, .35, 25) assert_equal(len(directions), 2) assert_almost_equal( angular_similarity(directions, golden_directions), 2, 1) # 5 subdivisions odf = mapfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) assert_equal(len(directions), 2) assert_almost_equal( angular_similarity(directions, golden_directions), 2, 1) sb_dummies = sticks_and_ball_dummies(gtab) for sbd in sb_dummies: data, golden_directions = sb_dummies[sbd] asmfit = mapmod.fit(data) odf = asmfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) if len(directions) <= 3: assert_equal(len(directions), len(golden_directions)) if len(directions) > 3: assert_equal(gfa(odf) < 0.1, True) # for the isotropic implementation check if the odf spherical harmonics # actually represent the discrete sphere function. mapmod = MapmriModel(gtab, radial_order=radial_order, laplacian_regularization=True, laplacian_weighting=0.01, anisotropic_scaling=False) mapfit = mapmod.fit(data) odf = mapfit.odf(sphere) odf_sh = mapfit.odf_sh() odf_from_sh = sh_to_sf(odf_sh, sphere, radial_order, basis_type=None) assert_almost_equal(odf, odf_from_sh, 10)
def test_odf_sh_to_sharp(): 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])) S, sticks = multi_tensor(gtab, mevals, S0, angles=[(10, 0), (100, 0)], fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric724') qb = QballModel(gtab, sh_order=8, assume_normed=True) qbfit = qb.fit(S) odf_gt = qbfit.odf(sphere) Z = np.linalg.norm(odf_gt) odfs_gt = np.zeros((3, 1, 1, odf_gt.shape[0])) odfs_gt[:, :, :] = odf_gt[:] odfs_sh = sf_to_sh(odfs_gt, sphere, sh_order=8, basis_type=None) odfs_sh /= Z fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=1.) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions2, _, _ = peak_directions(fodf[0, 0, 0], sphere) assert_equal(directions2.shape[0], 2)
def main(): odf_file = sys.argv[1] bvec_file = sys.argv[2] basis = sys.argv[3] odf = nib.load(odf_file) odf_sh = odf.get_fdata() bvec = np.loadtxt(bvec_file) bvec = bvec[1:, :] sph_gtab = Sphere(xyz=np.vstack(bvec)) print(odf_sh.shape) odf_sf = sh_to_sf(odf_sh, sph_gtab, basis_type=basis, sh_order=8) visu_odf(bvec, odf_sf)
def test_shore_odf(): gtab = get_isbi2013_2shell_gtab() # load symmetric 724 sphere sphere = get_sphere('symmetric724') # load icosahedron sphere sphere2 = create_unit_sphere(5) data, golden_directions = SticksAndBall(gtab, d=0.0015, S0=100, angles=[(0, 0), (90, 0)], fractions=[50, 50], snr=None) asm = ShoreModel(gtab, radial_order=6, zeta=700, lambdaN=1e-8, lambdaL=1e-8) # symmetric724 asmfit = asm.fit(data) odf = asmfit.odf(sphere) odf_sh = asmfit.odf_sh() odf_from_sh = sh_to_sf(odf_sh, sphere, 6, basis_type=None) assert_almost_equal(odf, odf_from_sh, 10) directions, _, _ = peak_directions(odf, sphere, .35, 25) assert_equal(len(directions), 2) assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1) # 5 subdivisions odf = asmfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) assert_equal(len(directions), 2) assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1) sb_dummies = sticks_and_ball_dummies(gtab) for sbd in sb_dummies: data, golden_directions = sb_dummies[sbd] asmfit = asm.fit(data) odf = asmfit.odf(sphere2) directions, _, _ = peak_directions(odf, sphere2, .35, 25) if len(directions) <= 3: assert_equal(len(directions), len(golden_directions)) if len(directions) > 3: assert_equal(gfa(odf) < 0.1, True)
def test_shore_odf(): gtab = get_isbi2013_2shell_gtab() # load symmetric 724 sphere sphere = get_sphere('symmetric724') # load icosahedron sphere sphere2 = create_unit_sphere(5) data, golden_directions = SticksAndBall(gtab, d=0.0015, S0=100, angles=[(0, 0), (90, 0)], fractions=[50, 50], snr=None) asm = ShoreModel(gtab, radial_order=6, zeta=700, lambdaN=1e-8, lambdaL=1e-8) # symmetric724 asmfit = asm.fit(data) odf = asmfit.odf(sphere) odf_sh = asmfit.odf_sh() odf_from_sh = sh_to_sf(odf_sh, sphere, 6, basis_type=None) assert_almost_equal(odf, odf_from_sh, 10) directions, _ , _ = peak_directions(odf, sphere, .35, 25) assert_equal(len(directions), 2) assert_almost_equal( angular_similarity(directions, golden_directions), 2, 1) # 5 subdivisions odf = asmfit.odf(sphere2) directions, _ , _ = peak_directions(odf, sphere2, .35, 25) assert_equal(len(directions), 2) assert_almost_equal( angular_similarity(directions, golden_directions), 2, 1) sb_dummies = sticks_and_ball_dummies(gtab) for sbd in sb_dummies: data, golden_directions = sb_dummies[sbd] asmfit = asm.fit(data) odf = asmfit.odf(sphere2) directions, _ , _ = peak_directions(odf, sphere2, .35, 25) if len(directions) <= 3: assert_equal(len(directions), len(golden_directions)) if len(directions) > 3: assert_equal(gfa(odf) < 0.1, True)
def test_r2_term_odf_sharp(): SNR = None S0 = 1 angle = 45 #45 degrees is a very tight angle to disentangle _, fbvals, fbvecs = get_data('small_64D') #get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) sphere = get_sphere('symmetric724') gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (angle, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) odfs_sh = sf_to_sh(odf_gt, sphere, sh_order=8, basis_type=None) fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=0.1, r2_term=True) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions_gt, _, _ = peak_directions(odf_gt, sphere) directions, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions_gt, directions) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) # This should pass as well sdt_model = ConstrainedSDTModel(gtab, ratio=3/15., sh_order=8) sdt_fit = sdt_model.fit(S) fodf = sdt_fit.odf(sphere) directions_gt, _, _ = peak_directions(odf_gt, sphere) directions, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions_gt, directions) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2)
def test_spherical_convolution_watson_sh(sh_order=4): sphere = get_sphere('symmetric724') n = sphere.vertices bval = np.tile(1e9, len(n)) scheme = acquisition_scheme_from_bvalues(bval, n, delta, Delta) indices_sphere_orientations = np.arange(sphere.vertices.shape[0]) np.random.shuffle(indices_sphere_orientations) mu_index = indices_sphere_orientations[0] mu_watson = sphere.vertices[mu_index] mu_watson_sphere = utils.cart2sphere(mu_watson)[1:] watson = distributions.SD1Watson(mu=mu_watson_sphere, odi=.3) f_sf = watson(n=sphere.vertices) f_sh = sf_to_sh(f_sf, sphere, sh_order) lambda_par = 2e-9 stick = cylinder_models.C1Stick(mu=[0, 0], lambda_par=lambda_par) k_sf = stick(scheme) sh_matrix, m, n = real_sym_sh_mrtrix(sh_order, sphere.theta, sphere.phi) sh_matrix_inv = np.linalg.pinv(sh_matrix) k_sh = np.dot(sh_matrix_inv, k_sf) k_rh = k_sh[m == 0] fk_convolved_sh = sh_convolution(f_sh, k_rh) fk_convolved_sf = sh_to_sf(fk_convolved_sh, sphere, sh_order) # assert if spherical mean is the same between kernel and convolved kernel assert_almost_equal(abs(np.mean(k_sf) - np.mean(fk_convolved_sf)), 0., 2) # assert if the lowest signal attenuation (E(b,n)) is orientation along # the orientation of the watson distribution. min_position = np.argmin(fk_convolved_sf) if min_position == mu_index: assert_equal(min_position, mu_index) else: # then it's the opposite direction sphere_positions = np.arange(sphere.vertices.shape[0]) opposite_index = np.all( np.round(sphere.vertices - mu_watson, 2) == 0, axis=1 ) min_position_opposite = sphere_positions[opposite_index] assert_equal(min_position_opposite, mu_index)
def show_odf_sample(filename): odf_sh = nib.load(filename).get_data() from dipy.data import get_sphere sphere = get_sphere('symmetric724') odf = sh_to_sf(odf_sh, sphere, 8, 'mrtrix') from dipy.viz import fvtk r = fvtk.ren() #odf = odf[:, :, 25] #fvtk.add(r, fvtk.sphere_funcs(odf[:, :, None], sphere, norm=True)) odf = odf[:, 22, :] #odf = odf[14: 23, 22, 34: 43] #odf = odf[14:24, 22, 23:33] fvtk.add(r, fvtk.sphere_funcs(odf[:, None, :], sphere, norm=True)) fvtk.show(r)
def test_odf_sh_to_sharp(): SNR = None 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])) S, sticks = multi_tensor(gtab, mevals, S0, angles=[(10, 0), (100, 0)], fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric724') qb = QballModel(gtab, sh_order=8, assume_normed=True) qbfit = qb.fit(S) odf_gt = qbfit.odf(sphere) Z = np.linalg.norm(odf_gt) odfs_gt = np.zeros((3, 1, 1, odf_gt.shape[0])) odfs_gt[:,:,:] = odf_gt[:] odfs_sh = sf_to_sh(odfs_gt, sphere, sh_order=8, basis_type=None) odfs_sh /= Z fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=0.1) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions2, _, _ = peak_directions(fodf[0, 0, 0], sphere) assert_equal(directions2.shape[0], 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 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_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)
#mask = data[..., 0] > 50 order = 4 csamodel = CsaOdfModel(gtab, order, smooth=0.006) print 'Computing the CSA odf...' csafit = csamodel.fit(data) coeff = csafit._shm_coef # dipy-dev compatible #GFA = csafit.gfa #nib.save(nib.Nifti1Image(GFA.astype('float32'), affine), 'gfa_csa.nii.gz') nib.save(nib.Nifti1Image(coeff.astype('float32'), affine), 'csa_odf_sh.nii.gz') sphere = get_sphere('symmetric724') odfs = sh_to_sf(coeff[20:50,55:85, 38:39], sphere, order) if vizu : from dipy.viz import fvtk r = fvtk.ren() fvtk.add(r, fvtk.sphere_funcs(odfs, sphere, colormap='jet')) fvtk.show(r) fvtk.clear(r) qballmodel = QballModel(gtab, order, smooth=0.006) print 'Computing the QBALL odf...' qballfit = qballmodel.fit(data) coeff = qballfit._shm_coef #GFA = qballfit.gfa # dipy 0.6 compatible
Visualize the kernel """ from dipy.viz import fvtk from dipy.data import get_sphere from dipy.reconst.shm import sf_to_sh, sh_to_sf ren = fvtk.ren() # convolve kernel with delta spike spike = np.zeros((7, 7, 7, k.get_orientations().shape[0]), dtype=np.float64) spike[3, 3, 3, 0] = 1 spike_shm_conv = convolve(sf_to_sh(spike, k.get_sphere(), sh_order=8), k, sh_order=8, test_mode=True) sphere = get_sphere('symmetric724') spike_sf_conv = sh_to_sf(spike_shm_conv, sphere, sh_order=8) model_kernel = fvtk.sphere_funcs((spike_sf_conv * 6)[3,:,:,:], sphere, norm=False, radial_scale=True) fvtk.add(ren, model_kernel) fvtk.camera(ren, pos=(30, 0, 0), focal=(0, 0, 0), viewup=(0, 0, 1), verbose=False) fvtk.record(ren, out_path='kernel.png', size=(900, 900)) """ .. figure:: kernel.png :align: center Visualization of the contour enhancement kernel. """
Visualize the kernel """ from dipy.viz import window, actor from dipy.reconst.shm import sf_to_sh, sh_to_sf scene = window.Scene() # convolve kernel with delta spike spike = np.zeros((7, 7, 7, k.get_orientations().shape[0]), dtype=np.float64) spike[3, 3, 3, 0] = 1 spike_shm_conv = convolve(sf_to_sh(spike, k.get_sphere(), sh_order=8), k, sh_order=8, test_mode=True) spike_sf_conv = sh_to_sf(spike_shm_conv, default_sphere, sh_order=8) model_kernel = actor.odf_slicer(spike_sf_conv * 6, sphere=default_sphere, norm=False, scale=0.4) model_kernel.display(x=3) scene.add(model_kernel) scene.set_camera(position=(30, 0, 0), focal_point=(0, 0, 0), view_up=(0, 0, 1)) window.record(scene, out_path='kernel.png', size=(900, 900)) if interactive: window.show(scene) """ .. figure:: kernel.png :align: center Visualization of the contour enhancement kernel.
# Change this value to try other maximum orders sh_order = 8 sh_coeffs = sf_to_sh(odf, sph, sh_order, sh_basis) """ ``sh_coeffs`` is an array containing the SH coefficients multiplying the SH functions of the chosen basis. We can use it as input of ``sh_to_sf`` to reconstruct our original signal. We will now reproject our signal on a high resolution sphere using ``sh_to_sf``. """ from dipy.data import get_sphere from dipy.reconst.shm import sh_to_sf high_res_sph = get_sphere('symmetric724').subdivide(2) reconst = sh_to_sf(sh_coeffs, high_res_sph, sh_order, sh_basis) scene.clear() odf_actor = actor.odf_slicer(reconst[None, None, None, :], sphere=high_res_sph) odf_actor.RotateX(90) scene.add(odf_actor) print('Saving output as symm_reconst.png') window.record(scene, out_path='symm_reconst.png', size=(300, 300)) if interactive: window.show(scene) """ .. figure:: symm_reconst.png :align: center Reconstruction of a symmetric signal on a high resolution sphere using a
def main(): logging.basicConfig(level=logging.INFO) parser = _build_arg_parser() args = parser.parse_args() required = [args.bundle_filename, args.fod_filename, args.mask_filename] assert_inputs_exist(parser, required) out_efod = os.path.join(args.output_dir, '{0}efod.nii.gz'.format(args.output_prefix)) out_priors = os.path.join(args.output_dir, '{0}priors.nii.gz'.format(args.output_prefix)) out_todi_mask = os.path.join( args.output_dir, '{0}todi_mask.nii.gz'.format(args.output_prefix)) out_endpoints_mask = os.path.join( args.output_dir, '{0}endpoints_mask.nii.gz'.format(args.output_prefix)) required = [out_efod, out_priors, out_todi_mask, out_endpoints_mask] assert_outputs_exist(parser, args, required) if args.output_dir and not os.path.isdir(args.output_dir): os.mkdir(args.output_dir) img_sh = nib.load(args.fod_filename) sh_shape = img_sh.shape sh_order = find_order_from_nb_coeff(sh_shape) img_mask = nib.load(args.mask_filename) sft = load_tractogram(args.bundle_filename, args.fod_filename, trk_header_check=True) sft.to_vox() streamlines = sft.streamlines if len(streamlines) < 1: raise ValueError('The input bundle contains no streamline.') # Compute TODI from streamlines with TrackOrientationDensityImaging(img_mask.shape, 'repulsion724') as todi_obj: todi_obj.compute_todi(streamlines, length_weights=True) todi_obj.smooth_todi_dir() todi_obj.smooth_todi_spatial(sigma=args.todi_sigma) # Fancy masking of 1d indices to limit spatial dilation to WM sub_mask_3d = np.logical_and( img_mask.get_data(), todi_obj.reshape_to_3d(todi_obj.get_mask())) sub_mask_1d = sub_mask_3d.flatten()[todi_obj.get_mask()] todi_sf = todi_obj.get_todi()[sub_mask_1d]**2 # The priors should always be between 0 and 1 # A minimum threshold is set to prevent misaligned FOD from disappearing todi_sf /= np.max(todi_sf, axis=-1, keepdims=True) todi_sf[todi_sf < args.sf_threshold] = args.sf_threshold # Memory friendly saving, as soon as possible saving then delete priors_3d = np.zeros(sh_shape) sphere = get_sphere('repulsion724') priors_3d[sub_mask_3d] = sf_to_sh(todi_sf, sphere, sh_order=sh_order, basis_type=args.sh_basis) nib.save(nib.Nifti1Image(priors_3d, img_mask.affine), out_priors) del priors_3d input_sh_3d = img_sh.get_data().astype(np.float) input_sf_1d = sh_to_sf(input_sh_3d[sub_mask_3d], sphere, sh_order=sh_order, basis_type=args.sh_basis) # Creation of the enhanced-FOD (direction-wise multiplication) mult_sf_1d = input_sf_1d * todi_sf del todi_sf input_max_value = np.max(input_sf_1d, axis=-1, keepdims=True) mult_max_value = np.max(mult_sf_1d, axis=-1, keepdims=True) mult_positive_mask = np.squeeze(mult_max_value) > 0.0 mult_sf_1d[mult_positive_mask] = mult_sf_1d[mult_positive_mask] * \ input_max_value[mult_positive_mask] / \ mult_max_value[mult_positive_mask] # Memory friendly saving input_sh_3d[sub_mask_3d] = sf_to_sh(mult_sf_1d, sphere, sh_order=sh_order, basis_type=args.sh_basis) nib.save(nib.Nifti1Image(input_sh_3d, img_mask.affine), out_efod) del input_sh_3d nib.save(nib.Nifti1Image(sub_mask_3d.astype(np.int16), img_mask.affine), out_todi_mask) endpoints_mask = np.zeros(img_mask.shape, dtype=np.int16) for streamline in streamlines: if img_mask.get_data()[tuple(streamline[0].astype(np.int16))]: endpoints_mask[tuple(streamline[0].astype(np.int16))] = 1 endpoints_mask[tuple(streamline[-1].astype(np.int16))] = 1 nib.save(nib.Nifti1Image(endpoints_mask, img_mask.affine), out_endpoints_mask)
def test_r2_term_odf_sharp(): SNR = None S0 = 1 angle = 45 # 45 degrees is a very tight angle to disentangle _, fbvals, fbvecs = get_fnames('small_64D') # get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) sphere = default_sphere gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (angle, 0)] S, _ = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) odfs_sh = sf_to_sh(odf_gt, sphere, sh_order=8, basis_type=None) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=0.1, r2_term=True) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions_gt, _, _ = peak_directions(odf_gt, sphere) directions, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions_gt, directions) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) # This should pass as well with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) sdt_model = ConstrainedSDTModel(gtab, ratio=3 / 15., sh_order=8) sdt_fit = sdt_model.fit(S) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=descoteaux07_legacy_msg, category=PendingDeprecationWarning) fodf = sdt_fit.odf(sphere) directions_gt, _, _ = peak_directions(odf_gt, sphere) directions, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions_gt, directions) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2)