예제 #1
0
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)
예제 #2
0
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
예제 #3
0
파일: eit.py 프로젝트: endolith/dipy
 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)
예제 #4
0
파일: eit.py 프로젝트: Garyfallidis/dipy
 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)
예제 #5
0
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
예제 #6
0
파일: test_voxel.py 프로젝트: jgors/dipy
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
예제 #7
0
파일: voxel.py 프로젝트: nmabhi/dipy
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])
예제 #8
0
파일: voxel.py 프로젝트: iannimmosmith/dipy
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])
예제 #9
0
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)
예제 #10
0
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)))
예제 #11
0
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)
예제 #12
0
 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
예제 #13
0
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
예제 #14
0
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])
예제 #15
0
파일: sfm.py 프로젝트: qytian/dipy
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
예제 #16
0
파일: csdeconv.py 프로젝트: mbeyeler/dipy
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
예제 #17
0
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]:
    """
예제 #18
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