mirror of
https://github.com/wassname/scikit-image.git
synced 2026-08-10 12:40:08 +08:00
Use typed memoryviews in morphology package
This commit is contained in:
@@ -7,7 +7,7 @@ import numpy as np
|
||||
cimport numpy as cnp
|
||||
|
||||
|
||||
def possible_hull(cnp.ndarray[dtype=cnp.uint8_t, ndim=2, mode="c"] img):
|
||||
def possible_hull(cnp.uint8_t[:, ::1] img):
|
||||
"""Return positions of pixels that possibly belong to the convex hull.
|
||||
|
||||
Parameters
|
||||
@@ -30,31 +30,43 @@ def possible_hull(cnp.ndarray[dtype=cnp.uint8_t, ndim=2, mode="c"] img):
|
||||
# cols storage slots for top boundary pixels
|
||||
# rows storage slots for right boundary pixels
|
||||
# cols storage slots for bottom boundary pixels
|
||||
cdef cnp.ndarray[dtype=cnp.intp_t, ndim=2] nonzero = \
|
||||
np.ones((2 * (rows + cols), 2), dtype=np.intp)
|
||||
nonzero *= -1
|
||||
coords = np.ones((2 * (rows + cols), 2), dtype=np.intp)
|
||||
coords *= -1
|
||||
|
||||
cdef Py_ssize_t[:, ::1] nonzero = coords
|
||||
cdef Py_ssize_t rows_cols = rows + cols
|
||||
cdef Py_ssize_t rows_2_cols = 2 * rows + cols
|
||||
cdef Py_ssize_t rows_cols_r, rows_c
|
||||
|
||||
for r in range(rows):
|
||||
|
||||
rows_cols_r = rows_cols + r
|
||||
|
||||
for c in range(cols):
|
||||
|
||||
if img[r, c] != 0:
|
||||
|
||||
rows_c = rows + c
|
||||
rows_2_cols_c = rows_2_cols + c
|
||||
|
||||
# Left check
|
||||
if nonzero[r, 1] == -1:
|
||||
nonzero[r, 0] = r
|
||||
nonzero[r, 1] = c
|
||||
|
||||
# Right check
|
||||
elif nonzero[rows + cols + r, 1] < c:
|
||||
nonzero[rows + cols + r, 0] = r
|
||||
nonzero[rows + cols + r, 1] = c
|
||||
elif nonzero[rows_cols_r, 1] < c:
|
||||
nonzero[rows_cols_r, 0] = r
|
||||
nonzero[rows_cols_r, 1] = c
|
||||
|
||||
# Top check
|
||||
if nonzero[rows + c, 1] == -1:
|
||||
nonzero[rows + c, 0] = r
|
||||
nonzero[rows + c, 1] = c
|
||||
if nonzero[rows_c, 1] == -1:
|
||||
nonzero[rows_c, 0] = r
|
||||
nonzero[rows_c, 1] = c
|
||||
|
||||
# Bottom check
|
||||
elif nonzero[2 * rows + cols + c, 0] < r:
|
||||
nonzero[2 * rows + cols + c, 0] = r
|
||||
nonzero[2 * rows + cols + c, 1] = c
|
||||
elif nonzero[rows_2_cols_c, 0] < r:
|
||||
nonzero[rows_2_cols_c, 0] = r
|
||||
nonzero[rows_2_cols_c, 1] = c
|
||||
|
||||
return nonzero[nonzero[:, 0] != -1]
|
||||
return coords[coords[:, 0] != -1]
|
||||
|
||||
@@ -21,8 +21,8 @@ def reconstruction_loop(cnp.ndarray[dtype=cnp.uint32_t, ndim=1,
|
||||
negative_indices=False, mode='c'] anext,
|
||||
cnp.ndarray[dtype=cnp.int32_t, ndim=1,
|
||||
negative_indices=False, mode='c'] astrides,
|
||||
int current_idx,
|
||||
int image_stride):
|
||||
Py_ssize_t current_idx,
|
||||
Py_ssize_t image_stride):
|
||||
"""The inner loop for reconstruction.
|
||||
|
||||
This algorithm uses the rank-order of pixels. If low intensity pixels have
|
||||
|
||||
@@ -29,7 +29,7 @@ def grid_points_inside_poly(shape, verts):
|
||||
True where the grid falls inside the polygon.
|
||||
|
||||
"""
|
||||
cdef cnp.ndarray[cnp.double_t, ndim=1, mode="c"] vx, vy
|
||||
cdef double[:] vx, vy
|
||||
verts = np.asarray(verts)
|
||||
|
||||
vx = verts[:, 0].astype(np.double)
|
||||
@@ -45,8 +45,7 @@ def grid_points_inside_poly(shape, verts):
|
||||
|
||||
for m in range(M):
|
||||
for n in range(N):
|
||||
out[m, n] = point_in_polygon(V, <double*>vx.data, <double*>vy.data,
|
||||
m, n)
|
||||
out[m, n] = point_in_polygon(V, &vx[0], &vy[0], m, n)
|
||||
|
||||
return out.view(bool)
|
||||
|
||||
@@ -57,18 +56,18 @@ def points_inside_poly(points, verts):
|
||||
Parameters
|
||||
----------
|
||||
points : (N, 2) array
|
||||
Input points, ``(x, y)``.
|
||||
Input points, ``(x, y)``.
|
||||
verts : (M, 2) array
|
||||
Vertices of the polygon, sorted either clockwise or anti-clockwise.
|
||||
The first point may (but does not need to be) duplicated.
|
||||
Vertices of the polygon, sorted either clockwise or anti-clockwise.
|
||||
The first point may (but does not need to be) duplicated.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mask : (N,) array of bool
|
||||
True if corresponding point is inside the polygon.
|
||||
True if corresponding point is inside the polygon.
|
||||
|
||||
"""
|
||||
cdef cnp.ndarray[cnp.double_t, ndim=1, mode="c"] x, y, vx, vy
|
||||
cdef double[:] x, y, vx, vy
|
||||
|
||||
points = np.asarray(points)
|
||||
verts = np.asarray(verts)
|
||||
@@ -82,8 +81,8 @@ def points_inside_poly(points, verts):
|
||||
cdef cnp.ndarray[cnp.uint8_t, ndim=1] out = \
|
||||
np.zeros(x.shape[0], dtype=np.uint8)
|
||||
|
||||
points_in_polygon(vx.shape[0], <double*>vx.data, <double*>vy.data,
|
||||
x.shape[0], <double*>x.data, <double*>y.data,
|
||||
points_in_polygon(vx.shape[0], &vx[0], &vy[0],
|
||||
x.shape[0], &x[0], &y[0],
|
||||
<unsigned char*>out.data)
|
||||
|
||||
return out.astype(bool)
|
||||
|
||||
@@ -19,16 +19,9 @@ import numpy as np
|
||||
cimport numpy as cnp
|
||||
|
||||
|
||||
def _skeletonize_loop(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
|
||||
negative_indices=False, mode='c'] result,
|
||||
cnp.ndarray[dtype=cnp.intp_t, ndim=1,
|
||||
negative_indices=False, mode='c'] i,
|
||||
cnp.ndarray[dtype=cnp.intp_t, ndim=1,
|
||||
negative_indices=False, mode='c'] j,
|
||||
cnp.ndarray[dtype=cnp.int32_t, ndim=1,
|
||||
negative_indices=False, mode='c'] order,
|
||||
cnp.ndarray[dtype=cnp.uint8_t, ndim=1,
|
||||
negative_indices=False, mode='c'] table):
|
||||
def _skeletonize_loop(cnp.uint8_t[:, ::1] result,
|
||||
cnp.uint8_t[:] i, cnp.uint8_t[:] j,
|
||||
cnp.int32_t[:] order, cnp.uint8_t[:] table):
|
||||
"""
|
||||
Inner loop of skeletonize function
|
||||
|
||||
@@ -65,9 +58,11 @@ def _skeletonize_loop(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
|
||||
pixels.
|
||||
"""
|
||||
cdef:
|
||||
cnp.int32_t accumulator
|
||||
Py_ssize_t accumulator
|
||||
Py_ssize_t index, order_index
|
||||
Py_ssize_t ii, jj
|
||||
Py_ssize_t rows = result.shape[0]
|
||||
Py_ssize_t cols = result.shape[1]
|
||||
|
||||
for index in range(order.shape[0]):
|
||||
accumulator = 16
|
||||
@@ -80,26 +75,25 @@ def _skeletonize_loop(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
|
||||
accumulator += 1
|
||||
if result[ii - 1, jj]:
|
||||
accumulator += 2
|
||||
if jj < result.shape[1] - 1 and result[ii - 1, jj + 1]:
|
||||
if jj < cols - 1 and result[ii - 1, jj + 1]:
|
||||
accumulator += 4
|
||||
if jj > 0 and result[ii, jj - 1]:
|
||||
accumulator += 8
|
||||
if jj < result.shape[1] - 1 and result[ii, jj + 1]:
|
||||
if jj < cols - 1 and result[ii, jj + 1]:
|
||||
accumulator += 32
|
||||
if ii < result.shape[0]-1:
|
||||
if ii < rows - 1:
|
||||
if jj > 0 and result[ii + 1, jj - 1]:
|
||||
accumulator += 64
|
||||
if result[ii + 1, jj]:
|
||||
accumulator += 128
|
||||
if jj < result.shape[1] - 1 and result[ii + 1, jj + 1]:
|
||||
if jj < cols - 1 and result[ii + 1, jj + 1]:
|
||||
accumulator += 256
|
||||
# Assign the value of table corresponding to the configuration
|
||||
result[ii, jj] = table[accumulator]
|
||||
|
||||
|
||||
|
||||
def _table_lookup_index(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
|
||||
negative_indices=False, mode='c'] image):
|
||||
def _table_lookup_index(cnp.uint8_t[:, ::1] image):
|
||||
"""
|
||||
Return an index into a table per pixel of a binary image
|
||||
|
||||
@@ -120,9 +114,8 @@ def _table_lookup_index(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
|
||||
hardwired kernel.
|
||||
"""
|
||||
cdef:
|
||||
cnp.ndarray[dtype=cnp.int32_t, ndim=2,
|
||||
negative_indices=False, mode='c'] indexer
|
||||
cnp.int32_t *p_indexer
|
||||
Py_ssize_t[:, ::1] indexer
|
||||
Py_ssize_t *p_indexer
|
||||
cnp.uint8_t *p_image
|
||||
Py_ssize_t i_stride
|
||||
Py_ssize_t i_shape
|
||||
@@ -133,9 +126,9 @@ def _table_lookup_index(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
|
||||
|
||||
i_shape = image.shape[0]
|
||||
j_shape = image.shape[1]
|
||||
indexer = np.zeros((i_shape, j_shape), np.int32)
|
||||
p_indexer = <cnp.int32_t *>indexer.data
|
||||
p_image = <cnp.uint8_t *>image.data
|
||||
indexer = np.zeros((i_shape, j_shape), dtype=np.intp)
|
||||
p_indexer = &indexer[0, 0]
|
||||
p_image = &image[0, 0]
|
||||
i_stride = image.strides[0]
|
||||
assert i_shape >= 3 and j_shape >= 3, \
|
||||
"Please use the slow method for arrays < 3x3"
|
||||
|
||||
@@ -23,17 +23,12 @@ include "heap_watershed.pxi"
|
||||
|
||||
|
||||
@cython.boundscheck(False)
|
||||
def watershed(np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
|
||||
mode='c'] image,
|
||||
np.ndarray[DTYPE_INT32_t, ndim=2, negative_indices=False,
|
||||
mode='c'] pq,
|
||||
def watershed(DTYPE_INT32_t[:] image,
|
||||
DTYPE_INT32_t[:, ::1] pq,
|
||||
Py_ssize_t age,
|
||||
np.ndarray[DTYPE_INT32_t, ndim=2, negative_indices=False,
|
||||
mode='c'] structure,
|
||||
np.ndarray[DTYPE_BOOL_t, ndim=1, negative_indices=False,
|
||||
mode='c'] mask,
|
||||
np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
|
||||
mode='c'] output):
|
||||
DTYPE_INT32_t[:, ::1] structure,
|
||||
DTYPE_BOOL_t[:] mask,
|
||||
DTYPE_INT32_t[:] output):
|
||||
"""Do heavy lifting of watershed algorithm
|
||||
|
||||
Parameters
|
||||
|
||||
@@ -8,9 +8,9 @@ cimport numpy as np
|
||||
from libc.stdlib cimport malloc, free
|
||||
|
||||
|
||||
def _dilate(np.ndarray[np.uint8_t, ndim=2] image,
|
||||
np.ndarray[np.uint8_t, ndim=2] selem,
|
||||
np.ndarray[np.uint8_t, ndim=2] out=None,
|
||||
def _dilate(np.uint8_t[:, :] image,
|
||||
np.uint8_t[:, :] selem,
|
||||
np.uint8_t[:, :] out=None,
|
||||
char shift_x=0, char shift_y=0):
|
||||
"""Return greyscale morphological dilation of an image.
|
||||
|
||||
@@ -52,12 +52,9 @@ def _dilate(np.ndarray[np.uint8_t, ndim=2] image,
|
||||
else:
|
||||
out = np.ascontiguousarray(out)
|
||||
|
||||
cdef np.uint8_t* out_data = <np.uint8_t*>out.data
|
||||
cdef np.uint8_t* image_data = <np.uint8_t*>image.data
|
||||
|
||||
cdef Py_ssize_t r, c, rr, cc, s, value, local_max
|
||||
|
||||
cdef Py_ssize_t selem_num = np.sum(selem != 0)
|
||||
cdef Py_ssize_t selem_num = np.sum(np.asarray(selem) != 0)
|
||||
cdef Py_ssize_t* sr = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
|
||||
cdef Py_ssize_t* sc = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
|
||||
|
||||
@@ -76,21 +73,21 @@ def _dilate(np.ndarray[np.uint8_t, ndim=2] image,
|
||||
rr = r + sr[s]
|
||||
cc = c + sc[s]
|
||||
if 0 <= rr < rows and 0 <= cc < cols:
|
||||
value = image_data[rr * cols + cc]
|
||||
value = image[rr, cc]
|
||||
if value > local_max:
|
||||
local_max = value
|
||||
|
||||
out_data[r * cols + c] = local_max
|
||||
out[r, c] = local_max
|
||||
|
||||
free(sr)
|
||||
free(sc)
|
||||
|
||||
return out
|
||||
return np.asarray(out)
|
||||
|
||||
|
||||
def _erode(np.ndarray[np.uint8_t, ndim=2] image,
|
||||
np.ndarray[np.uint8_t, ndim=2] selem,
|
||||
np.ndarray[np.uint8_t, ndim=2] out=None,
|
||||
def _erode(np.uint8_t[:, :] image,
|
||||
np.uint8_t[:, :] selem,
|
||||
np.uint8_t[:, :] out=None,
|
||||
char shift_x=0, char shift_y=0):
|
||||
"""Return greyscale morphological erosion of an image.
|
||||
|
||||
@@ -131,12 +128,9 @@ def _erode(np.ndarray[np.uint8_t, ndim=2] image,
|
||||
else:
|
||||
out = np.ascontiguousarray(out)
|
||||
|
||||
cdef np.uint8_t* out_data = <np.uint8_t*>out.data
|
||||
cdef np.uint8_t* image_data = <np.uint8_t*>image.data
|
||||
|
||||
cdef int r, c, rr, cc, s, value, local_min
|
||||
|
||||
cdef Py_ssize_t selem_num = np.sum(selem != 0)
|
||||
cdef Py_ssize_t selem_num = np.sum(np.asarray(selem) != 0)
|
||||
cdef Py_ssize_t* sr = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
|
||||
cdef Py_ssize_t* sc = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
|
||||
|
||||
@@ -155,13 +149,13 @@ def _erode(np.ndarray[np.uint8_t, ndim=2] image,
|
||||
rr = r + sr[s]
|
||||
cc = c + sc[s]
|
||||
if 0 <= rr < rows and 0 <= cc < cols:
|
||||
value = image_data[rr * cols + cc]
|
||||
value = image[rr, cc]
|
||||
if value < local_min:
|
||||
local_min = value
|
||||
|
||||
out_data[r * cols + c] = local_min
|
||||
out[r, c] = local_min
|
||||
|
||||
free(sr)
|
||||
free(sc)
|
||||
|
||||
return out
|
||||
return np.asarray(out)
|
||||
|
||||
Reference in New Issue
Block a user