GeoRacoon 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- convster/__init__.py +25 -0
- convster/filters/__init__.py +22 -0
- convster/filters/gaussian.py +282 -0
- convster/helper.py +94 -0
- convster/parallel.py +1475 -0
- convster/processing.py +1223 -0
- coonfit/__init__.py +35 -0
- coonfit/exceptions.py +19 -0
- coonfit/helper.py +120 -0
- coonfit/inference.py +815 -0
- coonfit/parallel.py +1246 -0
- coonfit/parallel_helpers.py +566 -0
- georacoon-1.0.0.dist-info/METADATA +362 -0
- georacoon-1.0.0.dist-info/RECORD +28 -0
- georacoon-1.0.0.dist-info/WHEEL +5 -0
- georacoon-1.0.0.dist-info/licenses/LICENSE +21 -0
- georacoon-1.0.0.dist-info/scm_file_list.json +112 -0
- georacoon-1.0.0.dist-info/scm_version.json +8 -0
- georacoon-1.0.0.dist-info/top_level.txt +3 -0
- riogrande/__init__.py +28 -0
- riogrande/helper.py +891 -0
- riogrande/io/__init__.py +48 -0
- riogrande/io/core.py +622 -0
- riogrande/io/exceptions.py +39 -0
- riogrande/io/models.py +1689 -0
- riogrande/parallel.py +571 -0
- riogrande/prepare.py +281 -0
- riogrande/timing.py +93 -0
convster/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
convster — Spatial filter application and derived metric computation for raster maps.
|
|
3
|
+
|
|
4
|
+
This package provides tools for applying spatial filters (e.g. Gaussian blur)
|
|
5
|
+
to land-cover type raster maps and for computing per-cell derived metrics such
|
|
6
|
+
as Shannon entropy and multi-layer interaction values. Processing is designed to
|
|
7
|
+
work block-wise for memory-efficient handling of large rasters.
|
|
8
|
+
|
|
9
|
+
Submodules
|
|
10
|
+
----------
|
|
11
|
+
filters
|
|
12
|
+
Implementations of spatial filters ready for use with raster data,
|
|
13
|
+
including Gaussian blurring via :mod:`~convster.filters.gaussian`.
|
|
14
|
+
helper
|
|
15
|
+
Array utility functions, including non-zero index lookups used
|
|
16
|
+
internally during filter application.
|
|
17
|
+
processing
|
|
18
|
+
Functions for category selection, entropy computation, and multi-layer
|
|
19
|
+
interaction metrics. Supports per-category filtering and rescaling.
|
|
20
|
+
parallel
|
|
21
|
+
Parallelized application of filters and entropy/interaction computations
|
|
22
|
+
across spatial blocks of a raster.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
_answer_to_everything = 42
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This package contains functions for specific filters that can be applied to
|
|
3
|
+
blur land-cover type maps.
|
|
4
|
+
|
|
5
|
+
Whenever possible the filters are not implemented directly but imported from
|
|
6
|
+
packages with efficient implementations.
|
|
7
|
+
In particular implementations from https://scikit-image.org are used.
|
|
8
|
+
|
|
9
|
+
Usually, within a specific sub-module a filter method of the same name exists.
|
|
10
|
+
So, for example, within `filters.gaussian`, `skimage.filters.gaussian` is
|
|
11
|
+
available as `gaussian`.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .gaussian import gaussian as _gauss_filter
|
|
15
|
+
from .gaussian import bpgaussian
|
|
16
|
+
from .gaussian import get_kernel_diameter as _gauss_get_kd
|
|
17
|
+
from .gaussian import get_kernel_size as _gauss_get_ks
|
|
18
|
+
from .gaussian import get_blur_params
|
|
19
|
+
|
|
20
|
+
_filters = [_gauss_filter, ]
|
|
21
|
+
_get_kernel_diam = [_gauss_get_kd, ]
|
|
22
|
+
_get_kernel_size = [_gauss_get_ks, ]
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides various functions to facilitate the usage of
|
|
3
|
+
`skimage.filters.gaussian`
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
|
|
11
|
+
from skimage.filters import gaussian
|
|
12
|
+
|
|
13
|
+
from ..helper import (first_nonzero,
|
|
14
|
+
last_nonzero)
|
|
15
|
+
|
|
16
|
+
# we abstract the specific filters:
|
|
17
|
+
img_filter = gaussian
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_kernel_diameter(sigma: float, **params) -> int:
|
|
21
|
+
"""
|
|
22
|
+
Compute the effective Gaussian kernel diameter in number of cells.
|
|
23
|
+
|
|
24
|
+
The diameter is estimated by applying a Gaussian filter to a single impulse
|
|
25
|
+
in the center of a zero image, and measuring the spread of the nonzero
|
|
26
|
+
region. The result is always odd to ensure symmetry.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
sigma : float
|
|
31
|
+
Standard deviation for the Gaussian kernel.
|
|
32
|
+
Currently only single scalar values are supported.
|
|
33
|
+
**params
|
|
34
|
+
Additional keyword arguments passed to the Gaussian filter.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
int
|
|
39
|
+
Estimated kernel diameter in pixels (always an odd number).
|
|
40
|
+
|
|
41
|
+
Notes
|
|
42
|
+
-----
|
|
43
|
+
This function determines the kernel diameter adaptively. Starting from
|
|
44
|
+
an initial guess of `10 * sigma`, the size is increased until the blurred
|
|
45
|
+
impulse response fits within the kernel. Uses :func:`skimage.filters.gaussian`
|
|
46
|
+
internally to compute the impulse response.
|
|
47
|
+
|
|
48
|
+
See Also
|
|
49
|
+
--------
|
|
50
|
+
:func:`get_kernel_size` : Return the radius (half-diameter) of the Gaussian kernel.
|
|
51
|
+
:func:`compatible_border_size` : Assert or compute a border size compatible with a kernel.
|
|
52
|
+
|
|
53
|
+
Examples
|
|
54
|
+
--------
|
|
55
|
+
>>> get_kernel_diameter(1)
|
|
56
|
+
7
|
|
57
|
+
>>> get_kernel_diameter(2)
|
|
58
|
+
15
|
|
59
|
+
"""
|
|
60
|
+
msize = int(10 * sigma)
|
|
61
|
+
# make sure it is odd
|
|
62
|
+
if not msize & 1:
|
|
63
|
+
msize += 1
|
|
64
|
+
diameter = msize
|
|
65
|
+
while diameter == msize:
|
|
66
|
+
msize += int(max(1, round(0.1 * msize)))
|
|
67
|
+
tmap = np.zeros((msize, msize), dtype=np.uint8)
|
|
68
|
+
half = int(0.5 * (msize - 1))
|
|
69
|
+
tmap[half, half] = 255
|
|
70
|
+
blurred = gaussian(tmap, sigma=sigma, **params)
|
|
71
|
+
diameter = max(np.unique(last_nonzero(blurred, axis=1)
|
|
72
|
+
- first_nonzero(blurred, axis=1))) + 1
|
|
73
|
+
return diameter
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_kernel_size(sigma: float, **params):
|
|
77
|
+
"""
|
|
78
|
+
Return the radius of a Gaussian kernel (center to border distance).
|
|
79
|
+
|
|
80
|
+
The kernel size is defined as half of the kernel diameter minus one,
|
|
81
|
+
i.e. size = (diameter - 1) / 2 where `diameter` is determined
|
|
82
|
+
by :func:`get_kernel_diameter`.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
sigma : float
|
|
87
|
+
Standard deviation for the Gaussian kernel.
|
|
88
|
+
**params
|
|
89
|
+
Additional keyword arguments passed to :func:`get_kernel_diameter`
|
|
90
|
+
(e.g. `truncate`, `mode`).
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
int
|
|
95
|
+
The radius of the Gaussian kernel in pixels.
|
|
96
|
+
|
|
97
|
+
See Also
|
|
98
|
+
--------
|
|
99
|
+
:func:`get_kernel_diameter` : Compute the full kernel diameter.
|
|
100
|
+
:func:`compatible_border_size` : Assert or compute a border size compatible with a kernel.
|
|
101
|
+
|
|
102
|
+
Examples
|
|
103
|
+
--------
|
|
104
|
+
>>> get_kernel_size(1)
|
|
105
|
+
3
|
|
106
|
+
>>> get_kernel_size(2)
|
|
107
|
+
7
|
|
108
|
+
"""
|
|
109
|
+
return int(0.5 * (get_kernel_diameter(sigma, **params) - 1))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def compatible_border_size(sigma: float | int, border: tuple[int, int] | None = None,
|
|
113
|
+
**params) -> tuple[int, int]:
|
|
114
|
+
"""
|
|
115
|
+
Assert that the border size is compatible with the specified parameter
|
|
116
|
+
|
|
117
|
+
This method asserts that the kernel size determined by `sigma` and further
|
|
118
|
+
parametrization is smaller than the border.
|
|
119
|
+
If no border is provided, then the minimal border size (in number of
|
|
120
|
+
pixels) is returned.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
sigma : float or int
|
|
125
|
+
Standard deviation for Gaussian kernel
|
|
126
|
+
border : tuple[int, int] or None
|
|
127
|
+
The border size (width, height) in number of pixels along each axis
|
|
128
|
+
**params
|
|
129
|
+
Additional keyword arguments passed to :func:`get_kernel_size`.
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
tuple[int, int]
|
|
134
|
+
The border (width, height) compatible with the specified parameters.
|
|
135
|
+
If a border was provided already, it is returned again, if no border
|
|
136
|
+
was provided, the smallest compatible border is returned.
|
|
137
|
+
|
|
138
|
+
See Also
|
|
139
|
+
--------
|
|
140
|
+
:func:`get_kernel_size` : Compute the kernel radius used in compatibility checks.
|
|
141
|
+
:func:`get_kernel_diameter` : Compute the full diameter of the Gaussian kernel.
|
|
142
|
+
"""
|
|
143
|
+
ks = get_kernel_size(sigma=sigma, **params)
|
|
144
|
+
if border:
|
|
145
|
+
assert all(ks <= b for b in border), f"A dimension of {border=} " \
|
|
146
|
+
f"exceeds the kernel size {ks}"
|
|
147
|
+
bs = border
|
|
148
|
+
else:
|
|
149
|
+
bs = (ks + 1,) * 2
|
|
150
|
+
return bs
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def bpgaussian(data: NDArray, **filter_params) -> NDArray:
|
|
154
|
+
"""Applies a border-preserving Gaussian filter
|
|
155
|
+
|
|
156
|
+
The approach considers a Gaussian blur to be a weighted average over
|
|
157
|
+
all pixels within the kernel diameter with the weight being given by
|
|
158
|
+
the Gaussian function.
|
|
159
|
+
Pixels close to `np.nan` values should simply "ignore" `np.nan` pixels
|
|
160
|
+
and perform the weighted average over all non-`np.nan` pixels within
|
|
161
|
+
the Gaussian kernel.
|
|
162
|
+
This can be achieved with a normal Gaussian filter in a three-step process:
|
|
163
|
+
|
|
164
|
+
1. Perform a Gaussian filter on the data with `np.nan` substituted by
|
|
165
|
+
the neutral element in terms of addition, i.e. 0.0.
|
|
166
|
+
This leads to a weighted average that is not properly normalized as
|
|
167
|
+
the former `np.nan` pixels do not contribute to the value, but are
|
|
168
|
+
considered in the normalizing sum of the weights.
|
|
169
|
+
2. To properly normalize all pixels, create a binary array in the same shape
|
|
170
|
+
as `data` with `np.nan` values becoming `0` and all other pixels `1`.
|
|
171
|
+
Apply the same Gaussian filter to this binary array which results in an
|
|
172
|
+
array holding the sum of weights for the weighted average.
|
|
173
|
+
3. Dividing the blurred array from point 1. by the sum-of-weights array form
|
|
174
|
+
step 2 results in a properly normalized weighted average and thus a blurred
|
|
175
|
+
version of the input data with preserved borders.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
data : NDArray
|
|
180
|
+
Array to apply the Gaussian filter on.
|
|
181
|
+
**filter_params : dict
|
|
182
|
+
Additional keyword arguments passed to :func:`skimage.filters.gaussian`.
|
|
183
|
+
Common parameters include:
|
|
184
|
+
|
|
185
|
+
- ``sigma`` : float
|
|
186
|
+
Standard deviation for Gaussian kernel.
|
|
187
|
+
- ``truncate`` : float
|
|
188
|
+
Truncate filter at this many standard deviations.
|
|
189
|
+
|
|
190
|
+
See :func:`skimage.filters.gaussian` for further parameters.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
NDArray
|
|
195
|
+
Blurred version of `data` with borders preserved at NaN boundaries.
|
|
196
|
+
|
|
197
|
+
See Also
|
|
198
|
+
--------
|
|
199
|
+
:func:`get_kernel_diameter` : Compute the effective kernel diameter for a given sigma.
|
|
200
|
+
:func:`get_blur_params` : Compute Gaussian blur parameters from diameter or sigma.
|
|
201
|
+
"""
|
|
202
|
+
# Substitute `np.nan`s with 0.0 and apply filter
|
|
203
|
+
_data_nonnan = np.where(np.isnan(data), 0.0, data)
|
|
204
|
+
_data_nonnan_blurred = gaussian(image=_data_nonnan, **filter_params)
|
|
205
|
+
|
|
206
|
+
_data_binary = np.where(np.isnan(data), 0.0, 1.0)
|
|
207
|
+
_data_binary_blurred = gaussian(image=_data_binary, **filter_params)
|
|
208
|
+
|
|
209
|
+
_blurred_data = np.divide(_data_nonnan_blurred, _data_binary_blurred,
|
|
210
|
+
out=np.full(data.shape, np.nan),
|
|
211
|
+
where=~np.isnan(data))
|
|
212
|
+
return _blurred_data
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def get_blur_params(diameter: float | None = None, sigma: float | None = None,
|
|
216
|
+
truncate: float = 3) -> dict[str, float]:
|
|
217
|
+
"""
|
|
218
|
+
Compute Gaussian blur parameters from either `diameter` or `sigma`.
|
|
219
|
+
|
|
220
|
+
Either `diameter` or `sigma` must be provided. Missing values are inferred
|
|
221
|
+
from the others, and `truncate` is used or recomputed to maintain consistency.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
diameter : float or None
|
|
226
|
+
Kernel diameter. If provided with `sigma`, `truncate` is recomputed.
|
|
227
|
+
sigma : float or None
|
|
228
|
+
Standard deviation of the Gaussian kernel. If provided with `diameter`,
|
|
229
|
+
`truncate` is recomputed.
|
|
230
|
+
truncate : float
|
|
231
|
+
Number of standard deviations at which to truncate the kernel.
|
|
232
|
+
Default is 3. Ignored if both `diameter` and `sigma` are provided
|
|
233
|
+
(recomputed).
|
|
234
|
+
|
|
235
|
+
Returns
|
|
236
|
+
-------
|
|
237
|
+
dict[str, float]
|
|
238
|
+
Dictionary containing:
|
|
239
|
+
- `diameter`: computed kernel diameter
|
|
240
|
+
- `sigma`: computed standard deviation
|
|
241
|
+
- `truncate`: final truncate value
|
|
242
|
+
|
|
243
|
+
Raises
|
|
244
|
+
------
|
|
245
|
+
TypeError
|
|
246
|
+
If neither `diameter` nor `sigma` is provided.
|
|
247
|
+
|
|
248
|
+
Notes
|
|
249
|
+
-----
|
|
250
|
+
The function ensures that `diameter`, `sigma`, and `truncate` are consistent
|
|
251
|
+
according to Gaussian kernel conventions.
|
|
252
|
+
|
|
253
|
+
See Also
|
|
254
|
+
--------
|
|
255
|
+
:func:`get_kernel_diameter` : Compute the effective kernel diameter from sigma.
|
|
256
|
+
:func:`get_kernel_size` : Compute the kernel radius from sigma.
|
|
257
|
+
:func:`compatible_border_size` : Assert or compute a border compatible with the kernel.
|
|
258
|
+
|
|
259
|
+
Examples
|
|
260
|
+
--------
|
|
261
|
+
>>> get_blur_params(diameter=15)
|
|
262
|
+
{'diameter': 15, 'sigma': 2.5, 'truncate': 3}
|
|
263
|
+
>>> get_blur_params(sigma=2.0)
|
|
264
|
+
{'diameter': 12.0, 'sigma': 2.0, 'truncate': 3}
|
|
265
|
+
>>> get_blur_params(diameter=15, sigma=3)
|
|
266
|
+
{'diameter': 15, 'sigma': 3, 'truncate': 2.5}
|
|
267
|
+
"""
|
|
268
|
+
if diameter is None and sigma is None:
|
|
269
|
+
raise TypeError("Either the `diameter` or the `sigma` parameter "
|
|
270
|
+
f"must be provided. \nGot: {diameter=}, {sigma=}")
|
|
271
|
+
|
|
272
|
+
if diameter:
|
|
273
|
+
if sigma:
|
|
274
|
+
truncate = 0.5 * diameter / sigma
|
|
275
|
+
else:
|
|
276
|
+
if truncate:
|
|
277
|
+
sigma = 0.5 * diameter / truncate
|
|
278
|
+
else:
|
|
279
|
+
if sigma:
|
|
280
|
+
diameter = 2 * sigma * truncate
|
|
281
|
+
|
|
282
|
+
return dict(diameter=diameter, sigma=sigma, truncate=truncate)
|
convster/helper.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Array utility functions for the convster package.
|
|
3
|
+
|
|
4
|
+
This module provides low-level helper functions for inspecting and manipulating
|
|
5
|
+
NumPy arrays. Currently, it exposes utilities for locating the first and last
|
|
6
|
+
non-zero element along a given axis, which are used internally during filter
|
|
7
|
+
application to determine valid data ranges within raster bands.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
from numpy.typing import NDArray
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def first_nonzero(data: NDArray, axis: int = 0, no_value: int = -1) -> NDArray:
|
|
15
|
+
"""
|
|
16
|
+
Return the index of the first non-zero value along the given axis.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
data : NDArray
|
|
21
|
+
Input array to examine.
|
|
22
|
+
axis : int
|
|
23
|
+
Array axis along which to search for the first non-zero. Default is 0.
|
|
24
|
+
no_value : int
|
|
25
|
+
Value to return when no non-zero entries are found along an axis.
|
|
26
|
+
Default is -1.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
indices
|
|
31
|
+
Array indices of the first non-zero values along the specified axis.
|
|
32
|
+
If no non-zero is found, returns `no_value` for that slice.
|
|
33
|
+
|
|
34
|
+
See Also
|
|
35
|
+
--------
|
|
36
|
+
:func:`last_nonzero` : Return the index of the last non-zero value.
|
|
37
|
+
|
|
38
|
+
Examples
|
|
39
|
+
--------
|
|
40
|
+
>>> a = np.array([
|
|
41
|
+
... [0, 0, 3, 0],
|
|
42
|
+
... [1, 0, 0, 0],
|
|
43
|
+
... [0, 2, 0, 0],
|
|
44
|
+
... [0, 0, 0, 4]
|
|
45
|
+
... ])
|
|
46
|
+
>>> first_nonzero(a, axis=1)
|
|
47
|
+
array([2, 0, 1, 3])
|
|
48
|
+
>>> first_nonzero(a, axis=0)
|
|
49
|
+
array([1, 2, 0, 3])
|
|
50
|
+
"""
|
|
51
|
+
mask = data != 0
|
|
52
|
+
return np.where(mask.any(axis=axis), mask.argmax(axis=axis), no_value)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def last_nonzero(data: NDArray, axis: int = 0, no_value: int = -1) -> NDArray:
|
|
56
|
+
"""
|
|
57
|
+
Return the index of the last non-zero value along the given axis.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
data : NDArray
|
|
62
|
+
Input array to examine.
|
|
63
|
+
axis : int
|
|
64
|
+
Array axis along which to search for the last non-zero. Default is 0.
|
|
65
|
+
no_value : int
|
|
66
|
+
Value to return when no non-zero entries are found along an axis.
|
|
67
|
+
Default is -1.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
indices
|
|
72
|
+
Array indices of the last non-zero values along the specified axis.
|
|
73
|
+
If no non-zero is found, returns `no_value` for that slice.
|
|
74
|
+
|
|
75
|
+
See Also
|
|
76
|
+
--------
|
|
77
|
+
:func:`first_nonzero` : Return the index of the first non-zero value.
|
|
78
|
+
|
|
79
|
+
Examples
|
|
80
|
+
--------
|
|
81
|
+
>>> a = np.array([
|
|
82
|
+
... [0, 0, 3, 0],
|
|
83
|
+
... [1, 0, 0, 0],
|
|
84
|
+
... [0, 2, 0, 0],
|
|
85
|
+
... [0, 0, 0, 4]
|
|
86
|
+
... ])
|
|
87
|
+
>>> last_nonzero(a, axis=1)
|
|
88
|
+
array([2, 0, 1, 3])
|
|
89
|
+
>>> last_nonzero(a, axis=0)
|
|
90
|
+
array([1, 2, 2, 3])
|
|
91
|
+
"""
|
|
92
|
+
mask = data != 0
|
|
93
|
+
loc = data.shape[axis] - np.flip(mask, axis=axis).argmax(axis=axis) - 1
|
|
94
|
+
return np.where(mask.any(axis=axis), loc, no_value)
|