예제 #1
0
def test_smooth_pinv():
    hemi = hemi_icosahedron.subdivide(2)
    m, n = sph_harm_ind_list(4)

    with warnings.catch_warnings():
        warnings.filterwarnings("ignore",
                                message=descoteaux07_legacy_msg,
                                category=PendingDeprecationWarning)

        B = real_sh_descoteaux_from_index(m, n, hemi.theta[:, None],
                                          hemi.phi[:, None])

    L = np.zeros(len(m))
    C = smooth_pinv(B, L)
    D = np.dot(npl.inv(np.dot(B.T, B)), B.T)
    assert_array_almost_equal(C, D)

    L = n * (n + 1) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)

    assert_array_almost_equal(C, D)

    L = np.arange(len(n)) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)
    assert_array_almost_equal(C, D)
예제 #2
0
def test_sh_to_sf_matrix():
    sphere = Sphere(xyz=hemi_icosahedron.vertices)

    with warnings.catch_warnings():
        warnings.filterwarnings("ignore",
                                message=descoteaux07_legacy_msg,
                                category=PendingDeprecationWarning)

        B1, invB1 = sh_to_sf_matrix(sphere)

        B2, m, n = real_sh_descoteaux(4, sphere.theta, sphere.phi)

    invB2 = smooth_pinv(B2, L=np.zeros_like(n))

    with warnings.catch_warnings():
        warnings.filterwarnings("ignore",
                                message=descoteaux07_legacy_msg,
                                category=PendingDeprecationWarning)

        B3 = sh_to_sf_matrix(sphere, return_inv=False)

    assert_array_almost_equal(B1, B2.T)
    assert_array_almost_equal(invB1, invB2.T)
    assert_array_almost_equal(B3, B1)
    assert_raises(ValueError, sh_to_sf_matrix, sphere, basis_type="")
예제 #3
0
def test_real_sh_descoteaux2():
    vertices = hemi_icosahedron.subdivide(2).vertices
    mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]])
    angles = [(0, 0), (60, 0)]
    odf = multi_tensor_odf(vertices, mevals, angles, [50, 50])

    mevals = np.array([[0.0015, 0.0003, 0.0003]])
    angles = [(0, 0)]
    odf2 = multi_tensor_odf(-vertices, mevals, angles, [100])

    sphere = Sphere(xyz=np.vstack((vertices, -vertices)))
    # Asymmetric spherical function with 162 coefficients
    sf = np.append(odf, odf2)

    # In order for our approximation to be precise enough, we
    # will use a SH basis of orders up to 10 (121 coefficients)

    with warnings.catch_warnings(record=True) as w:
        B, m, n = real_sh_descoteaux(10,
                                     sphere.theta,
                                     sphere.phi,
                                     full_basis=True)

    npt.assert_equal(len(w), 1)
    npt.assert_(issubclass(w[0].category, PendingDeprecationWarning))
    npt.assert_(descoteaux07_legacy_msg in str(w[0].message))

    invB = smooth_pinv(B, L=np.zeros_like(n))
    sh_coefs = np.dot(invB, sf)
    sf_approx = np.dot(B, sh_coefs)

    assert_array_almost_equal(sf_approx, sf, 2)
예제 #4
0
def main():
    parser = _build_arg_parser()
    args = parser.parse_args()

    assert_inputs_exist(parser, args.input_sh)
    assert_outputs_exist(parser, args, args.output_name)

    input_basis = args.sh_basis
    output_basis = 'descoteaux07' if input_basis == 'tournier07' else 'tournier07'

    sph_harm_basis_ori = sph_harm_lookup.get(input_basis)
    sph_harm_basis_des = sph_harm_lookup.get(output_basis)

    sphere = get_sphere('repulsion724').subdivide(1)
    img = nib.load(args.input_sh)
    data = img.get_data()
    sh_order = find_order_from_nb_coeff(data)

    b_ori, m_ori, n_ori = sph_harm_basis_ori(sh_order, sphere.theta,
                                             sphere.phi)
    b_des, m_des, n_des = sph_harm_basis_des(sh_order, sphere.theta,
                                             sphere.phi)
    l_des = -n_des * (n_des + 1)
    inv_b_des = smooth_pinv(b_des, 0 * l_des)

    indices = np.argwhere(np.any(data, axis=3))
    for i, ind in enumerate(indices):
        ind = tuple(ind)
        sf_1 = np.dot(data[ind], b_ori.T)
        data[ind] = np.dot(sf_1, inv_b_des.T)

    img = nib.Nifti1Image(data, img.affine, img.header)
    nib.save(nib.Nifti1Image(data, img.affine, img.header), args.output_name)
예제 #5
0
def sh_smooth(data, bvals, bvecs, sh_order=4, similarity_threshold=50, regul=0.006):
    """Smooth the raw diffusion signal with spherical harmonics.
    data : ndarray
        The diffusion data to smooth.
    gtab : gradient table object
        Corresponding gradients table object to data.
    sh_order : int, default 8
        Order of the spherical harmonics to fit.
    similarity_threshold : int, default 50
        All b-values such that |b_1 - b_2| < similarity_threshold
        will be considered as identical for smoothing purpose.
        Must be lower than 200.
    regul : float, default 0.006
        Amount of regularization to apply to sh coefficients computation.
    Return
    ---------
    pred_sig : ndarray
        The smoothed diffusion data, fitted through spherical harmonics.
    """

    if similarity_threshold > 200:
        raise ValueError("similarity_threshold = {}, which is higher than 200,"
                         " please use a lower value".format(similarity_threshold))

    m, n = sph_harm_ind_list(sh_order)
    L = -n * (n + 1)
    where_b0s = bvals == 0
    pred_sig = np.zeros_like(data, dtype=np.float32)

    # Round similar bvals together for identifying similar shells
    rounded_bvals = np.zeros_like(bvals)

    for unique_bval in np.unique(bvals):
        idx = np.abs(unique_bval - bvals) < similarity_threshold
        rounded_bvals[idx] = unique_bval

    # process each b-value separately
    for unique_bval in np.unique(rounded_bvals):
        idx = rounded_bvals == unique_bval

        # Just give back the signal for the b0s since we can't really do anything about it
        if np.all(idx == where_b0s):
            if np.sum(where_b0s) > 1:
                pred_sig[..., idx] = np.mean(data[..., idx], axis=-1, keepdims=True)
            else:
                pred_sig[..., idx] = data[..., idx]
            continue

        x, y, z = bvecs[:, idx]
        r, theta, phi = cart2sphere(x, y, z)

        # Find the sh coefficients to smooth the signal
        B_dwi = real_sph_harm(m, n, theta[:, None], phi[:, None])
        invB = smooth_pinv(B_dwi, np.sqrt(regul) * L)
        sh_coeff = np.dot(data[..., idx], invB.T)

        # Find the smoothed signal from the sh fit for the given gtab
        pred_sig[..., idx] = np.dot(sh_coeff, B_dwi.T)

    return pred_sig
예제 #6
0
def sf_to_sh_invB(sphere, sh_order=8, basis_type=None, smooth=0.0):
    sph_harm_basis = sph_harm_lookup.get(basis_type)
    if sph_harm_basis is None:
        raise ValueError("Invalid basis name.")
    B, m, n = sph_harm_basis(sh_order, sphere.theta, sphere.phi)
    L = -n * (n + 1)
    invB = smooth_pinv(B, np.sqrt(smooth) * L)
    return invB.T
예제 #7
0
    def process(self, data_container, points, dwi):
        raw_sphere = Sphere(xyz=data_container.bvecs)

        real_sh, _, n = real_sym_sh_mrtrix(self.sh_order, raw_sphere.theta,
                                           raw_sphere.phi)
        l = -n * (n + 1)
        inv_b = smooth_pinv(real_sh, np.sqrt(self.smooth) * l)
        data_sh = np.dot(dwi, inv_b.T)

        return data_sh
예제 #8
0
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
예제 #9
0
 def __init__(self, odf_data, basis, sphere):
     self.basis = basis
     self.order = find_order_from_nb_coeff(odf_data)
     self.sphere = sphere
     B, self.m, self.n = get_b_matrix(self.order,
                                      self.sphere,
                                      self.basis,
                                      return_all=True)
     self.B = np.ascontiguousarray(np.matrix(B), dtype=np.float64)
     invB = smooth_pinv(self.B, np.sqrt(0.006) * (-self.n * (self.n + 1)))
     self.invB = np.ascontiguousarray(np.matrix(invB), dtype=np.float64)
예제 #10
0
파일: test_shm.py 프로젝트: tangwei/dipy
def test_sh_to_sf_matrix():
    sphere = Sphere(xyz=hemi_icosahedron.vertices)
    B1, invB1 = sh_to_sf_matrix(sphere)
    B2, m, n = real_sym_sh_basis(4, sphere.theta, sphere.phi)
    invB2 = smooth_pinv(B2, L=np.zeros_like(n))
    B3 = sh_to_sf_matrix(sphere, return_inv=False)

    assert_array_almost_equal(B1, B2.T)
    assert_array_almost_equal(invB1, invB2.T)
    assert_array_almost_equal(B3, B1)
    assert_raises(ValueError, sh_to_sf_matrix, sphere, basis_type="")
예제 #11
0
파일: test_shm.py 프로젝트: arokem/dipy
def test_smooth_pinv():
    hemi = hemi_icosahedron.subdivide(2)
    m, n = sph_harm_ind_list(4)
    B = real_sph_harm(m, n, hemi.theta[:, None], hemi.phi[:, None])

    L = np.zeros(len(m))
    C = smooth_pinv(B, L)
    D = np.dot(npl.inv(np.dot(B.T, B)), B.T)
    assert_array_almost_equal(C, D)

    L = n * (n + 1) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)

    assert_array_almost_equal(C, D)

    L = np.arange(len(n)) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)
    assert_array_almost_equal(C, D)
예제 #12
0
def test_smooth_pinv():
    hemi = hemi_icosahedron.subdivide(2)
    m, n = sph_harm_ind_list(4)
    B = real_sph_harm(m, n, hemi.theta[:, None], hemi.phi[:, None])

    L = np.zeros(len(m))
    C = smooth_pinv(B, L)
    D = np.dot(npl.inv(np.dot(B.T, B)), B.T)
    assert_array_almost_equal(C, D)

    L = n * (n + 1) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)

    assert_array_almost_equal(C, D)

    L = np.arange(len(n)) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)
    assert_array_almost_equal(C, D)
예제 #13
0
def test_smooth_pinv():
    v, e, f = create_half_unit_sphere(3)
    m, n = sph_harm_ind_list(4)
    r, pol, azi = cart2sphere(*v.T)
    B = real_sph_harm(m, n, azi[:, None], pol[:, None])

    L = np.zeros(len(m))
    C = smooth_pinv(B, L)
    D = np.dot(npl.inv(np.dot(B.T, B)), B.T)
    assert_array_almost_equal(C, D)

    L = n * (n + 1) * 0.05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)

    assert_array_almost_equal(C, D)

    L = np.arange(len(n)) * 0.05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)
    assert_array_almost_equal(C, D)
예제 #14
0
def test_smooth_pinv():
    v, e, f = create_half_unit_sphere(3)
    m, n = sph_harm_ind_list(4)
    r, pol, azi = cart2sphere(*v.T)
    B = real_sph_harm(m, n, azi[:, None], pol[:, None])

    L = np.zeros(len(m))
    C = smooth_pinv(B, L)
    D = np.dot(npl.inv(np.dot(B.T, B)), B.T)
    assert_array_almost_equal(C, D)

    L = n * (n + 1) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)

    assert_array_almost_equal(C, D)

    L = np.arange(len(n)) * .05
    C = smooth_pinv(B, L)
    L = np.diag(L)
    D = np.dot(npl.inv(np.dot(B.T, B) + L * L), B.T)
    assert_array_almost_equal(C, D)
예제 #15
0
def get_spherical_harmonics_coefficients(dwi, bvals, bvecs, sh_order=8, smooth=0.006, first=False):
    """ 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.

    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)
    return data_sh
예제 #16
0
    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
예제 #17
0
파일: test_shm.py 프로젝트: tangwei/dipy
def test_real_full_sh_basis():
    vertices = hemi_icosahedron.subdivide(2).vertices
    mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]])
    angles = [(0, 0), (60, 0)]
    odf = multi_tensor_odf(vertices, mevals, angles, [50, 50])

    mevals = np.array([[0.0015, 0.0003, 0.0003]])
    angles = [(0, 0)]
    odf2 = multi_tensor_odf(-vertices, mevals, angles, [100])

    sphere = Sphere(xyz=np.vstack((vertices, -vertices)))
    # Asymmetric spherical function with 162 coefficients
    sf = np.append(odf, odf2)

    # In order for our approximation to be precise enough, we
    # will use a SH basis of orders up to 10 (121 coefficients)
    B, m, n = real_full_sh_basis(10, sphere.theta, sphere.phi)
    invB = smooth_pinv(B, L=np.zeros_like(n))
    sh_coefs = np.dot(invB, sf)
    sf_approx = np.dot(B, sh_coefs)

    assert_array_almost_equal(sf_approx, sf, 2)
예제 #18
0
def get_B_matrix(gtab=None, sh_order=8, theta=None, phi=None, smooth=0.006):
    """Function that return matrices for Spherical Harmonics fitting
    Attributes:
        gtab (dipy GradientTable): the gradient of the dwi to be fitted
        sh_order (int): Order of the Spherical Harmonics
        theta: custom gradient angle used instead of gtab in combinaison w/ phi
        phi: same as theta
        smooth (float): the smoothing parameter for the laplacian

    Returns:
        B (np.array(nb_dwi_directions, nb_sh_coeff)): matrix to fit SH->DWI
        invB (np.array(nb_sh_coeff, nb_dwi_directions)): matrix to fit DWI->SH
    """
    if theta is None or phi is None:
        x, y, z = gtab.gradients[~gtab.b0s_mask].T
        r, theta, phi = cart2sphere(x, y, z)
    B, m, n = real_sym_sh_basis(sh_order, theta[:, None], phi[:, None])
    # B = real_sph_harm(m, n, theta[:, None], phi[:, None])
    L = -n * (n + 1)
    invB = smooth_pinv(B, np.sqrt(smooth) * L)

    return B, invB
예제 #19
0
파일: smoothing.py 프로젝트: luzpaz/nlsam
def sh_smooth(data,
              bvals,
              bvecs,
              sh_order=4,
              similarity_threshold=50,
              regul=0.006):
    """Smooth the raw diffusion signal with spherical harmonics.
    data : ndarray
        The diffusion data to smooth.
    gtab : gradient table object
        Corresponding gradients table object to data.
    sh_order : int, default 8
        Order of the spherical harmonics to fit.
    similarity_threshold : int, default 50
        All b-values such that |b_1 - b_2| < similarity_threshold
        will be considered as identical for smoothing purpose.
        Must be lower than 200.
    regul : float, default 0.006
        Amount of regularization to apply to sh coefficients computation.
    Return
    ---------
    pred_sig : ndarray
        The smoothed diffusion data, fitted through spherical harmonics.
    """

    if similarity_threshold > 200:
        raise ValueError(
            "similarity_threshold = {}, which is higher than 200,"
            " please use a lower value".format(similarity_threshold))

    m, n = sph_harm_ind_list(sh_order)
    L = -n * (n + 1)
    where_b0s = bvals == 0
    pred_sig = np.zeros_like(data, dtype=np.float32)

    # Round similar bvals together for identifying similar shells
    rounded_bvals = np.zeros_like(bvals)

    for unique_bval in np.unique(bvals):
        idx = np.abs(unique_bval - bvals) < similarity_threshold
        rounded_bvals[idx] = unique_bval

    # process each b-value separately
    for unique_bval in np.unique(rounded_bvals):
        idx = rounded_bvals == unique_bval

        # Just give back the signal for the b0s since we can't really do anything about it
        if np.all(idx == where_b0s):
            if np.sum(where_b0s) > 1:
                pred_sig[..., idx] = np.mean(data[..., idx],
                                             axis=-1,
                                             keepdims=True)
            else:
                pred_sig[..., idx] = data[..., idx]
            continue

        x, y, z = bvecs[:, idx]
        r, theta, phi = cart2sphere(x, y, z)

        # Find the sh coefficients to smooth the signal
        B_dwi = real_sph_harm(m, n, theta[:, None], phi[:, None])
        invB = smooth_pinv(B_dwi, np.sqrt(regul) * L)
        sh_coeff = np.dot(data[..., idx], invB.T)

        # Find the smoothed signal from the sh fit for the given gtab
        pred_sig[..., idx] = np.dot(sh_coeff, B_dwi.T)

    return pred_sig
예제 #20
0
파일: odf.py 프로젝트: Vincent-Methot/dipy
def peaks_from_model(model, data, sphere, relative_peak_threshold,
                     min_separation_angle, mask=None, return_odf=False,
                     return_sh=True, gfa_thr=0, normalize_peaks=False,
                     sh_order=8, sh_basis_type=None):
    """Fits the model to data and computes peaks and metrics

    Parameters
    ----------
    model : a model instance
        `model` will be used to fit the data.
    sphere : Sphere
        The Sphere providing discrete directions for evaluation.
    relative_peak_threshold : float
        Only return peaks greater than ``relative_peak_threshold * m`` where m
        is the largest peak.
    min_separation_angle : float in [0, 90] The minimum distance between
        directions. If two peaks are too close only the larger of the two is
        returned.
    mask : array, optional
        If `mask` is provided, voxels that are False in `mask` are skipped and
        no peaks are returned.
    return_odf : bool
        If True, the odfs are returned.
    return_sh : bool
        If True, the odf as spherical harmonics coefficients is returned
    gfa_thr : float
        Voxels with gfa less than `gfa_thr` are skipped, no peaks are returned.
    normalize_peaks : bool
        If true, all peak values are calculated relative to `max(odf)`.
    sh_order : int, optional
        Maximum SH order in the SH fit.  For `sh_order`, there will be
        ``(sh_order + 1) * (sh_order + 2) / 2`` SH coefficients (default 8).
    sh_basis_type : {None, 'mrtrix', 'fibernav'}
        ``None`` for the default dipy basis which is the fibernav basis,
        ``mrtrix`` for the MRtrix basis, and
        ``fibernav`` for the FiberNavigator basis
    
    Returns
    -------
    pam : PeaksAndMetrics
        an object with ``gfa``, ``peak_values``, ``peak_indices``, ``odf``,
        ``shm_coeffs`` as attributes

    """

    data_flat = data.reshape((-1, data.shape[-1]))
    size = len(data_flat)
    if mask is None:
        mask = np.ones(size, dtype='bool')
    else:
        mask = mask.ravel()
        if len(mask) != size:
            raise ValueError("mask is not the same size as data")

    npeaks = 5
    sh_smooth=0
    gfa_array = np.zeros(size)
    qa_array = np.zeros((size, npeaks))
    peak_values = np.zeros((size, npeaks))
    peak_indices = np.zeros((size, npeaks), dtype='int')
    peak_indices.fill(-1)

    if return_sh:

        #import here to avoid circular imports
        from dipy.reconst.shm import sph_harm_lookup, smooth_pinv

        sph_harm_basis = sph_harm_lookup.get(sh_basis_type)
        if sph_harm_basis is None:
            raise ValueError("Invalid basis name.")
        B, m, n = sph_harm_basis(sh_order, sphere.theta, sphere.phi)
        L = -n * (n + 1)
        invB = smooth_pinv(B, np.sqrt(sh_smooth) * L)
        n_shm_coeff = (sh_order + 2) * (sh_order + 1) / 2
        shm_coeff = np.zeros((size, n_shm_coeff))
        invB = invB.T
        #sh = np.dot(sf, invB.T)

    if return_odf:
        odf_array = np.zeros((size, len(sphere.vertices)))

    global_max = -np.inf
    for i, sig in enumerate(data_flat):
        if not mask[i]:
            continue
        odf = model.fit(sig).odf(sphere)

        if return_sh:
            shm_coeff[i] = np.dot(odf, invB)

        if return_odf:
            odf_array[i] = odf

        gfa_array[i] = gfa(odf)
        if gfa_array[i] < gfa_thr:
            global_max = max(global_max, odf.max())
            continue

        # Get peaks of odf
        _, pk, ind = peak_directions(odf, sphere, relative_peak_threshold,
                                     min_separation_angle)

        # Calculate peak metrics
        global_max = max(global_max, pk[0])
        n = min(npeaks, len(pk))
        qa_array[i, :n] = pk[:n] - odf.min()
        if normalize_peaks:
            peak_values[i, :n] = pk[:n] / pk[0]
        else:
            peak_values[i, :n] = pk[:n]
        peak_indices[i, :n] = ind[:n]

    shape = data.shape[:-1]
    gfa_array = gfa_array.reshape(shape)
    qa_array = qa_array.reshape(shape + (npeaks,)) / global_max
    peak_values = peak_values.reshape(shape + (npeaks,))
    peak_indices = peak_indices.reshape(shape + (npeaks,))

    pam = PeaksAndMetrics()
    pam.peak_values = peak_values
    pam.peak_indices = peak_indices
    pam.gfa = gfa_array
    pam.qa = qa_array

    if return_sh:
        pam.shm_coeff = shm_coeff.reshape(shape + (n_shm_coeff,))
        pam.invB = invB
    else:
        pam.shm_coeff = None
        pam.invB = None

    if return_odf:
        pam.odf = odf_array.reshape(shape + odf_array.shape[-1:])
    else:
        pam.odf = None

    return pam
예제 #21
0
def main():
    params = readArgs()
    # read in from the command line
    read_args = params.collect_args()
    params.check_args(read_args)

    # get img obj
    dwi_img = nib.load(params.dwi_)
    mask_img = nib.load(params.mask_)

    from dipy.io import read_bvals_bvecs
    bvals, bvecs = read_bvals_bvecs(params.bval_, params.bvec_)

    # need to create the gradient table yo
    from dipy.core.gradients import gradient_table
    gtab = gradient_table(bvals, bvecs, b0_threshold=25)

    # get the data from image objects
    dwi_data = dwi_img.get_data()
    mask_data = mask_img.get_data()
    # and get affine
    img_affine = dwi_img.affine

    from dipy.data import get_sphere
    sphere = get_sphere('repulsion724')

    from dipy.segment.mask import applymask
    dwi_data = applymask(dwi_data, mask_data)

    printfl('dwi_data.shape (%d, %d, %d, %d)' % dwi_data.shape)
    printfl('\nYour bvecs look like this:{0}'.format(bvecs))
    printfl('\nYour bvals look like this:{0}\n'.format(bvals))

    from dipy.reconst.shm import anisotropic_power, sph_harm_lookup, smooth_pinv, normalize_data
    from dipy.core.sphere import HemiSphere

    smooth = 0.0
    normed_data = normalize_data(dwi_data, gtab.b0s_mask)
    normed_data = normed_data[..., np.where(1 - gtab.b0s_mask)[0]]

    from dipy.core.gradients import gradient_table_from_bvals_bvecs
    gtab2 = gradient_table_from_bvals_bvecs(
        gtab.bvals[np.where(1 - gtab.b0s_mask)[0]],
        gtab.bvecs[np.where(1 - gtab.b0s_mask)[0]])

    signal_native_pts = HemiSphere(xyz=gtab2.bvecs)
    sph_harm_basis = sph_harm_lookup.get(None)
    Ba, m, n = sph_harm_basis(params.sh_order_, signal_native_pts.theta,
                              signal_native_pts.phi)

    L = -n * (n + 1)
    invB = smooth_pinv(Ba, np.sqrt(smooth) * L)

    # fit SH basis to DWI signal
    normed_data_sh = np.dot(normed_data, invB.T)

    # power map call
    printfl("fitting power map")
    pow_map = anisotropic_power(normed_data_sh,
                                norm_factor=0.00001,
                                power=2,
                                non_negative=True)

    pow_map_img = nib.Nifti1Image(pow_map.astype(np.float32), img_affine)
    # make output name
    out_name = ''.join(
        [params.output_, '_powMap_sh',
         str(params.sh_order_), '.nii.gz'])

    printfl("writing power map to: {}".format(out_name))
    nib.save(pow_map_img, out_name)
예제 #22
0
def peaks_from_model(model,
                     data,
                     sphere,
                     relative_peak_threshold,
                     min_separation_angle,
                     mask=None,
                     return_odf=False,
                     return_sh=True,
                     gfa_thr=0,
                     normalize_peaks=False,
                     sh_order=8,
                     sh_basis_type=None):
    """Fits the model to data and computes peaks and metrics

    Parameters
    ----------
    model : a model instance
        `model` will be used to fit the data.
    sphere : Sphere
        The Sphere providing discrete directions for evaluation.
    relative_peak_threshold : float
        Only return peaks greater than ``relative_peak_threshold * m`` where m
        is the largest peak.
    min_separation_angle : float in [0, 90] The minimum distance between
        directions. If two peaks are too close only the larger of the two is
        returned.
    mask : array, optional
        If `mask` is provided, voxels that are False in `mask` are skipped and
        no peaks are returned.
    return_odf : bool
        If True, the odfs are returned.
    return_sh : bool
        If True, the odf as spherical harmonics coefficients is returned
    gfa_thr : float
        Voxels with gfa less than `gfa_thr` are skipped, no peaks are returned.
    normalize_peaks : bool
        If true, all peak values are calculated relative to `max(odf)`.
    sh_order : int, optional
        Maximum SH order in the SH fit.  For `sh_order`, there will be
        ``(sh_order + 1) * (sh_order + 2) / 2`` SH coefficients (default 8).
    sh_basis_type : {None, 'mrtrix', 'fibernav'}
        ``None`` for the default dipy basis which is the fibernav basis,
        ``mrtrix`` for the MRtrix basis, and
        ``fibernav`` for the FiberNavigator basis
    
    Returns
    -------
    pam : PeaksAndMetrics
        an object with ``gfa``, ``peak_values``, ``peak_indices``, ``odf``,
        ``shm_coeffs`` as attributes

    """

    data_flat = data.reshape((-1, data.shape[-1]))
    size = len(data_flat)
    if mask is None:
        mask = np.ones(size, dtype='bool')
    else:
        mask = mask.ravel()
        if len(mask) != size:
            raise ValueError("mask is not the same size as data")

    npeaks = 5
    sh_smooth = 0
    gfa_array = np.zeros(size)
    qa_array = np.zeros((size, npeaks))
    peak_values = np.zeros((size, npeaks))
    peak_indices = np.zeros((size, npeaks), dtype='int')
    peak_indices.fill(-1)

    if return_sh:

        #import here to avoid circular imports
        from dipy.reconst.shm import sph_harm_lookup, smooth_pinv

        sph_harm_basis = sph_harm_lookup.get(sh_basis_type)
        if sph_harm_basis is None:
            raise ValueError("Invalid basis name.")
        B, m, n = sph_harm_basis(sh_order, sphere.theta, sphere.phi)
        L = -n * (n + 1)
        invB = smooth_pinv(B, np.sqrt(sh_smooth) * L)
        n_shm_coeff = (sh_order + 2) * (sh_order + 1) / 2
        shm_coeff = np.zeros((size, n_shm_coeff))
        invB = invB.T
        #sh = np.dot(sf, invB.T)

    if return_odf:
        odf_array = np.zeros((size, len(sphere.vertices)))

    global_max = -np.inf
    for i, sig in enumerate(data_flat):
        if not mask[i]:
            continue
        odf = model.fit(sig).odf(sphere)

        if return_sh:
            shm_coeff[i] = np.dot(odf, invB)

        if return_odf:
            odf_array[i] = odf

        gfa_array[i] = gfa(odf)
        if gfa_array[i] < gfa_thr:
            global_max = max(global_max, odf.max())
            continue

        # Get peaks of odf
        _, pk, ind = peak_directions(odf, sphere, relative_peak_threshold,
                                     min_separation_angle)

        # Calculate peak metrics
        global_max = max(global_max, pk[0])
        n = min(npeaks, len(pk))
        qa_array[i, :n] = pk[:n] - odf.min()
        if normalize_peaks:
            peak_values[i, :n] = pk[:n] / pk[0]
        else:
            peak_values[i, :n] = pk[:n]
        peak_indices[i, :n] = ind[:n]

    shape = data.shape[:-1]
    gfa_array = gfa_array.reshape(shape)
    qa_array = qa_array.reshape(shape + (npeaks, )) / global_max
    peak_values = peak_values.reshape(shape + (npeaks, ))
    peak_indices = peak_indices.reshape(shape + (npeaks, ))

    pam = PeaksAndMetrics()
    pam.peak_values = peak_values
    pam.peak_indices = peak_indices
    pam.gfa = gfa_array
    pam.qa = qa_array

    if return_sh:
        pam.shm_coeff = shm_coeff.reshape(shape + (n_shm_coeff, ))
        pam.invB = invB
    else:
        pam.shm_coeff = None
        pam.invB = None

    if return_odf:
        pam.odf = odf_array.reshape(shape + odf_array.shape[-1:])
    else:
        pam.odf = None

    return pam
예제 #23
0
파일: odf.py 프로젝트: swederik/dipy
def peaks_from_model(model, data, sphere, relative_peak_threshold,
                     min_separation_angle, mask=None, return_odf=False,
                     return_sh=True, gfa_thr=0, normalize_peaks=False,
                     sh_order=8, sh_basis_type=None, ravel_peaks=False,
                     npeaks=5, parallel=False, nbr_process=None):
    """Fits the model to data and computes peaks and metrics

    Parameters
    ----------
    model : a model instance
        `model` will be used to fit the data.
    sphere : Sphere
        The Sphere providing discrete directions for evaluation.
    relative_peak_threshold : float
        Only return peaks greater than ``relative_peak_threshold * m`` where m
        is the largest peak.
    min_separation_angle : float in [0, 90] The minimum distance between
        directions. If two peaks are too close only the larger of the two is
        returned.
    mask : array, optional
        If `mask` is provided, voxels that are False in `mask` are skipped and
        no peaks are returned.
    return_odf : bool
        If True, the odfs are returned.
    return_sh : bool
        If True, the odf as spherical harmonics coefficients is returned
    gfa_thr : float
        Voxels with gfa less than `gfa_thr` are skipped, no peaks are returned.
    normalize_peaks : bool
        If true, all peak values are calculated relative to `max(odf)`.
    sh_order : int, optional
        Maximum SH order in the SH fit.  For `sh_order`, there will be
        ``(sh_order + 1) * (sh_order + 2) / 2`` SH coefficients (default 8).
    sh_basis_type : {None, 'mrtrix', 'fibernav'}
        ``None`` for the default dipy basis which is the fibernav basis,
        ``mrtrix`` for the MRtrix basis, and
        ``fibernav`` for the FiberNavigator basis
    ravel_peaks : bool
        If True, the peaks are returned as [x1, y1, z1, ..., xn, yn, zn] instead
        of Nx3. Set this flag to True if you want to visualize the peaks in the
        fibernavigator or in mrtrix.
    npeaks : int
        Maximum number of peaks found (default 5 peaks).
    parallel: bool
        If True, use multiprocessing to compute peaks and metric (default False).
    nbr_process: int
        If `parallel == True`, the number of subprocess to use (default multiprocessing.cpu_count()).

    Returns
    -------
    pam : PeaksAndMetrics
        An object with ``gfa``, ``peak_directions``, ``peak_values``,
        ``peak_indices``, ``odf``, ``shm_coeffs`` as attributes

    """

    if parallel:
        return __peaks_from_model_parallel(model,
                                           data, sphere,
                                           relative_peak_threshold,
                                           min_separation_angle,
                                           mask, return_odf,
                                           return_sh,
                                           gfa_thr,
                                           normalize_peaks,
                                           sh_order,
                                           sh_basis_type,
                                           ravel_peaks,
                                           npeaks,
                                           nbr_process)

    shape = data.shape[:-1]
    if mask is None:
        mask = np.ones(shape, dtype='bool')
    else:
        if mask.shape != shape:
            raise ValueError("Mask is not the same shape as data.")

    sh_smooth = 0
    gfa_array = np.zeros(shape)
    qa_array = np.zeros((shape + (npeaks,)))

    peak_dirs = np.zeros((shape + (npeaks, 3)))
    peak_values = np.zeros((shape + (npeaks,)))
    peak_indices = np.zeros((shape + (npeaks,)), dtype='int')
    peak_indices.fill(-1)

    if return_sh:
        # import here to avoid circular imports
        from dipy.reconst.shm import sph_harm_lookup, smooth_pinv

        sph_harm_basis = sph_harm_lookup.get(sh_basis_type)
        if sph_harm_basis is None:
            raise ValueError("Invalid basis name.")
        B, m, n = sph_harm_basis(sh_order, sphere.theta, sphere.phi)
        L = -n * (n + 1)
        invB = smooth_pinv(B, np.sqrt(sh_smooth) * L)
        n_shm_coeff = (sh_order + 2) * (sh_order + 1) / 2
        shm_coeff = np.zeros((shape + (n_shm_coeff,)))
        invB = invB.T

    if return_odf:
        odf_array = np.zeros((shape + (len(sphere.vertices),)))

    global_max = -np.inf
    for idx in ndindex(shape):
        if not mask[idx]:
            continue

        odf = model.fit(data[idx]).odf(sphere)

        if return_sh:
            shm_coeff[idx] = np.dot(odf, invB)

        if return_odf:
            odf_array[idx] = odf

        gfa_array[idx] = gfa(odf)
        if gfa_array[idx] < gfa_thr:
            global_max = max(global_max, odf.max())
            continue

        # Get peaks of odf
        direction, pk, ind = peak_directions(
            odf, sphere, relative_peak_threshold,
            min_separation_angle)

        # Calculate peak metrics
        global_max = max(global_max, pk[0])
        n = min(npeaks, len(pk))
        qa_array[idx][:n] = pk[:n] - odf.min()

        peak_dirs[idx][:n] = direction[:n]
        peak_indices[idx][:n] = ind[:n]
        peak_values[idx][:n] = pk[:n]

        if normalize_peaks:
            peak_values[idx][:n] /= pk[0]
            peak_dirs[idx] *= peak_values[idx][:, None]

    #gfa_array = gfa_array
    qa_array /= global_max
    #peak_values = peak_values
    #peak_indices = peak_indices

    # The fibernavigator only supports float32. Since this form is mainly
    # for external visualisation, we enforce float32.
    if ravel_peaks:
        peak_dirs = peak_dirs.reshape(shape + (3 * npeaks,)).astype('float32')

    pam = PeaksAndMetrics()
    pam.peak_dirs = peak_dirs
    pam.peak_values = peak_values
    pam.peak_indices = peak_indices
    pam.gfa = gfa_array
    pam.qa = qa_array

    if return_sh:
        pam.shm_coeff = shm_coeff
        pam.invB = invB
    else:
        pam.shm_coeff = None
        pam.invB = None

    if return_odf:
        pam.odf = odf_array
    else:
        pam.odf = None

    return pam