def test_vec2vec_rotmat(): a = np.array([1, 0, 0]) for b in np.array([[0, 0, 1], [-1, 0, 0], [1, 0, 0]]): R = vec2vec_rotmat(a, b) assert_array_almost_equal(np.dot(R, a), b) # These vectors are not unit norm c = np.array([0.33950729, 0.92041729, 0.1938216]) d = np.array([0.40604787, 0.97518325, 0.2057731]) R1 = vec2vec_rotmat(c, d) c_norm = c / np.linalg.norm(c) d_norm = d / np.linalg.norm(d) R2 = vec2vec_rotmat(c_norm, d_norm) assert_array_almost_equal(R1, R2, decimal=1) assert_array_almost_equal(np.diag(R1), np.diag(R2), decimal=3) # we are catching collinear vectors # but in the case where they are not # exactly collinear and slightly different # the cosine can be larger than 1 or smaller than # -1 and therefore we have to catch that issue e = np.array([1.0001, 0, 0]) f = np.array([1.001, 0.01, 0]) R3 = vec2vec_rotmat(e, f) g = np.array([1.001, 0.0, 0]) R4 = vec2vec_rotmat(e, g) assert_array_almost_equal(R3, R4, decimal=1) assert_array_almost_equal(np.diag(R3), np.diag(R4), decimal=3)
def calc_euler(evecs): """ Calculate the Euler angles that rotate from the canonical coordinate frame to a coordinate frame defined by a set of eigenvectors. Parameters ---------- evecs : 3-by-3 array """ rot0 = np.eye(4) # What is the rotation from the first eigenvector to eye(3)? rot0[:3, :3] = vec2vec_rotmat(evecs[0], np.eye(3)[0]) # Decompose (we only need the angles) scale, shear, angles0, translate, perspective = decompose_matrix(rot0) # Convert angles to Euler matrix: em = euler_matrix(*angles0) # Now, we need another rotation to bring the second eigenvector to the right # direction ang1 = np.arccos( np.dot(evecs[1], em[1, :3]) / (np.linalg.norm(evecs[1]) * np.linalg.norm(em[1, :3]))) rar = np.eye(4) # The rar is a matrix that rotates for a given angle around a given # vector: rar[:3, :3] = rodrigues_axis_rotation(evecs[0], np.rad2deg(ang1)) # We combine these two rotations and decompose the combined matrix to give # us three Euler angles, which will be our parameters scale, shear, angles, translate, perspective = decompose_matrix(em @ rar) return angles
def radon_params(self,ang_res=64): #calculate radon integration parameters phis=np.linspace(0,2*np.pi,ang_res)[:-1] planars=[] for phi in phis: planars.append(sphere2cart(1,np.pi/2,phi)) planars=np.array(planars) planarsR=[] for v in self.odf_vertices: R=vec2vec_rotmat(np.array([0,0,1]),v) planarsR.append(np.dot(R,planars.T).T) self.equators=planarsR self.equatorn=len(phis)
def radon_params(self, ang_res=64): #calculate radon integration parameters phis = np.linspace(0, 2 * np.pi, ang_res)[:-1] planars = [] for phi in phis: planars.append(sphere2cart(1, np.pi / 2, phi)) planars = np.array(planars) planarsR = [] for v in self.odf_vertices: R = vec2vec_rotmat(np.array([0, 0, 1]), v) planarsR.append(np.dot(R, planars.T).T) self.equators = planarsR self.equatorn = len(phis)
def diff2eigenvectors(dx,dy,dz): """ numerical derivatives 2 eigenvectors """ u=np.array([dx,dy,dz]) u=u/np.linalg.norm(u) R=vec2vec_rotmat(basis[:,0],u) eig0=u eig1=np.dot(R,basis[:,1]) eig2=np.dot(R,basis[:,2]) eigs=np.zeros((3,3)) eigs[:,0]=eig0 eigs[:,1]=eig1 eigs[:,2]=eig2 return eigs, R
def diff2eigenvectors(dx, dy, dz): """ numerical derivatives 2 eigenvectors """ u = np.array([dx, dy, dz]) u = u / np.linalg.norm(u) R = vec2vec_rotmat(basis[:, 0], u) eig0 = u eig1 = np.dot(R, basis[:, 1]) eig2 = np.dot(R, basis[:, 2]) eigs = np.zeros((3, 3)) eigs[:, 0] = eig0 eigs[:, 1] = eig1 eigs[:, 2] = eig2 return eigs, R
def all_tensor_evecs(e0): """Given the principle tensor axis, return the array of all eigenvectors (or, the rotation matrix that orientates the tensor). Parameters ---------- e0 : (3,) ndarray Principle tensor axis. Returns ------- evecs : (3,3) ndarray Tensor eigenvectors. """ axes = np.eye(3) mat = vec2vec_rotmat(axes[0], e0) e1 = np.dot(mat, axes[1]) e2 = np.dot(mat, axes[2]) return np.array([e0, e1, e2])
def all_tensor_evecs(e0): """Given the principle tensor axis, return the array of all eigenvectors (or, the rotation matrix that orientates the tensor). Parameters ---------- e0 : (3,) ndarray Principle tensor axis. Returns ------- evecs : (3,3) ndarray Tensor eigenvectors. """ axes = np.eye(3) mat = vec2vec_rotmat(axes[2], e0) e1 = np.dot(mat, axes[0]) e2 = np.dot(mat, axes[1]) return np.array([e0, e1, e2])
def gtab_reorient(gtab, old_vec, new_vec=np.array((0, 0, 1))): """ Rotate gradients the same way you would rotate old_vec to get new_vec Parameters ---------- gtab : dipy.data.GradientTable An object holding information about the applied Gradients including b-values and b-vectors old_vec : ndarray (3) Vector before rotation new_vec : ndarray (3) Vector after rotation. Default is the z-axis (0, 0, 1) Returns ------- dipy.data.GradientTable Rotated GradientTable """ rot_matrix = vec2vec_rotmat(old_vec, new_vec) return gtab_rotate(gtab, rot_matrix)
def test_btensor_to_bdelta(): """ Checks if bdeltas and bvals are as expected for 4 b-tensor shapes (LTE, PTE, STE, CTE) as well as scaled and rotated versions of them This function intrinsically tests the function `_btensor_to_bdelta_2d` as `_btensor_to_bdelta_2d` is only meant to be called by `btensor_to_bdelta` """ n_rotations = 30 n_scales = 3 expected_bdeltas = np.array([1, -0.5, 0, 0.5]) expected_bvals = np.array([1, 1, 1, 1]) # Baseline tensors to test linear_tensor = np.array([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) planar_tensor = np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]) / 2 spherical_tensor = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) / 3 cigar_tensor = np.array([[2, 0, 0], [0, .5, 0], [0, 0, .5]]) / 3 base_tensors = [ linear_tensor, planar_tensor, spherical_tensor, cigar_tensor ] n_base_tensors = len(base_tensors) # --------------------------------- # Test function on baseline tensors # --------------------------------- # Pre-allocate bdeltas = np.empty(n_base_tensors) bvals = np.empty(n_base_tensors) # Loop through each tensor type and check results for i, tensor in enumerate(base_tensors): i_bdelta, i_bval = btensor_to_bdelta(tensor) bdeltas[i] = i_bdelta bvals[i] = i_bval npt.assert_array_almost_equal(bdeltas, expected_bdeltas) npt.assert_array_almost_equal(bvals, expected_bvals) # Test function on a 3D input base_tensors_array = np.empty((4, 3, 3)) base_tensors_array[0, :, :] = linear_tensor base_tensors_array[1, :, :] = planar_tensor base_tensors_array[2, :, :] = spherical_tensor base_tensors_array[3, :, :] = cigar_tensor bdeltas, bvals = btensor_to_bdelta(base_tensors_array) npt.assert_array_almost_equal(bdeltas, expected_bdeltas) npt.assert_array_almost_equal(bvals, expected_bvals) # ----------------------------------------------------- # Test function after rotating+scaling baseline tensors # ----------------------------------------------------- scales = np.concatenate((np.array([1]), np.random.random(n_scales))) for scale in scales: ebs = expected_bvals * scale # Generate `n_rotations` random 3-element vectors of norm 1 v = np.random.random((n_rotations, 3)) - 0.5 u = np.apply_along_axis(lambda w: w / np.linalg.norm(w), axis=1, arr=v) for rot_idx in range(n_rotations): # Get rotation matrix for current iteration u_i = u[rot_idx, :] R_i = vec2vec_rotmat(np.array([1, 0, 0]), u_i) # Pre-allocate bdeltas = np.empty(n_base_tensors) bvals = np.empty(n_base_tensors) # Rotate each of the baseline test tensors and check results for i, tensor in enumerate(base_tensors): tensor_rot_i = np.matmul(np.matmul(R_i, tensor), R_i.T) i_bdelta, i_bval = btensor_to_bdelta(tensor_rot_i * scale) bdeltas[i] = i_bdelta bvals[i] = i_bval npt.assert_array_almost_equal(bdeltas, expected_bdeltas) npt.assert_array_almost_equal(bvals, ebs) # Input can't be string npt.assert_raises(ValueError, btensor_to_bdelta, 'LTE') # Input can't be list of strings npt.assert_raises(ValueError, btensor_to_bdelta, ['LTE', 'LTE']) # Input can't be 1D nor 4D npt.assert_raises(ValueError, btensor_to_bdelta, np.zeros((3, ))) npt.assert_raises(ValueError, btensor_to_bdelta, np.zeros((3, 3, 3, 3))) # Input shape must be (3, 3) OR (N, 3, 3) npt.assert_raises(ValueError, btensor_to_bdelta, np.zeros((4, 4))) npt.assert_raises(ValueError, btensor_to_bdelta, np.zeros((2, 2, 2)))
def test_vec2vec_rotmat(): a = np.array([1, 0, 0]) for b in np.array([[0, 0, 1], [-1, 0, 0], [1, 0, 0]]): R = vec2vec_rotmat(a, b) assert_array_almost_equal(np.dot(R, a), b)
def __init__(self, gradients, big_delta=None, small_delta=None, b0_threshold=50, btens=None): """Constructor for GradientTable class""" gradients = np.asarray(gradients) if gradients.ndim != 2 or gradients.shape[1] != 3: raise ValueError("gradients should be an (N, 3) array") self.gradients = gradients # Avoid nan gradients. Set these to 0 instead: self.gradients = np.where(np.isnan(gradients), 0., gradients) self.big_delta = big_delta self.small_delta = small_delta self.b0_threshold = b0_threshold if btens is not None: linear_tensor = np.array([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) planar_tensor = np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]) / 2 spherical_tensor = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) / 3 cigar_tensor = np.array([[2, 0, 0], [0, .5, 0], [0, 0, .5]]) / 3 if isinstance(btens, str): b_tensors = np.zeros((len(self.bvals), 3, 3)) if btens == 'LTE': b_tensor = linear_tensor elif btens == 'PTE': b_tensor = planar_tensor elif btens == 'STE': b_tensor = spherical_tensor elif btens == 'CTE': b_tensor = cigar_tensor else: raise ValueError("%s is an invalid value for btens. " % btens + "Please provide one of the following: " + "'LTE', 'PTE', 'STE', 'CTE'.") for i, (bvec, bval) in enumerate(zip(self.bvecs, self.bvals)): if btens == 'STE': b_tensors[i] = b_tensor * bval else: R = vec2vec_rotmat(np.array([1, 0, 0]), bvec) b_tensors[i] = ( np.matmul(np.matmul(R, b_tensor), R.T) * bval) self.btens = b_tensors elif (isinstance(btens, np.ndarray) and (btens.shape == (gradients.shape[0], ) or (btens.shape == (gradients.shape[0], 1)) or (btens.shape == (1, gradients.shape[0])))): b_tensors = np.zeros((len(self.bvals), 3, 3)) if btens.shape == (1, gradients.shape[0]): btens = btens.reshape((gradients.shape[0], 1)) for i, (bvec, bval) in enumerate(zip(self.bvecs, self.bvals)): R = vec2vec_rotmat(np.array([1, 0, 0]), bvec) if btens[i] == 'LTE': b_tensors[i] = ( np.matmul(np.matmul(R, linear_tensor), R.T) * bval) elif btens[i] == 'PTE': b_tensors[i] = ( np.matmul(np.matmul(R, planar_tensor), R.T) * bval) elif btens[i] == 'STE': b_tensors[i] = spherical_tensor * bval elif btens[i] == 'CTE': b_tensors[i] = ( np.matmul(np.matmul(R, cigar_tensor), R.T) * bval) else: raise ValueError( "%s is an invalid value in btens. " % btens[i] + "Array element options: 'LTE', 'PTE', 'STE', " + "'CTE'.") self.btens = b_tensors elif (isinstance(btens, np.ndarray) and btens.shape == (gradients.shape[0], 3, 3)): self.btens = btens else: raise ValueError("%s is an invalid value for btens. " % btens + "Please provide a string, an array of " + "strings, or an array of exact b-tensors. " + "String options: 'LTE', 'PTE', 'STE', 'CTE'") else: self.btens = None
def recursive_response(gtab, data, mask=None, sh_order=8, peak_thr=0.01, init_fa=0.08, init_trace=0.0021, iter=8, convergence=0.001, parallel=True, nbr_processes=None, sphere=default_sphere): """ Recursive calibration of response function using peak threshold Parameters ---------- gtab : GradientTable data : ndarray diffusion data mask : ndarray, optional mask for recursive calibration, for example a white matter mask. It has shape `data.shape[0:3]` and dtype=bool. Default: use the entire data array. sh_order : int, optional maximal spherical harmonics order. Default: 8 peak_thr : float, optional peak threshold, how large the second peak can be relative to the first peak in order to call it a single fiber population [1]. Default: 0.01 init_fa : float, optional FA of the initial 'fat' response function (tensor). Default: 0.08 init_trace : float, optional trace of the initial 'fat' response function (tensor). Default: 0.0021 iter : int, optional maximum number of iterations for calibration. Default: 8. convergence : float, optional convergence criterion, maximum relative change of SH coefficients. Default: 0.001. parallel : bool, optional Whether to use parallelization in peak-finding during the calibration procedure. Default: True nbr_processes: int If `parallel` is True, the number of subprocesses to use (default multiprocessing.cpu_count()). sphere : Sphere, optional. The sphere used for peak finding. Default: default_sphere. Returns ------- response : ndarray response function in SH coefficients Notes ----- In CSD there is an important pre-processing step: the estimation of the fiber response function. Using an FA threshold is not a very robust method. It is dependent on the dataset (non-informed used subjectivity), and still depends on the diffusion tensor (FA and first eigenvector), which has low accuracy at high b-value. This function recursively calibrates the response function, for more information see [1]. References ---------- .. [1] Tax, C.M.W., et al. NeuroImage 2014. Recursive calibration of the fiber response function for spherical deconvolution of diffusion MRI data. """ S0 = 1. evals = fa_trace_to_lambdas(init_fa, init_trace) res_obj = (evals, S0) if mask is None: data = data.reshape(-1, data.shape[-1]) else: data = data[mask] n = np.arange(0, sh_order + 1, 2) where_dwi = lazy_index(~gtab.b0s_mask) response_p = np.ones(len(n)) for num_it in range(iter): r_sh_all = np.zeros(len(n)) csd_model = ConstrainedSphericalDeconvModel(gtab, res_obj, sh_order=sh_order) csd_peaks = peaks_from_model(model=csd_model, data=data, sphere=sphere, relative_peak_threshold=peak_thr, min_separation_angle=25, parallel=parallel, nbr_processes=nbr_processes) dirs = csd_peaks.peak_dirs vals = csd_peaks.peak_values single_peak_mask = (vals[:, 1] / vals[:, 0]) < peak_thr data = data[single_peak_mask] dirs = dirs[single_peak_mask] for num_vox in range(data.shape[0]): rotmat = vec2vec_rotmat(dirs[num_vox, 0], np.array([0, 0, 1])) rot_gradients = np.dot(rotmat, gtab.gradients.T).T x, y, z = rot_gradients[where_dwi].T r, theta, phi = cart2sphere(x, y, z) # for the gradient sphere B_dwi = real_sph_harm(0, n, theta[:, None], phi[:, None]) r_sh_all += np.linalg.lstsq(B_dwi, data[num_vox, where_dwi])[0] response = r_sh_all / data.shape[0] res_obj = AxSymShResponse(data[:, gtab.b0s_mask].mean(), response) change = abs((response_p - response) / response_p) if all(change < convergence): break response_p = response return res_obj
def all_evecs(e0): axes=np.array([[1.,0,0],[0,1.,0],[0,0,1.]]) mat=vec2vec_rotmat(axes[2],e0) e1=np.dot(mat,axes[0]) e2=np.dot(mat,axes[1]) return np.array([e0,e1,e2])
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 recursive_response(gtab, data, mask=None, sh_order=8, peak_thr=0.01, init_fa=0.08, init_trace=0.0021, iter=8, convergence=0.001, parallel=True, nbr_processes=None, sphere=default_sphere): """ Recursive calibration of response function using peak threshold Parameters ---------- gtab : GradientTable data : ndarray diffusion data mask : ndarray, optional mask for recursive calibration, for example a white matter mask. It has shape `data.shape[0:3]` and dtype=bool. Default: use the entire data array. sh_order : int, optional maximal spherical harmonics order. Default: 8 peak_thr : float, optional peak threshold, how large the second peak can be relative to the first peak in order to call it a single fiber population [1]. Default: 0.01 init_fa : float, optional FA of the initial 'fat' response function (tensor). Default: 0.08 init_trace : float, optional trace of the initial 'fat' response function (tensor). Default: 0.0021 iter : int, optional maximum number of iterations for calibration. Default: 8. convergence : float, optional convergence criterion, maximum relative change of SH coefficients. Default: 0.001. parallel : bool, optional Whether to use parallelization in peak-finding during the calibration procedure. Default: True nbr_processes: int If `parallel` is True, the number of subprocesses to use (default multiprocessing.cpu_count()). sphere : Sphere, optional. The sphere used for peak finding. Default: default_sphere. Returns ------- response : ndarray response function in SH coefficients Notes ----- In CSD there is an important pre-processing step: the estimation of the fiber response function. Using an FA threshold is not a very robust method. It is dependent on the dataset (non-informed used subjectivity), and still depends on the diffusion tensor (FA and first eigenvector), which has low accuracy at high b-value. This function recursively calibrates the response function, for more information see [1]. References ---------- .. [1] Tax, C.M.W., et al. NeuroImage 2014. Recursive calibration of the fiber response function for spherical deconvolution of diffusion MRI data. """ S0 = 1. evals = fa_trace_to_lambdas(init_fa, init_trace) res_obj = (evals, S0) if mask is None: data = data.reshape(-1, data.shape[-1]) else: data = data[mask] n = np.arange(0, sh_order + 1, 2) where_dwi = lazy_index(~gtab.b0s_mask) response_p = np.ones(len(n)) for _ in range(iter): r_sh_all = np.zeros(len(n)) csd_model = ConstrainedSphericalDeconvModel(gtab, res_obj, sh_order=sh_order) csd_peaks = peaks_from_model(model=csd_model, data=data, sphere=sphere, relative_peak_threshold=peak_thr, min_separation_angle=25, parallel=parallel, nbr_processes=nbr_processes) dirs = csd_peaks.peak_dirs vals = csd_peaks.peak_values single_peak_mask = (vals[:, 1] / vals[:, 0]) < peak_thr data = data[single_peak_mask] dirs = dirs[single_peak_mask] for num_vox in range(data.shape[0]): rotmat = vec2vec_rotmat(dirs[num_vox, 0], np.array([0, 0, 1])) rot_gradients = np.dot(rotmat, gtab.gradients.T).T x, y, z = rot_gradients[where_dwi].T r, theta, phi = cart2sphere(x, y, z) # for the gradient sphere B_dwi = real_sph_harm(0, n, theta[:, None], phi[:, None]) r_sh_all += np.linalg.lstsq(B_dwi, data[num_vox, where_dwi], rcond=-1)[0] response = r_sh_all / data.shape[0] res_obj = AxSymShResponse(data[:, gtab.b0s_mask].mean(), response) change = abs((response_p - response) / response_p) if all(change < convergence): break response_p = response return res_obj
def test(): # img=nib.load('/home/eg309/Data/project01_dsi/connectome_0001/tp1/RAWDATA/OUT/mr000001.nii.gz') btable = np.loadtxt(get_data("dsi515btable")) # volume size sz = 16 # shifting origin = 8 # hanning width filter_width = 32.0 # number of signal sampling points n = 515 # odf radius radius = np.arange(2.1, 6, 0.2) # create q-table bv = btable[:, 0] bmin = np.sort(bv)[1] bv = np.sqrt(bv / bmin) qtable = np.vstack((bv, bv, bv)).T * btable[:, 1:] qtable = np.floor(qtable + 0.5) # copy bvals and bvecs bvals = btable[:, 0] bvecs = btable[:, 1:] # S=img.get_data()[38,50,20]#[96/2,96/2,20] S, stics = SticksAndBall( bvals, bvecs, d=0.0015, S0=100, angles=[(0, 0), (60, 0), (90, 90)], fractions=[0, 0, 0], snr=None ) S2 = S.copy() S2 = S2.reshape(1, len(S)) dn = DiffusionNabla(S2, bvals, bvecs, auto=False) pR = dn.equators odf = dn.odf(S) # Xs=dn.precompute_interp_coords() peaks, inds = peak_finding(odf.astype("f8"), dn.odf_faces.astype("uint16")) print peaks print peaks / peaks.min() # print dn.PK dn.fit() print dn.PK # """ ren = fvtk.ren() colors = fvtk.colors(odf, "jet") fvtk.add(ren, fvtk.point(dn.odf_vertices, colors, point_radius=0.05, theta=8, phi=8)) fvtk.show(ren) # """ stop # ds=DiffusionSpectrum(S2,bvals,bvecs) # tpr=ds.pdf(S) # todf=ds.odf(tpr) """ #show projected signal Bvecs=np.concatenate([bvecs[1:],-bvecs[1:]]) X0=np.dot(np.diag(np.concatenate([S[1:],S[1:]])),Bvecs) ren=fvtk.ren() fvtk.add(ren,fvtk.point(X0,fvtk.yellow,1,2,16,16)) fvtk.show(ren) """ # qtable=5*matrix[:,1:] # calculate radius for the hanning filter r = np.sqrt(qtable[:, 0] ** 2 + qtable[:, 1] ** 2 + qtable[:, 2] ** 2) # setting hanning filter width and hanning hanning = 0.5 * np.cos(2 * np.pi * r / filter_width) # center and index in q space volume q = qtable + origin q = q.astype("i8") # apply the hanning filter values = S * hanning """ #plot q-table ren=fvtk.ren() colors=fvtk.colors(values,'jet') fvtk.add(ren,fvtk.point(q,colors,1,0.1,6,6)) fvtk.show(ren) """ # create the signal volume Sq = np.zeros((sz, sz, sz)) for i in range(n): Sq[q[i][0], q[i][1], q[i][2]] += values[i] # apply fourier transform Pr = fftshift(np.abs(np.real(fftn(fftshift(Sq), (sz, sz, sz))))) # """ ren = fvtk.ren() vol = fvtk.volume(Pr) fvtk.add(ren, vol) fvtk.show(ren) # """ """ from enthought.mayavi import mlab mlab.pipeline.volume(mlab.pipeline.scalar_field(Sq)) mlab.show() """ # vertices, edges, faces = create_unit_sphere(5) vertices, faces = sphere_vf_from("symmetric362") odf = np.zeros(len(vertices)) for m in range(len(vertices)): xi = origin + radius * vertices[m, 0] yi = origin + radius * vertices[m, 1] zi = origin + radius * vertices[m, 2] PrI = map_coordinates(Pr, np.vstack((xi, yi, zi)), order=1) for i in range(len(radius)): odf[m] = odf[m] + PrI[i] * radius[i] ** 2 """ ren=fvtk.ren() colors=fvtk.colors(odf,'jet') fvtk.add(ren,fvtk.point(vertices,colors,point_radius=.05,theta=8,phi=8)) fvtk.show(ren) """ """ #Pr[Pr<500]=0 ren=fvtk.ren() #ren.SetBackground(1,1,1) fvtk.add(ren,fvtk.volume(Pr)) fvtk.show(ren) """ peaks, inds = peak_finding(odf.astype("f8"), faces.astype("uint16")) Eq = np.zeros((sz, sz, sz)) for i in range(n): Eq[q[i][0], q[i][1], q[i][2]] += S[i] / S[0] LEq = laplace(Eq) # Pr[Pr<500]=0 ren = fvtk.ren() # ren.SetBackground(1,1,1) fvtk.add(ren, fvtk.volume(Eq)) fvtk.show(ren) phis = np.linspace(0, 2 * np.pi, 100) planars = [] for phi in phis: planars.append(sphere2cart(1, np.pi / 2, phi)) planars = np.array(planars) planarsR = [] for v in vertices: R = vec2vec_rotmat(np.array([0, 0, 1]), v) planarsR.append(np.dot(R, planars.T).T) """ ren=fvtk.ren() fvtk.add(ren,fvtk.point(planarsR[0],fvtk.green,1,0.1,8,8)) fvtk.add(ren,fvtk.point(2*planarsR[1],fvtk.red,1,0.1,8,8)) fvtk.show(ren) """ azimsums = [] for disk in planarsR: diskshift = 4 * disk + origin # Sq0=map_coordinates(Sq,diskshift.T,order=1) # azimsums.append(np.sum(Sq0)) # Eq0=map_coordinates(Eq,diskshift.T,order=1) # azimsums.append(np.sum(Eq0)) LEq0 = map_coordinates(LEq, diskshift.T, order=1) azimsums.append(np.sum(LEq0)) azimsums = np.array(azimsums) # """ ren = fvtk.ren() colors = fvtk.colors(azimsums, "jet") fvtk.add(ren, fvtk.point(vertices, colors, point_radius=0.05, theta=8, phi=8)) fvtk.show(ren) # """ # for p in planarsR[0]: """
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