def get_spherical_harmonics_coefficients(dwi, bvals, bvecs, sh_order=8, smooth=0.006, first=False, mean_centering=True): """ Compute coefficients of the spherical harmonics basis. Parameters ----------- dwi : `nibabel.NiftiImage` object Diffusion signal as weighted images (4D). bvals : ndarray shape (N,) B-values used with each direction. bvecs : ndarray shape (N, 3) Directions of the diffusion signal. Directions are assumed to be only on the hemisphere. sh_order : int, optional SH order. Default: 8 smooth : float, optional Lambda-regularization in the SH fit. Default: 0.006. mean_centering : bool If True, signal will have zero mean in each direction for all nonzero voxels Returns ------- sh_coeffs : ndarray of shape (X, Y, Z, #coeffs) Spherical harmonics coefficients at every voxel. The actual number of coeffs depends on `sh_order`. """ bvals = np.asarray(bvals) bvecs = np.asarray(bvecs) dwi_weights = dwi.get_data().astype("float32") # Exract the averaged b0. b0_idx = bvals == 0 b0 = dwi_weights[..., b0_idx].mean(axis=3) # Extract diffusion weights and normalize by the b0. bvecs = bvecs[np.logical_not(b0_idx)] weights = dwi_weights[..., np.logical_not(b0_idx)] weights = normalize_dwi(weights, b0) # Assuming all directions are on the hemisphere. raw_sphere = HemiSphere(xyz=bvecs) # Fit SH to signal sph_harm_basis = sph_harm_lookup.get('mrtrix') Ba, m, n = sph_harm_basis(sh_order, raw_sphere.theta, raw_sphere.phi) L = -n * (n + 1) invB = smooth_pinv(Ba, np.sqrt(smooth) * L) data_sh = np.dot(weights, invB.T) if mean_centering: # Normalization in each direction (zero mean) idx = data_sh.sum(axis=-1).nonzero() means = data_sh[idx].mean(axis=0) data_sh[idx] -= means return data_sh
def displaySphericalHist(odf, pts, minmax=False): # assumes pts and odf are hemisphere fullsphere = HemiSphere(xyz=pts).mirror() fullodf = np.concatenate((odf, odf), axis=0) r = fvtk.ren() if minmax: a = fvtk.sphere_funcs(fullodf - fullodf.min(), fullsphere) else: a = fvtk.sphere_funcs(fullodf, fullsphere) fvtk.add(r, a) fvtk.show(r)
def create_repulsion_sphere(n_points, n_iter): """ Create a sphere using electrostatic repulsion. params: npoints: number of points in the electrostatic repulsion n_iter: number of iterations to optimise energy return: HemiSphere object with n points vertices """ theta = np.pi * np.random.rand(n_points) phi = 2 * np.pi * np.random.rand(n_points) hsph_initial = HemiSphere(theta=theta, phi=phi) hsph_updated, energy = disperse_charges(hsph_initial, iters=n_iter) sph = hsph_updated return sph
def create_symmetric_repulsion_sphere(n_points, n_iter): """ Create a full Sphere object using electrostatic repulsion. params: npoints: number of points in the electrostatic repulsion n_iter: number of iterations to optimise energy return: Sphere object with 2*npoints vertices """ theta = np.pi * np.random.rand(n_points) phi = 2 * np.pi * np.random.rand(n_points) hsph_initial = HemiSphere(theta=theta, phi=phi) hsph_updated, energy = disperse_charges(hsph_initial, iters=n_iter) sph = Sphere(xyz=np.vstack((hsph_updated.vertices, -hsph_updated.vertices))) return sph
def get_spherical_harmonics_coefficients(self, dwi_weights, bvals, bvecs, sh_order=8, smooth=0.006): """ Compute coefficients of the spherical harmonics basis. Parameters ----------- dwi_weights : `nibabel.NiftiImage` object Diffusion signal as weighted images (4D). bvals : ndarray shape (N,) B-values used with each direction. bvecs : ndarray shape (N, 3) Directions of the diffusion signal. Directions are assumed to be only on the hemisphere. sh_order : int, optional SH order. Default: 8 smooth : float, optional Lambda-regularization in the SH fit. Default: 0.006. Returns ------- sh_coeffs : ndarray of shape (X, Y, Z, #coeffs) Spherical harmonics coefficients at every voxel. The actual number of coeffs depends on `sh_order`. """ # Exract the averaged b0. b0_idx = bvals == 0 b0 = dwi_weights[..., b0_idx].mean(axis=3) + 1e-10 # Extract diffusion weights and normalize by the b0. bvecs = bvecs[np.logical_not(b0_idx)] weights = dwi_weights[..., np.logical_not(b0_idx)] weights = self.normalize_dwi(weights, b0) # Assuming all directions are on the hemisphere. raw_sphere = HemiSphere(xyz=bvecs) # Fit SH to signal sph_harm_basis = sph_harm_lookup.get("tournier07") Ba, m, n = sph_harm_basis(sh_order, raw_sphere.theta, raw_sphere.phi) L = -n * (n + 1) invB = smooth_pinv(Ba, np.sqrt(smooth) * L) data_sh = np.dot(weights, invB.T) return data_sh