Example #1
0
def test_peak_finding():

    vertices, faces=get_sphere('symmetric724')
    odf=np.zeros(len(vertices))
    odf = np.abs(vertices.sum(-1))

    odf[1] = 10.
    odf[505] = 505.
    odf[143] = 143.

    peaks, inds=peak_finding(odf.astype('f8'), faces.astype('uint16'))
    print peaks, inds
    edges = unique_edges(faces)
    peaks, inds = local_maxima(odf, edges)
    print peaks, inds
    vertices_half, edges_half, faces_half = reduce_antipodal(vertices, faces)
    n = len(vertices_half)
    peaks, inds = local_maxima(odf[:n], edges_half)
    print peaks, inds
    mevals=np.array(([0.0015,0.0003,0.0003],
                    [0.0015,0.0003,0.0003]))
    e0=np.array([1,0,0.])
    e1=np.array([0.,1,0])
    mevecs=[all_tensor_evecs(e0),all_tensor_evecs(e1)]
    odf = multi_tensor_odf(vertices, [0.5,0.5], mevals, mevecs)
    peaks, inds=peak_finding(odf, faces)
    print peaks, inds
    peaks2, inds2 = local_maxima(odf[:n], edges_half)
    print peaks2, inds2
    assert_equal(len(peaks), 2)
    assert_equal(len(peaks2), 2)
Example #2
0
def test_local_maxima():
    sphere = get_sphere('symmetric724')
    vertices, faces = sphere.vertices, sphere.faces
    edges = unique_edges(faces)
    odf = abs(vertices.sum(-1))
    odf[1] = 10.
    odf[143] = 143.
    odf[505] = 505

    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_values, [505, 143, 10])
    npt.assert_array_equal(peak_index, [505, 143, 1])

    hemisphere = HemiSphere(xyz=vertices, faces=faces)
    vertices_half, edges_half = hemisphere.vertices, hemisphere.edges
    odf = abs(vertices_half.sum(-1))
    odf[1] = 10.
    odf[143] = 143.

    peak_value, peak_index = local_maxima(odf, edges_half)
    npt.assert_array_equal(peak_value, [143, 10])
    npt.assert_array_equal(peak_index, [143, 1])

    odf[20] = np.nan
    npt.assert_raises(ValueError, local_maxima, odf, edges_half)
Example #3
0
    def odf(self, sphere):
        r""" Calculates the real discrete odf for a given discrete sphere

        ..math::
            :nowrap:
                \begin{equation}
                    \psi_{DSI}(\hat{\mathbf{u}})=\int_{0}^{\infty}P(r\hat{\mathbf{u}})r^{2}dr
                \end{equation}

        where $\hat{\mathbf{u}}$ is the unit vector which corresponds to a
        sphere point.
        """
        interp_coords = self.model.cache_get('interp_coords',
                                             key=sphere)
        if interp_coords is None:
            interp_coords = pdf_interp_coords(sphere,
                                              self.model.qradius,
                                              self.model.origin)
            self.model.cache_set('interp_coords', sphere, interp_coords)

        Pr = self.pdf()

        #calculate the orientation distribution function
        odf = pdf_odf(Pr, sphere, self.model.qradius, interp_coords)

        # We compute the gfa here, since we have the ODF available and
        # the storage requirements are minimal.  Otherwise, we'd need to
        # recompute the ODF at significant computational expense.
        self._gfa = gfa(odf)
        pk, ind = local_maxima(odf, sphere.edges)

        relative_peak_threshold = self.model.direction_finder._config["relative_peak_threshold"]
        min_separation_angle = self.model.direction_finder._config["min_separation_angle"]

        # Remove small peaks.
        gt_threshold = pk >= (relative_peak_threshold * pk[0])
        pk = pk[gt_threshold]
        ind = ind[gt_threshold]

        # Keep peaks which are unique, which means remove peaks that are too
        # close to a larger peak.
        _, where_uniq = remove_similar_vertices(sphere.vertices[ind],
                                                min_separation_angle,
                                                return_index=True)
        pk = pk[where_uniq]
        ind = ind[where_uniq]

        # Calculate peak metrics
        #global_max = max(global_max, pk[0])
        n = min(self.npeaks, len(pk))
        #qa_array[i, :n] = pk[:n] - odf.min()
        self._peak_values = np.zeros(self.npeaks)
        self._peak_indices = np.zeros(self.npeaks)
        if self.model.normalize_peaks:
            self._peak_values[:n] = pk[:n] / pk[0]
        else:
            self._peak_values[:n] = pk[:n]
        self._peak_indices[:n] = ind[:n]

        return odf
Example #4
0
    def fit_angle(self):
        """
        The angle between the two primary peaks in the ODF
        
        """
        out_flat = np.zeros(self._flat_signal.shape[0])
        flat_odf = self.odf[self.mask]
        for vox in xrange(out_flat.shape[0]):
            if np.any(np.isnan(flat_odf[vox])):
                out_flat[vox] = np.nan
            else:
                p, i = recspeed.local_maxima(flat_odf[vox], self.odf_verts[1])
                mask = p > 0.5 * np.max(p)
                p = p[mask]
                i = i[mask]

                if len(p) < 2:
                    out_flat[vox] = np.nan
                else:
                    out_flat[vox] = np.rad2deg(ozu.vector_angle(
                                        self.odf_verts[0][i[0]],
                                        self.odf_verts[0][i[1]]))

        out = ozu.nans(self.signal.shape[:3])
        out[self.mask] = out_flat
        return out
Example #5
0
    def fit_angle(self):
        """
        The angle between the two primary peaks in the ODF
        
        """
        out_flat = np.zeros(self._flat_signal.shape[0])
        flat_odf = self.odf[self.mask]
        for vox in xrange(out_flat.shape[0]):
            if np.any(np.isnan(flat_odf[vox])):
                out_flat[vox] = np.nan
            else:
                p, i = recspeed.local_maxima(flat_odf[vox], self.odf_verts[1])
                mask = p > 0.5 * np.max(p)
                p = p[mask]
                i = i[mask]

                if len(p) < 2:
                    out_flat[vox] = np.nan
                else:
                    out_flat[vox] = np.rad2deg(
                        ozu.vector_angle(self.odf_verts[0][i[0]],
                                         self.odf_verts[0][i[1]]))

        out = ozu.nans(self.signal.shape[:3])
        out[self.mask] = out_flat
        return out
Example #6
0
def separation_from_odf(odf):
    # Find angles
    from dipy.reconst.recspeed import local_maxima
    p, i = local_maxima(odf, edges)
    p = p[:2]
    i = i[:2]
    print "Peaks:", p
    print "Angular separation:", np.rad2deg(np.arccos(np.abs(np.dot(verts[i[0]], verts[i[1]]))))
Example #7
0
def angle_from_odf(odf, verts, edges):
    # Find angles
    p, i = local_maxima(odf, edges)

    mask = p > 0
    p = p[mask]
    i = i[mask]

    if len(p) < 2:
        return 0

    w = np.dot(verts[i[0]], verts[i[1]])
    return np.rad2deg(np.arccos(np.abs(w)))
Example #8
0
def test_local_maxima():
    vertices, faces=get_sphere('symmetric724')
    edges = unique_edges(faces)
    odf = abs(vertices.sum(-1))
    odf[1] = 10.
    odf[143] = 143.
    odf[505] = 505

    peak_values, peak_index = local_maxima(odf, edges)
    assert_array_equal(peak_values, [505, 143, 10])
    assert_array_equal(peak_index, [505, 143, 1])

    vertices_half, edges_half, faces_half = reduce_antipodal(vertices, faces)
    odf = abs(vertices_half.sum(-1))
    odf[1] = 10.
    odf[143] = 143.

    peak_value, peak_index = local_maxima(odf, edges_half)
    assert_array_equal(peak_value, [143, 10])
    assert_array_equal(peak_index, [143, 1])

    odf[20] = np.nan
    assert_raises(ValueError, local_maxima, odf, edges_half)
Example #9
0
    def odf_peaks(self):
        """
        Calculate the value of each of the peaks in the ODF using the dipy
        peak-finding algorithm
        """
        faces = sphere.Sphere(xyz=self.bvecs[:, self.b_idx].T).faces
        odf_flat = self.odf[self.mask]
        out_flat = np.zeros(odf_flat.shape)
        for vox in xrange(odf_flat.shape[0]):
            if np.all(np.isfinite(odf_flat[vox])):
                peaks, inds = recspeed.local_maxima(odf_flat[vox], faces)
                out_flat[vox][inds] = peaks

        out = np.zeros(self.odf.shape)
        out[self.mask] = out_flat
        return out
Example #10
0
    def odf_peaks(self):
        """
        Calculate the value of each of the peaks in the ODF using the dipy
        peak-finding algorithm
        """
        faces = sphere.Sphere(xyz=self.bvecs[:, self.b_idx].T).faces
        odf_flat = self.odf[self.mask]
        out_flat = np.zeros(odf_flat.shape)
        for vox in xrange(odf_flat.shape[0]):
            if np.all(np.isfinite(odf_flat[vox])):
                peaks, inds = recspeed.local_maxima(odf_flat[vox], faces)
                out_flat[vox][inds] = peaks

        out = np.zeros(self.odf.shape)
        out[self.mask] = out_flat
        return out
Example #11
0
    def odf_peaks(self):
        """
        Calculate the value of the peaks in the ODF (in this case, that is
        defined as the weights on the model params 
        """
        faces = dps.Sphere(xyz=self.bvecs[:,self.b_idx].T).faces
        if self._n_vox == 1: 
            odf_flat = np.array([self.model_params])
        else: 
            odf_flat = self.model_params[self.mask]
        out_flat = np.zeros(odf_flat.shape)
        for vox in xrange(odf_flat.shape[0]):
            if ~np.any(np.isnan(odf_flat[vox])):
                this_odf = odf_flat[vox].copy()
                peaks, inds = recspeed.local_maxima(this_odf, faces)
                out_flat[vox][inds] = peaks 

        if self._n_vox == 1:
            return out_flat
        
        out = ozu.nans(self.model_params.shape)
        out[self.mask] = out_flat
        return out
Example #12
0
def test_local_maxima():
    sphere = get_sphere('symmetric724')
    vertices, faces = sphere.vertices, sphere.faces
    edges = unique_edges(faces)

    # Check that the first peak is == max(odf)
    odf = abs(vertices.sum(-1))
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_equal(max(odf), peak_values[0])
    npt.assert_equal(max(odf), odf[peak_index[0]])

    # Create an artificial odf with a few peaks
    odf = np.zeros(len(vertices))
    odf[1] = 1.
    odf[143] = 143.
    odf[505] = 505.
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_values, [505, 143, 1])
    npt.assert_array_equal(peak_index, [505, 143, 1])

    # Check that neighboring points can both be peaks
    odf = np.zeros(len(vertices))
    point1, point2 = edges[0]
    odf[[point1, point2]] = 1.
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_values, [1., 1.])
    npt.assert_(point1 in peak_index)
    npt.assert_(point2 in peak_index)

    # Repeat with a hemisphere
    hemisphere = HemiSphere(xyz=vertices, faces=faces)
    vertices, edges = hemisphere.vertices, hemisphere.edges

    # Check that the first peak is == max(odf)
    odf = abs(vertices.sum(-1))
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_equal(max(odf), peak_values[0])
    npt.assert_equal(max(odf), odf[peak_index[0]])

    # Create an artificial odf with a few peaks
    odf = np.zeros(len(vertices))
    odf[1] = 1.
    odf[143] = 143.
    odf[300] = 300.
    peak_value, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_value, [300, 143, 1])
    npt.assert_array_equal(peak_index, [300, 143, 1])

    # Check that neighboring points can both be peaks
    odf = np.zeros(len(vertices))
    point1, point2 = edges[0]
    odf[[point1, point2]] = 1.
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_values, [1., 1.])
    npt.assert_(point1 in peak_index)
    npt.assert_(point2 in peak_index)

    # Should raise an error if odf has nans
    odf[20] = np.nan
    npt.assert_raises(ValueError, local_maxima, odf, edges)

    # Should raise an error if edge values are too large to index odf
    edges[0, 0] = 9999
    odf[20] = 0
    npt.assert_raises(IndexError, local_maxima, odf, edges)
Example #13
0
def peak_directions(odf, sphere, relative_peak_threshold=.5,
                    min_separation_angle=25, minmax_norm=True):
    """Get the directions of odf peaks.

    Peaks are defined as points on the odf that are greater than at least one
    neighbor and greater than or equal to all neighbors. Peaks are sorted in
    descending order by their values then filtered based on their relative size
    and spacing on the sphere. An odf may have 0 peaks, for example if the odf
    is perfectly isotropic.

    Parameters
    ----------
    odf : 1d ndarray
        The odf function evaluated on the vertices of `sphere`
    sphere : Sphere
        The Sphere providing discrete directions for evaluation.
    relative_peak_threshold : float in [0., 1.]
        Only peaks greater than ``min + relative_peak_threshold * scale`` are
        kept, where ``min = max(0, odf.min())`` and
        ``scale = odf.max() - min``.
    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.

    Returns
    -------
    directions : (N, 3) ndarray
        N vertices for sphere, one for each peak
    values : (N,) ndarray
        peak values
    indices : (N,) ndarray
        peak indices of the directions on the sphere

    Notes
    -----
    If the odf has any negative values, they will be clipped to zeros.

    """
    values, indices = local_maxima(odf, sphere.edges)

    # If there is only one peak return
    n = len(values)
    if n == 0 or (values[0] < 0.):
        return np.zeros((0, 3)), np.zeros(0), np.zeros(0, dtype=int)
    elif n == 1:
        return sphere.vertices[indices], values, indices

    odf_min = np.min(odf)
    odf_min = odf_min if (odf_min >= 0.) else 0.
    # because of the relative threshold this algorithm will give the same peaks
    # as if we divide (values - odf_min) with (odf_max - odf_min) or not so
    # here we skip the division to increase speed
    values_norm = (values - odf_min)

    # Remove small peaks
    n = search_descending(values_norm, relative_peak_threshold)
    indices = indices[:n]
    directions = sphere.vertices[indices]

    # Remove peaks too close together
    directions, uniq = remove_similar_vertices(directions,
                                               min_separation_angle,
                                               return_index=True)
    values = values[uniq]
    indices = indices[uniq]
    return directions, values, indices
Example #14
0
def peak_directions_nl(sphere_eval, relative_peak_threshold=.25,
                       min_separation_angle=25, sphere=default_sphere,
                       xtol=1e-7):
    """Non Linear Direction Finder.

    Parameters
    ----------
    sphere_eval : callable
        A function which can be evaluated on a sphere.
    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.
    sphere : Sphere
        A discrete Sphere. The points on the sphere will be used for initial
        estimate of maximums.
    xtol : float
        Relative tolerance for optimization.

    Returns
    -------
    directions : array (N, 3)
        Points on the sphere corresponding to N local maxima on the sphere.
    values : array (N,)
        Value of sphere_eval at each point on directions.

    """
    # Find discrete peaks for use as seeds in non-linear search
    discrete_values = sphere_eval(sphere)
    values, indices = local_maxima(discrete_values, sphere.edges)

    seeds = np.column_stack([sphere.theta[indices], sphere.phi[indices]])

    # Helper function
    def _helper(x):
        sphere = Sphere(theta=x[0], phi=x[1])
        return -sphere_eval(sphere)

    # Non-linear search
    num_seeds = len(seeds)
    theta = np.empty(num_seeds)
    phi = np.empty(num_seeds)
    for i in xrange(num_seeds):
        peak = opt.fmin(_helper, seeds[i], xtol=xtol, disp=False)
        theta[i], phi[i] = peak

    # Evaluate on new-found peaks
    small_sphere = Sphere(theta=theta, phi=phi)
    values = sphere_eval(small_sphere)

    # Sort in descending order
    order = values.argsort()[::-1]
    values = values[order]
    directions = small_sphere.vertices[order]

    # Remove directions that are too small
    n = search_descending(values, relative_peak_threshold)
    directions = directions[:n]

    # Remove peaks too close to each-other
    directions, idx = remove_similar_vertices(directions, min_separation_angle,
                                              return_index=True)
    values = values[idx]
    return directions, values
Example #15
0
def test_local_maxima():
    sphere = default_sphere
    vertices, faces = sphere.vertices, sphere.faces
    edges = unique_edges(faces)

    # Check that the first peak is == max(odf)
    odf = abs(vertices.sum(-1))
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_equal(max(odf), peak_values[0])
    npt.assert_equal(max(odf), odf[peak_index[0]])

    # Create an artificial odf with a few peaks
    odf = np.zeros(len(vertices))
    odf[1] = 1.
    odf[143] = 143.
    odf[361] = 361.
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_values, [361, 143, 1])
    npt.assert_array_equal(peak_index, [361, 143, 1])

    # Check that neighboring points can both be peaks
    odf = np.zeros(len(vertices))
    point1, point2 = edges[0]
    odf[[point1, point2]] = 1.
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_values, [1., 1.])
    npt.assert_(point1 in peak_index)
    npt.assert_(point2 in peak_index)

    # Repeat with a hemisphere
    hemisphere = HemiSphere(xyz=vertices, faces=faces)
    vertices, edges = hemisphere.vertices, hemisphere.edges

    # Check that the first peak is == max(odf)
    odf = abs(vertices.sum(-1))
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_equal(max(odf), peak_values[0])
    npt.assert_equal(max(odf), odf[peak_index[0]])

    # Create an artificial odf with a few peaks
    odf = np.zeros(len(vertices))
    odf[1] = 1.
    odf[143] = 143.
    odf[300] = 300.
    peak_value, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_value, [300, 143, 1])
    npt.assert_array_equal(peak_index, [300, 143, 1])

    # Check that neighboring points can both be peaks
    odf = np.zeros(len(vertices))
    point1, point2 = edges[0]
    odf[[point1, point2]] = 1.
    peak_values, peak_index = local_maxima(odf, edges)
    npt.assert_array_equal(peak_values, [1., 1.])
    npt.assert_(point1 in peak_index)
    npt.assert_(point2 in peak_index)

    # Should raise an error if odf has nans
    odf[20] = np.nan
    npt.assert_raises(ValueError, local_maxima, odf, edges)

    # Should raise an error if edge values are too large to index odf
    edges[0, 0] = 9999
    odf[20] = 0
    npt.assert_raises(IndexError, local_maxima, odf, edges)
Example #16
0
def peak_directions_nl(sphere_eval,
                       relative_peak_threshold=.25,
                       min_separation_angle=25,
                       sphere=default_sphere,
                       xtol=1e-7):
    """Non Linear Direction Finder

    Parameters
    ----------
    sphere_eval : callable
        A function which can be evaluated on a sphere.
    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.
    sphere : Sphere
        A discrete Sphere. The points on the sphere will be used for initial
        estimate of maximums.
    xtol : float
        Relative tolerance for optimization.

    Returns
    -------
    directions : array (N, 3)
        Points on the sphere corresponding to N local maxima on the sphere.
    values : array (N,)
        Value of sphere_eval at each point on directions.

    """
    # Find discrete peaks for use as seeds in non-linear search
    discrete_values = sphere_eval(sphere)
    values, indices = local_maxima(discrete_values, sphere.edges)

    seeds = np.column_stack([sphere.theta[indices], sphere.phi[indices]])

    # Helper function
    def _helper(x):
        sphere = Sphere(theta=x[0], phi=x[1])
        return -sphere_eval(sphere)

    # Non-linear search
    num_seeds = len(seeds)
    theta = np.empty(num_seeds)
    phi = np.empty(num_seeds)
    for i in xrange(num_seeds):
        peak = opt.fmin(_helper, seeds[i], xtol=xtol, disp=False)
        theta[i], phi[i] = peak

    # Evaluate on new-found peaks
    small_sphere = Sphere(theta=theta, phi=phi)
    values = sphere_eval(small_sphere)

    # Sort in descending order
    order = values.argsort()[::-1]
    values = values[order]
    directions = small_sphere.vertices[order]

    # Remove directions that are too small
    n = search_descending(values, relative_peak_threshold)
    directions = directions[:n]

    # Remove peaks too close to each-other
    directions, idx = remove_similar_vertices(directions,
                                              min_separation_angle,
                                              return_index=True)
    values = values[idx]
    return directions, values
Example #17
0
def peak_directions(odf,
                    sphere,
                    relative_peak_threshold=.5,
                    min_separation_angle=25,
                    minmax_norm=True):
    """Get the directions of odf peaks

    Peaks are defined as points on the odf that are greater than at least one
    neighbor and greater than or equal to all neighbors. Peaks are sorted in
    descending order by their values then filtered based on their relative size
    and spacing on the sphere. An odf may have 0 peaks, for example if the odf
    is perfectly isotropic.

    Parameters
    ----------
    odf : 1d ndarray
        The odf function evaluated on the vertices of `sphere`
    sphere : Sphere
        The Sphere providing discrete directions for evaluation.
    relative_peak_threshold : float in [0., 1.]
        Only peaks greater than ``min + relative_peak_threshold * scale`` are
        kept, where ``min = max(0, odf.min())`` and
        ``scale = odf.max() - min``.
    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.

    Returns
    -------
    directions : (N, 3) ndarray
        N vertices for sphere, one for each peak
    values : (N,) ndarray
        peak values
    indices : (N,) ndarray
        peak indices of the directions on the sphere

    Notes
    -----
    If the odf has any negative values, they will be clipped to zeros.

    """
    values, indices = local_maxima(odf, sphere.edges)

    # If there is only one peak return
    n = len(values)
    if n == 0 or (values[0] < 0.):
        return np.zeros((0, 3)), np.zeros(0), np.zeros(0, dtype=int)
    elif n == 1:
        return sphere.vertices[indices], values, indices

    odf_min = odf.min()
    odf_min = odf_min if (odf_min >= 0.) else 0.
    # because of the relative threshold this algorithm will give the same peaks
    # as if we divide (values - odf_min) with (odf_max - odf_min) or not so
    # here we skip the division to increase speed
    values_norm = (values - odf_min)

    # Remove small peaks
    n = search_descending(values_norm, relative_peak_threshold)
    indices = indices[:n]
    directions = sphere.vertices[indices]

    # Remove peaks too close together
    directions, uniq = remove_similar_vertices(directions,
                                               min_separation_angle,
                                               return_index=True)
    values = values[uniq]
    indices = indices[uniq]
    return directions, values, indices
Example #18
0
def find_dominant_fibers_dipy_way(sph, f_n, min_angle, n_fib, peak_thr=.25, optimize=False, Psi= None, opt_tol=1e-7):
    
    if optimize:
        
        v = sph.vertices
        
        '''values, indices = local_maxima(f_n, sph.edges)
        directions= v[indices,:]
        
        order = values.argsort()[::-1]
        values = values[order]
        directions = directions[order]
        
        directions, idx = remove_similar_vertices(directions, 25,
                                                  return_index=True)
        values = values[idx]
        directions= directions.T
        
        seeds = directions
        
        def SHORE_ODF_f(x):
            fx= np.dot(Psi, x)
            return -fx
        
        num_seeds = seeds.shape[1]
        theta = np.empty(num_seeds)
        phi = np.empty(num_seeds)
        values = np.empty(num_seeds)
        for i in range(num_seeds):
            peak = opt.fmin(SHORE_ODF_f, seeds[:,i], xtol=opt_tol, disp=False)
            theta[i], phi[i] = peak
            
        # Evaluate on new-found peaks
        small_sphere = Sphere(theta=theta, phi=phi)
        values = sphere_eval(small_sphere)
    
        # Sort in descending order
        order = values.argsort()[::-1]
        values = values[order]
        directions = small_sphere.vertices[order]
    
        # Remove directions that are too small
        n = search_descending(values, relative_peak_threshold)
        directions = directions[:n]
    
        # Remove peaks too close to each-other
        directions, idx = remove_similar_vertices(directions, min_separation_angle,
                                                  return_index=True)
        values = values[idx]'''
        
    else:
        
        v = sph.vertices
        
        values, indices = local_maxima(f_n, sph.edges)
        directions= v[indices,:]
        
        order = values.argsort()[::-1]
        values = values[order]
        directions = directions[order]
        
        directions, idx = remove_similar_vertices(directions, min_angle,
                                                  return_index=True)
        values = values[idx]
        directions= directions.T
        
    return directions, values