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
def test_remove_similar_peaks(): vertices = np.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.], [1.1, 1., 0.], [0., 2., 1.], [2., 1., 0.], [1., 0., 0.]]) norms = np.sqrt((vertices*vertices).sum(-1)) vertices = vertices/norms[:, None] # Return unique vertices uv = remove_similar_vertices(vertices, .01) npt.assert_array_equal(uv, vertices[:6]) # Return vertices with mapping and indices uv, mapping, index = remove_similar_vertices(vertices, .01, return_mapping=True, return_index=True) npt.assert_array_equal(uv, vertices[:6]) npt.assert_array_equal(mapping, list(range(6)) + [0]) npt.assert_array_equal(index, range(6)) # Test mapping with different angles uv, mapping = remove_similar_vertices(vertices, .01, return_mapping=True) npt.assert_array_equal(uv, vertices[:6]) npt.assert_array_equal(mapping, list(range(6)) + [0]) uv, mapping = remove_similar_vertices(vertices, 30, return_mapping=True) npt.assert_array_equal(uv, vertices[:4]) npt.assert_array_equal(mapping, list(range(4)) + [1, 0, 0]) uv, mapping = remove_similar_vertices(vertices, 60, return_mapping=True) npt.assert_array_equal(uv, vertices[:3]) npt.assert_array_equal(mapping, list(range(3)) + [0, 1, 0, 0]) # Test index with different angles uv, index = remove_similar_vertices(vertices, .01, return_index=True) npt.assert_array_equal(uv, vertices[:6]) npt.assert_array_equal(index, range(6)) uv, index = remove_similar_vertices(vertices, 30, return_index=True) npt.assert_array_equal(uv, vertices[:4]) npt.assert_array_equal(index, range(4)) uv, index = remove_similar_vertices(vertices, 60, return_index=True) npt.assert_array_equal(uv, vertices[:3]) npt.assert_array_equal(index, range(3))
def __init__(self, x=None, y=None, z=None, theta=None, phi=None, xyz=None, faces=None, edges=None, tol=1e-5): """Create a HemiSphere from points""" sphere = Sphere(x=x, y=y, z=z, theta=theta, phi=phi, xyz=xyz) uniq_vertices, mapping = remove_similar_vertices(sphere.vertices, tol, return_mapping=True) uniq_vertices *= 1 - 2*(uniq_vertices[:, -1:] < 0) if faces is not None: faces = np.asarray(faces) faces = unique_sets(mapping[faces]) if edges is not None: edges = np.asarray(edges) edges = unique_sets(mapping[edges]) Sphere.__init__(self, xyz=uniq_vertices, edges=edges, faces=faces)
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
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
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
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
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