scikit-image
141 строка · 4.8 Кб
1#cython: cdivision=True
2#cython: boundscheck=False
3#cython: nonecheck=False
4#cython: wraparound=False
5
6"""Cython code used in _flood_fill.py."""
7
8cimport numpy as cnp
9cnp.import_array()
10
11# Must be defined to use QueueWithHistory
12ctypedef Py_ssize_t QueueItem
13
14include "../morphology/_queue_with_history.pxi"
15
16
17ctypedef fused dtype_t:
18cnp.uint8_t
19cnp.uint16_t
20cnp.uint32_t
21cnp.uint64_t
22cnp.int8_t
23cnp.int16_t
24cnp.int32_t
25cnp.int64_t
26cnp.float32_t
27cnp.float64_t
28
29
30# Definition of flag values used for `flags` in _flood_fill & _fill_plateau
31cdef:
32# Border value - do not cross!
33unsigned char BORDER = 2
34# Part of the flood fill
35unsigned char FILL = 1
36# Not checked yet
37unsigned char UNKNOWN = 0
38
39
40cpdef inline void _flood_fill_equal(dtype_t[::1] image,
41unsigned char[::1] flags,
42Py_ssize_t[::1] neighbor_offsets,
43Py_ssize_t start_index,
44dtype_t seed_value):
45"""Find connected areas to fill, requiring strict equality.
46
47Parameters
48----------
49image : ndarray, one-dimensional
50The raveled view of a n-dimensional array.
51flags : ndarray, one-dimensional
52An array of flags that is used to store the state of each pixel during
53evaluation.
54neighbor_offsets : ndarray
55A one-dimensional array that contains the offsets to find the
56connected neighbors for any index in `image`.
57start_index : int
58Start position for the flood-fill.
59seed_value :
60Value of ``image[start_index]``.
61"""
62cdef:
63QueueWithHistory queue
64QueueItem current_index, neighbor
65
66with nogil:
67# Initialize the queue
68queue_init(&queue, 64)
69try:
70queue_push(&queue, &start_index)
71flags[start_index] = FILL
72# Break loop if all queued positions were evaluated
73while queue_pop(&queue, ¤t_index):
74# Look at all neighboring samples
75for i in range(neighbor_offsets.shape[0]):
76neighbor = current_index + neighbor_offsets[i]
77
78# Shortcut if neighbor is already part of fill
79if flags[neighbor] == UNKNOWN:
80if image[neighbor] == seed_value:
81# Neighbor is in fill; check its neighbors too.
82flags[neighbor] = FILL
83queue_push(&queue, &neighbor)
84finally:
85# Ensure memory released
86queue_exit(&queue)
87
88
89cpdef inline void _flood_fill_tolerance(dtype_t[::1] image,
90unsigned char[::1] flags,
91Py_ssize_t[::1] neighbor_offsets,
92Py_ssize_t start_index,
93dtype_t seed_value,
94dtype_t low_tol,
95dtype_t high_tol):
96"""Find connected areas to fill, within a tolerance.
97
98Parameters
99----------
100image : ndarray, one-dimensional
101The raveled view of a n-dimensional array.
102flags : ndarray, one-dimensional
103An array of flags that is used to store the state of each pixel during
104evaluation.
105neighbor_offsets : ndarray
106A one-dimensional array that contains the offsets to find the
107connected neighbors for any index in `image`.
108start_index : int
109Start position for the flood-fill.
110seed_value :
111Value of ``image[start_index]``.
112low_tol :
113Lower limit for tolerance comparison.
114high_tol :
115Upper limit for tolerance comparison.
116"""
117cdef:
118QueueWithHistory queue
119QueueItem current_index, neighbor
120
121with nogil:
122# Initialize the queue and push start position
123queue_init(&queue, 64)
124try:
125queue_push(&queue, &start_index)
126flags[start_index] = FILL
127# Break loop if all queued positions were evaluated
128while queue_pop(&queue, ¤t_index):
129# Look at all neighboring samples
130for i in range(neighbor_offsets.shape[0]):
131neighbor = current_index + neighbor_offsets[i]
132
133# Only do comparisons on points not (yet) part of fill
134if flags[neighbor] == UNKNOWN:
135if low_tol <= image[neighbor] <= high_tol:
136# Neighbor is in fill; check its neighbors too.
137flags[neighbor] = FILL
138queue_push(&queue, &neighbor)
139finally:
140# Ensure memory released
141queue_exit(&queue)
142