18 *args, **kwargs) -> np.array:
20 Applies the function `fn` to a sliding window over the array `arr`.
21 \note Results in the margins (the first and last entries closer than
22 `radius` to the edge of the array in each direction) are not
23 reliable, as they suffer from boundary effects.
24 This is caused by the sliding window only visit "complete" windows.
25 In the margins, the values of the edge is repeated.
26 The padding behavior can be changed with `pad_mode`.
27 \param arr Array of data, over which the window should slide.
28 \param radius Inradius of the window, sets the window's widths.
29 Along an axis, the window has a width of \f$(2r+1)\f$.
30 It is expected to be an `int` a `tuple`.
31 If `radius` is an integer, it is used for all axes.
32 The windows will contain \f$(2r+1)^n\f$ entries.
33 To set indiviual widths along for each dimension, use a `tuple`.
34 This `tuple`'s length has to match the dimension of `arr`.
35 \param fn A function object (type: `callable`), taking a `np.array`
36 as input and returning a `float`.
37 \param pad_mode Mode for padding the edges of the result array.
38 Defaults to `"edge"`, which repeats the result value on the edge.
39 For more, options, see [`numpy.pad()`](https://numpy.org/doc/stable/reference/generated/numpy.pad.html)
40 \param *args Additional positional arguments; ignored.
41 \param **kwargs Additional keyword arguments; ignored.
42 \return Return a `np.array` with the same shape as `arr`.
43 Each entry is the result of applying `fn` to a window reaching
44 `radius` into each direction.
46 pad_mode = pad_mode
if pad_mode
is not None else "edge"
48 radius = misc.np_to_python(radius)
49 if isinstance(radius, int):
50 radius = (radius,)*arr.ndim
52 assert len(radius) == arr.ndim
53 radius = tuple([int(r)
for r
in radius])
54 except AssertionError:
55 raise ValueError(
"Shape of radius ({}) does not match the shape of array ({})".format(radius, arr.ndim))
56 window_size = tuple([int(r * 2 + 1)
for r
in radius])
57 view = np.lib.stride_tricks.sliding_window_view(arr, window_size)
58 axis = tuple(range(-1, -arr.ndim - 1, -1))
if arr.ndim > 1
else -1
59 fn_result = fn(view, axis=axis)
60 pad = np.pad(fn_result, pad_width=radius, mode=pad_mode)
65 Generates a sliding window over an array.
66 This function returns a generator, hence, it should be use like:
68 for pixel, window in sliding(<array>, <radius>):
72 In contrast to other function like
73 [`numpy.lib.stride_tricks.sliding_window_view()`](https://numpy.org/devdocs/reference/generated/numpy.lib.stride_tricks.sliding_window_view.html),
74 this window slides over each pixel, even in the margin areas of `data_array`.
75 So, for each entry in `data_array`, a view to the window surrounding it is yielded.
76 In the margins, the window contains fewer entries.
77 Thus, boundary effects are to be expected, when using this function.
78 \remark Note, that a views of the original array are yielded, not copies.
79 Changing a pixel's value in the window will change the original array.
80 \param data_array Array of data, over which the window should slide.
81 \param radius Inradius of the window, sets the window's widths.
82 Along an axis, the window has a width of \f$(2r+1)\f$.
83 It is expected to be an `int` or `iterable`.
84 If `radius` is an integer, it is used for all axes.
85 The window will contain (up to) \f$(2r+1)^2\f$ entries.
86 To set different widths for axes, use an `iterable`, such as a `tuple`.
87 This `tuple`'s length has to match the dimension of `data_array`.
88 \return In each iteration, a tuple like `(pixel, window)` is yielded.
89 \retval pixel Index of the window's central pixel in `data_array`.
90 \retval window Sub-array view of the `data_array` centered around `pixel`.
92 data_array = np.array(data_array)
93 radius = misc.np_to_python(radius)
95 assert len(radius) == data_array.ndim
96 radius = tuple(radius)
98 radius = (radius,)*data_array.ndim
99 except AssertionError:
100 raise ValueError(
"Shape of radius ({}) does not match the shape of array ({})".format(len(radius), data_array.ndim))
101 if isinstance(radius, int):
102 radius = (radius,)*data_array.ndim
103 iterator = np.nditer(data_array, flags=[
"multi_index"])
104 for pixel_value
in iterator:
105 pixel = iterator.multi_index
106 slices = tuple(slice(max(p-r, 0), min(p+r+1, z+1))
for p, r, z
in zip(pixel, radius, data_array.shape))
107 yield pixel, data_array[slices]
111 start_pixel: tuple =
None,
112 step_size: tuple =
None,
115 Generates a symmetric moving window over an array.
116 This function returns a generator that yields information about the window_center_orig, target_pixel, and the content of the window.
117 Converts data_array to a Numpy array. Ensuring radius as a tuple. do this similar for stepsize and the start pixel
118 (start pixel if not given equal to radius). Determine orig_index_lists based on array dimensions and provided indices.
119 It generates combinations of indices. It iterates over combinations and yields window information.
120 \param data_array Array of data over which the window should move.
121 \param radius Inradius of the window's rectangle.
122 If `radius` is an `int`, all axes will use this radius and the
124 For non-square windows, pass a tuple with a radius for each
125 dimension of `data_array`.
126 Along an axis, the window has a width of \f$2r + 1\f$ for each
127 element \f$r\f$ of `radius`.
128 \param start_pixel Index of the first window's central pixel.
129 If `start_pixel` is an `int`, it is used for all dimensions of `data_array`.
130 To specify a custom starting element, pass a tuple with a step
131 size for each dimension of `data_array`.
132 If `None`, it defaults to `radius`, the moving window starts with
134 \param step_size Step size how far the window moves in one step.
135 If `step_size` is an `int`, it is used for all dimensions of `data_array`.
136 If `None`, it defaults to \f$2r + 1\f$ for each element \f$r\f$
137 of `radius`, which is equivalent to a rolling window.
138 \return Generator yielding in each iteration a tuple like
139 `(orig_pixel, target_pixel, window_content)`.
140 \retval orig_pixel Index of the window's center in `data_array`.
141 \retval target_pixel Index of the entry in a new array, in which the
142 aggregated result is to be stored.
143 \retval window_content A view of the `data_array`, around the `orig_pixel`.
146 data_array, radius, start_pixel, step_size
148 orig_index_lists, radius, start_pixel, step_size = moving_params
150 orig_index_combinations = list(itertools.product(*orig_index_lists))
152 target_pixels = itertools.product(*(range(len(x))
for x
in orig_index_lists))
154 for (orig_pixel, target_pixel)
in zip(orig_index_combinations, target_pixels):
155 window_content = data_array[tuple(slice(max(0, i - r), min(s, i + r + 1))
for i, r, s
in zip(orig_pixel, radius, data_array.shape))]
156 yield orig_pixel, target_pixel, window_content
159 data_array: np.array,
161 start_pixel: tuple =
None,
162 step_size: tuple =
None,
165 Generate indices for a moving window and check the other parameters.
166 \param data_array Array of data over which the window should move.
167 \param radius Inradius of the window's rectangle.
168 If `radius` is an `int`, all axes will use this radius and the
170 For non-square windows, pass a tuple with a radius for each
171 dimension of `data_array`.
172 Along an axis, the window has a width of \f$2r + 1\f$ for each
173 element \f$r\f$ of `radius`.
174 \param start_pixel Index of the first window's central pixel.
175 If `start_pixel` is an `int`, it is used for all dimensions of `data_array`.
176 To specify a custom starting element, pass a tuple with a step
177 size for each dimension of `data_array`.
178 If `None`, it defaults to `radius`, the moving window starts with
180 \param step_size Step size for estimation.
181 If `step_size` is an `int`, it is used for all dimensions of `data_array`.
182 If `None`, it defaults to \f$2r + 1\f$ for each element \f$r\f$
183 of `radius`, which is equivalent to a rolling window.
184 \return Retuns a tuple like `(orig_index_lists, radius, start_pixel, step_size)`:
185 \retval orig_index_lists List of lists, containing the indices along each axis.
186 \retval radius A tuple, see above.
187 \retval start_pixel A tuple, see above.
188 \retval step_size A tuple, see above.
191 data_array = np.array(data_array)
192 radius = misc.np_to_python(radius)
193 start_pixel = misc.np_to_python(start_pixel)
194 step_size = misc.np_to_python(step_size)
197 assert radius
is not None
198 except AssertionError:
199 raise ValueError(
"Parameter radius must not be None!")
201 assert len(radius) == len(data_array.shape)
203 radius = (radius,) * data_array.ndim
204 except AssertionError:
205 err_msg =
"Dimensions non-conformant: data_array.shape: {}, radius: {}"
206 raise ValueError(err_msg.format(data_array.shape, radius))
208 start_pixel = radius
if start_pixel
is None else start_pixel
209 step_size = tuple((r*2 + 1)
for r
in radius)
if step_size
is None else step_size
212 assert len(start_pixel) == len(data_array.shape)
214 start_pixel = (start_pixel,) * data_array.ndim
215 except AssertionError:
216 err_msg =
"Dimensions non-conformant: data_array.shape: {}, start_pixel: {}"
217 raise ValueError(err_msg.format(data_array.shape, start_pixel))
219 assert len(step_size) == len(data_array.shape)
221 step_size = (step_size,) * data_array.ndim
222 except AssertionError:
223 err_msg =
"Dimensions non-conformant: data_array.shape: {}, step_size: {}"
224 raise ValueError(err_msg.format(data_array.shape, start_pixel))
226 orig_index_lists = [list(range(start, stop, step))
for start, stop, step
in zip(start_pixel, data_array.shape, step_size)]
227 return (orig_index_lists, radius, start_pixel, step_size)
229 raise ValueError(
"Something went wrong generating indices, please check parameters.")
moving(np.array data_array, tuple radius, tuple start_pixel=None, tuple step_size=None)
Generates a symmetric moving window over an array.
np.array sliding_window_function(np.array arr, radius, fn, str pad_mode=None, *args, **kwargs)
Applies the function fn to a sliding window over the array arr.
list determine_moving_parameters(np.array data_array, tuple radius, tuple start_pixel=None, tuple step_size=None)
Generate indices for a moving window and check the other parameters.