def non_traversing_segments(a): """Find segments that enter the volume but do not leave it elsewhere. Parameters ---------- a : array of int A segmented volume. Returns ------- nt : 1D array of int The IDs of any segments not traversing the volume. Examples -------- >>> segs = np.array([[1, 2, 3, 3, 4], ... [1, 2, 2, 3, 4], ... [1, 5, 5, 3, 4], ... [1, 1, 5, 3, 4]], int) >>> non_traversing_segments(segs) array([1, 2, 4, 5]) """ surface = hollowed(a) surface_ccs = measure.label(surface) + 1 surface_ccs[surface == 0] = 0 idxs = flatnonzero(surface) pairs = np.array( list(zip(surface.ravel()[idxs], surface_ccs.ravel()[idxs]))) unique_pairs = util.unique_rows(pairs) surface_singles = np.bincount(unique_pairs[:, 0]) == 1 nt = np.flatnonzero(surface_singles) return nt
def non_traversing_segments(a): """Find segments that enter the volume but do not leave it elsewhere. Parameters ---------- a : array of int A segmented volume. Returns ------- nt : 1D array of int The IDs of any segments not traversing the volume. Examples -------- >>> segs = np.array([[1, 2, 3, 3, 4], ... [1, 2, 2, 3, 4], ... [1, 5, 5, 3, 4], ... [1, 1, 5, 3, 4]], int) >>> non_traversing_segments(segs) array([1, 2, 4, 5]) """ surface = hollowed(a) surface_ccs = measure.label(surface) + 1 surface_ccs[surface == 0] = 0 idxs = flatnonzero(surface) pairs = np.array(list(zip(surface.ravel()[idxs], surface_ccs.ravel()[idxs]))) unique_pairs = util.unique_rows(pairs) surface_singles = np.bincount(unique_pairs[:, 0]) == 1 nt = np.flatnonzero(surface_singles) return nt
def nuclei_per_cell_histogram(nuc_im, cell_im, max_value=10): """Compute the histogram of nucleus count per cell object. Counts above or below max_value and min_value are clipped. Parameters ---------- nuc_im : array of bool or int An image of nucleus objects, binary or labelled. cell_im : array of bool or int An image of cell objects, binary or labelled. max_value : int, optional The highest nucleus count we expect. Anything above this will be clipped to ``max_value + 1``. Returns ------- fs : array of float, shape ``(max_value - min_value + 2,)``. The proportion of cells with each nucleus counts. names : list of string, same length as fs The name of each feature. """ names = [('cells-with-%i-nuclei' % n) for n in range(max_value + 1)] names.append('cells-with->%i-nuclei' % max_value) nuc_lab = nd.label(nuc_im)[0] cell_lab = nd.label(cell_im)[0] match = np.vstack((nuc_lab.ravel(), cell_lab.ravel())).T match = match[(match.sum(axis=1) != 0), :] match = util.unique_rows(match).astype(np.int64) # number of nuclei in each cell cells = np.bincount(match[:, 1]) # number of cells with x nuclei nhist = np.bincount(cells, minlength=max_value + 2) total = np.sum(nhist) fs = np.zeros((max_value + 2), np.float) fs[:(max_value + 1)] = nhist[:(max_value + 1)] fs[max_value + 1] = np.sum(nhist[(max_value + 1):]) fs /= total return fs, names
def test_discontiguous_array(): ar = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]], np.uint8) ar = ar[::2] ar_out = unique_rows(ar) desired_ar_out = np.array([[1, 0, 1]], np.uint8) assert_equal(ar_out, desired_ar_out)
def test_float_array(): ar = np.array([[1.1, 0.0, 1.1], [0.0, 1.1, 0.0], [1.1, 0.0, 1.1]], np.float) ar_out = unique_rows(ar) desired_ar_out = np.array([[0.0, 1.1, 0.0], [1.1, 0.0, 1.1]], np.float) assert_equal(ar_out, desired_ar_out)
def test_uint8_array(): ar = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]], np.uint8) ar_out = unique_rows(ar) desired_ar_out = np.array([[0, 1, 0], [1, 0, 1]], np.uint8) assert_equal(ar_out, desired_ar_out)
def convex_hull_image(image): """Compute the convex hull image of a binary image. The convex hull is the set of pixels included in the smallest convex polygon that surround all white pixels in the input image. Parameters ---------- image : ndarray Binary input image. This array is cast to bool before processing. Returns ------- hull : ndarray of bool Binary image with pixels in convex hull set to True. References ---------- .. [1] http://blogs.mathworks.com/steve/2011/10/04/binary-image-convex-hull-algorithm-notes/ """ image = image.astype(bool) # Here we do an optimisation by choosing only pixels that are # the starting or ending pixel of a row or column. This vastly # limits the number of coordinates to examine for the virtual # hull. coords = possible_hull(image.astype(np.uint8)) N = len(coords) # Add a vertex for the middle of each pixel edge coords_corners = np.empty((N * 4, 2)) for i, (x_offset, y_offset) in enumerate(zip((0, 0, -0.5, 0.5), (-0.5, 0.5, 0, 0))): coords_corners[i * N:(i + 1) * N] = coords + [x_offset, y_offset] # repeated coordinates can *sometimes* cause problems in # scipy.spatial.Delaunay, so we remove them. coords = unique_rows(coords_corners) try: from scipy.spatial import Delaunay except ImportError: raise ImportError('Could not import scipy.spatial, only available in ' 'scipy >= 0.9.') # Find the convex hull chull = Delaunay(coords).convex_hull v = coords[np.unique(chull)] # Sort vertices clock-wise v_centred = v - v.mean(axis=0) angles = np.arctan2(v_centred[:, 0], v_centred[:, 1]) v = v[np.argsort(angles)] # For each pixel coordinate, check whether that pixel # lies inside the convex hull mask = grid_points_inside_poly(image.shape[:2], v) return mask
def convex_hull_image(image): """Compute the convex hull image of a binary image. The convex hull is the set of pixels included in the smallest convex polygon that surround all white pixels in the input image. Parameters ---------- image : ndarray Binary input image. This array is cast to bool before processing. Returns ------- hull : ndarray of bool Binary image with pixels in convex hull set to True. References ---------- .. [1] http://blogs.mathworks.com/steve/2011/10/04/binary-image-convex-hull-algorithm-notes/ """ image = image.astype(bool) # Here we do an optimisation by choosing only pixels that are # the starting or ending pixel of a row or column. This vastly # limits the number of coordinates to examine for the virtual # hull. coords = possible_hull(image.astype(np.uint8)) N = len(coords) # Add a vertex for the middle of each pixel edge coords_corners = np.empty((N * 4, 2)) for i, (x_offset, y_offset) in enumerate(zip((0, 0, -0.5, 0.5), (-0.5, 0.5, 0, 0))): coords_corners[i * N:(i + 1) * N] = coords + [x_offset, y_offset] # repeated coordinates can *sometimes* cause problems in # scipy.spatial.Delaunay, so we remove them. coords = unique_rows(coords_corners) try: from scipy.spatial import Delaunay except ImportError: raise ImportError('Could not import scipy.spatial, only available in ' 'scipy >= 0.9.') # Subtract offset offset = coords.mean(axis=0) coords -= offset # Find the convex hull chull = Delaunay(coords).convex_hull v = coords[np.unique(chull)] # Sort vertices clock-wise v_centred = v - v.mean(axis=0) angles = np.arctan2(v_centred[:, 0], v_centred[:, 1]) v = v[np.argsort(angles)] # Add back offset v += offset # For each pixel coordinate, check whether that pixel # lies inside the convex hull mask = grid_points_inside_poly(image.shape[:2], v) return mask
def test_3d_array(): ar = np.arange(8).reshape((2, 2, 2)) with pytest.raises(ValueError): unique_rows(ar)
def test_1d_array(): ar = np.array([1, 0, 1, 1], np.uint8) with pytest.raises(ValueError): unique_rows(ar)
def test_3d_array(): ar = np.arange(8).reshape((2, 2, 2)) with testing.raises(ValueError): unique_rows(ar)
def test_1d_array(): ar = np.array([1, 0, 1, 1], np.uint8) with testing.raises(ValueError): unique_rows(ar)