mirror of
https://github.com/wassname/scikit-image.git
synced 2026-06-29 01:59:36 +08:00
110 lines
3.8 KiB
Cython
110 lines
3.8 KiB
Cython
"""watershed.pyx - scithon implementation of guts of watershed
|
|
|
|
Originally part of CellProfiler, code licensed under both GPL and BSD licenses.
|
|
Website: http://www.cellprofiler.org
|
|
|
|
Copyright (c) 2003-2009 Massachusetts Institute of Technology
|
|
Copyright (c) 2009-2011 Broad Institute
|
|
All rights reserved.
|
|
|
|
Original author: Lee Kamentsky
|
|
"""
|
|
|
|
cdef extern from "numpy/arrayobject.h":
|
|
cdef void import_array()
|
|
import_array()
|
|
|
|
import numpy as np
|
|
cimport numpy as np
|
|
cimport cython
|
|
|
|
DTYPE_INT32 = np.int32
|
|
ctypedef np.int32_t DTYPE_INT32_t
|
|
DTYPE_BOOL = np.bool
|
|
ctypedef np.int8_t DTYPE_BOOL_t
|
|
|
|
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,
|
|
DTYPE_INT32_t age,
|
|
np.ndarray[DTYPE_INT32_t, ndim=2, negative_indices=False,
|
|
mode='c'] structure,
|
|
DTYPE_INT32_t ndim,
|
|
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'] image_shape,
|
|
np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
|
|
mode='c'] output):
|
|
"""Do heavy lifting of watershed algorithm
|
|
|
|
Parameters
|
|
----------
|
|
|
|
image - the flattened image pixels, converted to rank-order
|
|
pq - the priority queue, starts with the marked pixels
|
|
the first element in each row is the image intensity
|
|
the second element is the age at entry into the queue
|
|
the third element is the index into the flattened image or labels
|
|
the remaining elements are the coordinates of the point
|
|
age - the next age to assign to a pixel
|
|
structure - a numpy int32 array containing the structuring elements
|
|
that define nearest neighbors. For each row, the first
|
|
element is the stride from the point to its neighbor
|
|
in a flattened array. The remaining elements are the
|
|
offsets from the point to its neighbor in the various
|
|
dimensions
|
|
ndim - # of dimensions in the image
|
|
mask - numpy boolean (char) array indicating which pixels to consider
|
|
and which to ignore. Also flattened.
|
|
image_shape - the dimensions of the image, for boundary checking,
|
|
a numpy array of np.int32
|
|
output - put the image labels in here
|
|
"""
|
|
cdef Heapitem elem
|
|
cdef Heapitem new_elem
|
|
cdef DTYPE_INT32_t nneighbors = structure.shape[0]
|
|
cdef DTYPE_INT32_t i = 0
|
|
cdef DTYPE_INT32_t index = 0
|
|
cdef DTYPE_INT32_t old_index = 0
|
|
cdef DTYPE_INT32_t max_index = image.shape[0]
|
|
|
|
cdef Heap *hp = <Heap *> heap_from_numpy2()
|
|
|
|
for i in range(pq.shape[0]):
|
|
elem.value = pq[i, 0]
|
|
elem.age = pq[i, 1]
|
|
elem.index = pq[i, 2]
|
|
heappush(hp, &elem)
|
|
|
|
while hp.items > 0:
|
|
#
|
|
# Pop off an item to work on
|
|
#
|
|
heappop(hp, &elem)
|
|
####################################################
|
|
# loop through each of the structuring elements
|
|
#
|
|
old_index = elem.index
|
|
for i in range(nneighbors):
|
|
# get the flattened address of the neighbor
|
|
index = structure[i, 0] + old_index
|
|
if index < 0 or index >= max_index or output[index] or \
|
|
not mask[index]:
|
|
continue
|
|
|
|
new_elem.value = image[index]
|
|
new_elem.age = elem.age + 1
|
|
new_elem.index = index
|
|
age += 1
|
|
output[index] = output[old_index]
|
|
#
|
|
# Push the neighbor onto the heap to work on it later
|
|
#
|
|
heappush(hp, &new_elem)
|
|
heap_done(hp)
|