pytme 0.2.0b0__cp311-cp311-macosx_14_0_arm64.whl → 0.2.2__cp311-cp311-macosx_14_0_arm64.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.
- pytme-0.2.2.data/scripts/match_template.py +1187 -0
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/postprocess.py +170 -71
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/preprocessor_gui.py +179 -86
- pytme-0.2.2.dist-info/METADATA +91 -0
- pytme-0.2.2.dist-info/RECORD +74 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/WHEEL +1 -1
- scripts/extract_candidates.py +126 -87
- scripts/match_template.py +596 -209
- scripts/match_template_filters.py +571 -223
- scripts/postprocess.py +170 -71
- scripts/preprocessor_gui.py +179 -86
- scripts/refine_matches.py +567 -159
- tme/__init__.py +0 -1
- tme/__version__.py +1 -1
- tme/analyzer.py +627 -855
- tme/backends/__init__.py +41 -11
- tme/backends/_jax_utils.py +185 -0
- tme/backends/cupy_backend.py +120 -225
- tme/backends/jax_backend.py +282 -0
- tme/backends/matching_backend.py +464 -388
- tme/backends/mlx_backend.py +45 -68
- tme/backends/npfftw_backend.py +256 -514
- tme/backends/pytorch_backend.py +41 -154
- tme/density.py +312 -421
- tme/extensions.cpython-311-darwin.so +0 -0
- tme/matching_data.py +366 -303
- tme/matching_exhaustive.py +279 -1521
- tme/matching_optimization.py +234 -129
- tme/matching_scores.py +884 -0
- tme/matching_utils.py +281 -387
- tme/memory.py +377 -0
- tme/orientations.py +226 -66
- tme/parser.py +3 -4
- tme/preprocessing/__init__.py +2 -0
- tme/preprocessing/_utils.py +217 -0
- tme/preprocessing/composable_filter.py +31 -0
- tme/preprocessing/compose.py +55 -0
- tme/preprocessing/frequency_filters.py +388 -0
- tme/preprocessing/tilt_series.py +1011 -0
- tme/preprocessor.py +574 -530
- tme/structure.py +495 -189
- tme/types.py +5 -3
- pytme-0.2.0b0.data/scripts/match_template.py +0 -800
- pytme-0.2.0b0.dist-info/METADATA +0 -73
- pytme-0.2.0b0.dist-info/RECORD +0 -66
- tme/helpers.py +0 -881
- tme/matching_constrained.py +0 -195
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/preprocess.py +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/LICENSE +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/entry_points.txt +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
""" Defines a specification for filters that can be used with
|
2
|
+
:py:class:`tme.preprocessing.compose.Compose`.
|
3
|
+
|
4
|
+
Copyright (c) 2024 European Molecular Biology Laboratory
|
5
|
+
|
6
|
+
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
7
|
+
"""
|
8
|
+
from typing import Dict
|
9
|
+
from abc import ABC, abstractmethod
|
10
|
+
|
11
|
+
|
12
|
+
class ComposableFilter(ABC):
|
13
|
+
"""
|
14
|
+
Strategy class for composable filters.
|
15
|
+
"""
|
16
|
+
|
17
|
+
@abstractmethod
|
18
|
+
def __call__(self, *args, **kwargs) -> Dict:
|
19
|
+
"""
|
20
|
+
Parameters:
|
21
|
+
-----------
|
22
|
+
*args : tuple
|
23
|
+
Variable length argument list.
|
24
|
+
**kwargs : dict
|
25
|
+
Arbitrary keyword arguments.
|
26
|
+
|
27
|
+
Returns:
|
28
|
+
--------
|
29
|
+
Dict
|
30
|
+
A dictionary representing the result of the filtering operation.
|
31
|
+
"""
|
@@ -0,0 +1,55 @@
|
|
1
|
+
""" Combine filters using an interface analogous to pytorch's Compose.
|
2
|
+
|
3
|
+
Copyright (c) 2024 European Molecular Biology Laboratory
|
4
|
+
|
5
|
+
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import Tuple, Dict
|
9
|
+
|
10
|
+
from tme.backends import backend as be
|
11
|
+
|
12
|
+
|
13
|
+
class Compose:
|
14
|
+
"""
|
15
|
+
Compose a series of transformations.
|
16
|
+
|
17
|
+
This class allows composing multiple transformations together. Each transformation
|
18
|
+
is expected to be a callable that accepts keyword arguments and returns metadata.
|
19
|
+
|
20
|
+
Parameters:
|
21
|
+
-----------
|
22
|
+
transforms : Tuple[object]
|
23
|
+
A tuple containing transformation objects.
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
--------
|
27
|
+
Dict
|
28
|
+
Metadata resulting from the composed transformations.
|
29
|
+
|
30
|
+
"""
|
31
|
+
|
32
|
+
def __init__(self, transforms: Tuple[object]):
|
33
|
+
self.transforms = transforms
|
34
|
+
|
35
|
+
def __call__(self, **kwargs: Dict) -> Dict:
|
36
|
+
meta = {}
|
37
|
+
if not len(self.transforms):
|
38
|
+
return meta
|
39
|
+
|
40
|
+
meta = self.transforms[0](**kwargs)
|
41
|
+
for transform in self.transforms[1:]:
|
42
|
+
kwargs.update(meta)
|
43
|
+
ret = transform(**kwargs)
|
44
|
+
|
45
|
+
if "data" not in ret:
|
46
|
+
continue
|
47
|
+
|
48
|
+
if ret.get("is_multiplicative_filter", False):
|
49
|
+
prev_data = meta.pop("data")
|
50
|
+
ret["data"] = be.multiply(ret["data"], prev_data, out=ret["data"])
|
51
|
+
ret["merge"], prev_data = None, None
|
52
|
+
|
53
|
+
meta = ret
|
54
|
+
|
55
|
+
return meta
|
@@ -0,0 +1,388 @@
|
|
1
|
+
""" Defines Fourier frequency filters.
|
2
|
+
|
3
|
+
Copyright (c) 2024 European Molecular Biology Laboratory
|
4
|
+
|
5
|
+
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
6
|
+
"""
|
7
|
+
from math import log, sqrt
|
8
|
+
from typing import Tuple, Dict
|
9
|
+
|
10
|
+
import numpy as np
|
11
|
+
from scipy.ndimage import mean as ndimean
|
12
|
+
from scipy.ndimage import map_coordinates
|
13
|
+
|
14
|
+
from ..types import BackendArray
|
15
|
+
from ..backends import backend as be
|
16
|
+
from ._utils import fftfreqn, crop_real_fourier, shift_fourier, compute_fourier_shape
|
17
|
+
|
18
|
+
|
19
|
+
class BandPassFilter:
|
20
|
+
"""
|
21
|
+
This class provides methods to generate bandpass filters in Fourier space,
|
22
|
+
either by directly specifying the frequency cutoffs (discrete_bandpass) or
|
23
|
+
by using Gaussian functions (gaussian_bandpass).
|
24
|
+
|
25
|
+
Parameters:
|
26
|
+
-----------
|
27
|
+
lowpass : float, optional
|
28
|
+
The lowpass cutoff, defaults to None.
|
29
|
+
highpass : float, optional
|
30
|
+
The highpass cutoff, defaults to None.
|
31
|
+
sampling_rate : Tuple[float], optional
|
32
|
+
The sampling r_position_to_molmapate in Fourier space, defaults to 1.
|
33
|
+
use_gaussian : bool, optional
|
34
|
+
Whether to use Gaussian bandpass filter, defaults to True.
|
35
|
+
return_real_fourier : bool, optional
|
36
|
+
Whether to return only the real Fourier space, defaults to False.
|
37
|
+
shape_is_real_fourier : bool, optional
|
38
|
+
Whether the shape represents the real Fourier space, defaults to False.
|
39
|
+
"""
|
40
|
+
|
41
|
+
def __init__(
|
42
|
+
self,
|
43
|
+
lowpass: float = None,
|
44
|
+
highpass: float = None,
|
45
|
+
sampling_rate: Tuple[float] = 1,
|
46
|
+
use_gaussian: bool = True,
|
47
|
+
return_real_fourier: bool = False,
|
48
|
+
shape_is_real_fourier: bool = False,
|
49
|
+
):
|
50
|
+
self.lowpass = lowpass
|
51
|
+
self.highpass = highpass
|
52
|
+
self.use_gaussian = use_gaussian
|
53
|
+
self.return_real_fourier = return_real_fourier
|
54
|
+
self.shape_is_real_fourier = shape_is_real_fourier
|
55
|
+
self.sampling_rate = sampling_rate
|
56
|
+
|
57
|
+
@staticmethod
|
58
|
+
def discrete_bandpass(
|
59
|
+
shape: Tuple[int],
|
60
|
+
lowpass: float,
|
61
|
+
highpass: float,
|
62
|
+
sampling_rate: Tuple[float],
|
63
|
+
return_real_fourier: bool = False,
|
64
|
+
shape_is_real_fourier: bool = False,
|
65
|
+
**kwargs,
|
66
|
+
) -> BackendArray:
|
67
|
+
"""
|
68
|
+
Generate a bandpass filter using discrete frequency cutoffs.
|
69
|
+
|
70
|
+
Parameters:
|
71
|
+
-----------
|
72
|
+
shape : tuple of int
|
73
|
+
The shape of the bandpass filter.
|
74
|
+
lowpass : float
|
75
|
+
The lowpass cutoff in units of sampling rate.
|
76
|
+
highpass : float
|
77
|
+
The highpass cutoff in units of sampling rate.
|
78
|
+
return_real_fourier : bool, optional
|
79
|
+
Whether to return only the real Fourier space, defaults to False.
|
80
|
+
sampling_rate : float
|
81
|
+
The sampling rate in Fourier space.
|
82
|
+
shape_is_real_fourier : bool, optional
|
83
|
+
Whether the shape represents the real Fourier space, defaults to False.
|
84
|
+
**kwargs : dict
|
85
|
+
Additional keyword arguments.
|
86
|
+
|
87
|
+
Returns:
|
88
|
+
--------
|
89
|
+
BackendArray
|
90
|
+
The bandpass filter in Fourier space.
|
91
|
+
"""
|
92
|
+
if shape_is_real_fourier:
|
93
|
+
return_real_fourier = False
|
94
|
+
|
95
|
+
grid = fftfreqn(
|
96
|
+
shape=shape,
|
97
|
+
sampling_rate=0.5,
|
98
|
+
shape_is_real_fourier=shape_is_real_fourier,
|
99
|
+
compute_euclidean_norm=True,
|
100
|
+
)
|
101
|
+
|
102
|
+
lowpass = 0 if lowpass is None else lowpass
|
103
|
+
highpass = 1e10 if highpass is None else highpass
|
104
|
+
|
105
|
+
highcut = grid.max()
|
106
|
+
if lowpass > 0:
|
107
|
+
highcut = np.max(2 * sampling_rate / lowpass)
|
108
|
+
lowcut = np.max(2 * sampling_rate / highpass)
|
109
|
+
|
110
|
+
bandpass_filter = ((grid <= highcut) & (grid >= lowcut)) * 1.0
|
111
|
+
|
112
|
+
bandpass_filter = shift_fourier(
|
113
|
+
data=bandpass_filter, shape_is_real_fourier=shape_is_real_fourier
|
114
|
+
)
|
115
|
+
|
116
|
+
if return_real_fourier:
|
117
|
+
bandpass_filter = crop_real_fourier(bandpass_filter)
|
118
|
+
|
119
|
+
return bandpass_filter
|
120
|
+
|
121
|
+
@staticmethod
|
122
|
+
def gaussian_bandpass(
|
123
|
+
shape: Tuple[int],
|
124
|
+
lowpass: float,
|
125
|
+
highpass: float,
|
126
|
+
sampling_rate: float,
|
127
|
+
return_real_fourier: bool = False,
|
128
|
+
shape_is_real_fourier: bool = False,
|
129
|
+
**kwargs,
|
130
|
+
) -> BackendArray:
|
131
|
+
"""
|
132
|
+
Generate a bandpass filter using Gaussian functions.
|
133
|
+
|
134
|
+
Parameters:
|
135
|
+
-----------
|
136
|
+
shape : tuple of int
|
137
|
+
The shape of the bandpass filter.
|
138
|
+
lowpass : float
|
139
|
+
The lowpass cutoff in units of sampling rate.
|
140
|
+
highpass : float
|
141
|
+
The highpass cutoff in units of sampling rate.
|
142
|
+
sampling_rate : float
|
143
|
+
The sampling rate in Fourier space.
|
144
|
+
return_real_fourier : bool, optional
|
145
|
+
Whether to return only the real Fourier space, defaults to False.
|
146
|
+
shape_is_real_fourier : bool, optional
|
147
|
+
Whether the shape represents the real Fourier space, defaults to False.
|
148
|
+
**kwargs : dict
|
149
|
+
Additional keyword arguments.
|
150
|
+
|
151
|
+
Returns:
|
152
|
+
--------
|
153
|
+
BackendArray
|
154
|
+
The bandpass filter in Fourier space.
|
155
|
+
"""
|
156
|
+
if shape_is_real_fourier:
|
157
|
+
return_real_fourier = False
|
158
|
+
|
159
|
+
grid = fftfreqn(
|
160
|
+
shape=shape,
|
161
|
+
sampling_rate=0.5,
|
162
|
+
shape_is_real_fourier=shape_is_real_fourier,
|
163
|
+
compute_euclidean_norm=True,
|
164
|
+
)
|
165
|
+
grid = be.to_backend_array(grid)
|
166
|
+
grid = -be.square(grid)
|
167
|
+
|
168
|
+
lowpass_filter, highpass_filter = 1, 1
|
169
|
+
norm = float(sqrt(2 * log(2)))
|
170
|
+
upper_sampling = float(
|
171
|
+
be.max(be.multiply(2, be.to_backend_array(sampling_rate)))
|
172
|
+
)
|
173
|
+
|
174
|
+
if lowpass is not None:
|
175
|
+
lowpass = float(lowpass)
|
176
|
+
lowpass = be.maximum(lowpass, be.eps(be._float_dtype))
|
177
|
+
if highpass is not None:
|
178
|
+
highpass = float(highpass)
|
179
|
+
highpass = be.maximum(highpass, be.eps(be._float_dtype))
|
180
|
+
|
181
|
+
if lowpass is not None:
|
182
|
+
lowpass = upper_sampling / (lowpass * norm)
|
183
|
+
lowpass = be.multiply(2, be.square(lowpass))
|
184
|
+
lowpass_filter = be.exp(be.divide(grid, lowpass))
|
185
|
+
if highpass is not None:
|
186
|
+
highpass = upper_sampling / (highpass * norm)
|
187
|
+
highpass = be.multiply(2, be.square(highpass))
|
188
|
+
highpass_filter = 1 - be.exp(be.divide(grid, highpass))
|
189
|
+
|
190
|
+
bandpass_filter = be.multiply(lowpass_filter, highpass_filter)
|
191
|
+
bandpass_filter = shift_fourier(
|
192
|
+
data=bandpass_filter, shape_is_real_fourier=shape_is_real_fourier
|
193
|
+
)
|
194
|
+
|
195
|
+
if return_real_fourier:
|
196
|
+
bandpass_filter = crop_real_fourier(bandpass_filter)
|
197
|
+
|
198
|
+
return bandpass_filter
|
199
|
+
|
200
|
+
def __call__(self, **kwargs):
|
201
|
+
func_args = vars(self)
|
202
|
+
func_args.update(kwargs)
|
203
|
+
|
204
|
+
func = self.discrete_bandpass
|
205
|
+
if func_args.get("use_gaussian"):
|
206
|
+
func = self.gaussian_bandpass
|
207
|
+
|
208
|
+
mask = func(**func_args)
|
209
|
+
|
210
|
+
return {
|
211
|
+
"data": be.to_backend_array(mask),
|
212
|
+
"sampling_rate": func_args.get("sampling_rate", 1),
|
213
|
+
"is_multiplicative_filter": True,
|
214
|
+
}
|
215
|
+
|
216
|
+
|
217
|
+
class LinearWhiteningFilter:
|
218
|
+
"""
|
219
|
+
This class provides methods to compute the spectrum of the input data and
|
220
|
+
apply linear whitening to the Fourier coefficients.
|
221
|
+
|
222
|
+
Parameters:
|
223
|
+
-----------
|
224
|
+
**kwargs : Dict, optional
|
225
|
+
Additional keyword arguments.
|
226
|
+
|
227
|
+
|
228
|
+
References
|
229
|
+
----------
|
230
|
+
.. [1] de Teresa-Trueba, I.; Goetz, S. K.; Mattausch, A.; Stojanovska, F.; Zimmerli, C. E.;
|
231
|
+
Toro-Nahuelpan, M.; Cheng, D. W. C.; Tollervey, F.; Pape, C.; Beck, M.; Diz-Munoz,
|
232
|
+
A.; Kreshuk, A.; Mahamid, J.; Zaugg, J. B. Nat. Methods 2023, 20, 284–294.
|
233
|
+
.. [2] M. L. Chaillet, G. van der Schot, I. Gubins, S. Roet,
|
234
|
+
R. C. Veltkamp, and F. Förster, Int. J. Mol. Sci. 24,
|
235
|
+
13375 (2023)
|
236
|
+
"""
|
237
|
+
|
238
|
+
def __init__(self, **kwargs):
|
239
|
+
pass
|
240
|
+
|
241
|
+
@staticmethod
|
242
|
+
def _compute_spectrum(
|
243
|
+
data_rfft: BackendArray, n_bins: int = None, batch_dimension: int = None
|
244
|
+
) -> Tuple[BackendArray, BackendArray]:
|
245
|
+
"""
|
246
|
+
Compute the spectrum of the input data.
|
247
|
+
|
248
|
+
Parameters:
|
249
|
+
-----------
|
250
|
+
data_rfft : BackendArray
|
251
|
+
The Fourier transform of the input data.
|
252
|
+
n_bins : int, optional
|
253
|
+
The number of bins for computing the spectrum, defaults to None.
|
254
|
+
batch_dimension : int, optional
|
255
|
+
Batch dimension to average over.
|
256
|
+
|
257
|
+
Returns:
|
258
|
+
--------
|
259
|
+
bins : BackendArray
|
260
|
+
Array containing the bin indices for the spectrum.
|
261
|
+
radial_averages : BackendArray
|
262
|
+
Array containing the radial averages of the spectrum.
|
263
|
+
"""
|
264
|
+
shape = tuple(x for i, x in enumerate(data_rfft.shape) if i != batch_dimension)
|
265
|
+
|
266
|
+
max_bins = max(max(shape[:-1]) // 2 + 1, shape[-1])
|
267
|
+
n_bins = max_bins if n_bins is None else n_bins
|
268
|
+
n_bins = int(min(n_bins, max_bins))
|
269
|
+
|
270
|
+
bins = fftfreqn(
|
271
|
+
shape=shape,
|
272
|
+
sampling_rate=0.5,
|
273
|
+
shape_is_real_fourier=True,
|
274
|
+
compute_euclidean_norm=True,
|
275
|
+
)
|
276
|
+
bins = be.to_numpy_array(bins)
|
277
|
+
|
278
|
+
# Implicit lowpass to nyquist
|
279
|
+
bins = np.floor(bins * (n_bins - 1) + 0.5).astype(int)
|
280
|
+
fft_shift_axes = tuple(
|
281
|
+
i for i in range(data_rfft.ndim - 1) if i != batch_dimension
|
282
|
+
)
|
283
|
+
fourier_spectrum = np.fft.fftshift(data_rfft, axes=fft_shift_axes)
|
284
|
+
fourier_spectrum = np.abs(fourier_spectrum)
|
285
|
+
np.square(fourier_spectrum, out=fourier_spectrum)
|
286
|
+
|
287
|
+
radial_averages = ndimean(
|
288
|
+
fourier_spectrum, labels=bins, index=np.arange(n_bins)
|
289
|
+
)
|
290
|
+
np.sqrt(radial_averages, out=radial_averages)
|
291
|
+
np.reciprocal(radial_averages, out=radial_averages)
|
292
|
+
np.divide(radial_averages, radial_averages.max(), out=radial_averages)
|
293
|
+
|
294
|
+
return bins, radial_averages
|
295
|
+
|
296
|
+
@staticmethod
|
297
|
+
def _interpolate_spectrum(
|
298
|
+
spectrum: BackendArray,
|
299
|
+
shape: Tuple[int],
|
300
|
+
shape_is_real_fourier: bool = True,
|
301
|
+
order: int = 1,
|
302
|
+
) -> BackendArray:
|
303
|
+
"""
|
304
|
+
References
|
305
|
+
----------
|
306
|
+
.. [1] M. L. Chaillet, G. van der Schot, I. Gubins, S. Roet,
|
307
|
+
R. C. Veltkamp, and F. Förster, Int. J. Mol. Sci. 24,
|
308
|
+
13375 (2023)
|
309
|
+
"""
|
310
|
+
grid = fftfreqn(
|
311
|
+
shape=shape,
|
312
|
+
sampling_rate=0.5,
|
313
|
+
shape_is_real_fourier=shape_is_real_fourier,
|
314
|
+
compute_euclidean_norm=True,
|
315
|
+
)
|
316
|
+
grid = be.to_numpy_array(grid)
|
317
|
+
np.multiply(grid, (spectrum.shape[0] - 1), out=grid) + 0.5
|
318
|
+
spectrum = map_coordinates(spectrum, grid.reshape(1, -1), order=order)
|
319
|
+
return spectrum.reshape(grid.shape)
|
320
|
+
|
321
|
+
def __call__(
|
322
|
+
self,
|
323
|
+
data: BackendArray = None,
|
324
|
+
data_rfft: BackendArray = None,
|
325
|
+
n_bins: int = None,
|
326
|
+
batch_dimension: int = None,
|
327
|
+
order: int = 1,
|
328
|
+
**kwargs: Dict,
|
329
|
+
) -> Dict:
|
330
|
+
"""
|
331
|
+
Apply linear whitening to the data and return the result.
|
332
|
+
|
333
|
+
Parameters:
|
334
|
+
-----------
|
335
|
+
data : BackendArray, optional
|
336
|
+
The input data, defaults to None.
|
337
|
+
data_rfft : BackendArray, optional
|
338
|
+
The Fourier transform of the input data, defaults to None.
|
339
|
+
n_bins : int, optional
|
340
|
+
The number of bins for computing the spectrum, defaults to None.
|
341
|
+
batch_dimension : int, optional
|
342
|
+
Batch dimension to average over.
|
343
|
+
order : int, optional
|
344
|
+
Interpolation order to use.
|
345
|
+
**kwargs : Dict
|
346
|
+
Additional keyword arguments.
|
347
|
+
|
348
|
+
Returns:
|
349
|
+
--------
|
350
|
+
Dict
|
351
|
+
Filter data and associated parameters.
|
352
|
+
"""
|
353
|
+
if data_rfft is None:
|
354
|
+
data_rfft = np.fft.rfftn(be.to_numpy_array(data))
|
355
|
+
|
356
|
+
data_rfft = be.to_numpy_array(data_rfft)
|
357
|
+
|
358
|
+
bins, radial_averages = self._compute_spectrum(
|
359
|
+
data_rfft, n_bins, batch_dimension
|
360
|
+
)
|
361
|
+
|
362
|
+
if order is None:
|
363
|
+
cutoff = bins < radial_averages.size
|
364
|
+
filter_mask = np.zeros(bins.shape, radial_averages.dtype)
|
365
|
+
filter_mask[cutoff] = radial_averages[bins[cutoff]]
|
366
|
+
else:
|
367
|
+
shape = bins.shape
|
368
|
+
if kwargs.get("shape", False):
|
369
|
+
shape = compute_fourier_shape(
|
370
|
+
shape=kwargs.get("shape"),
|
371
|
+
shape_is_real_fourier=kwargs.get("shape_is_real_fourier", False),
|
372
|
+
)
|
373
|
+
|
374
|
+
filter_mask = self._interpolate_spectrum(
|
375
|
+
spectrum=radial_averages,
|
376
|
+
shape=shape,
|
377
|
+
shape_is_real_fourier=True,
|
378
|
+
)
|
379
|
+
|
380
|
+
filter_mask = np.fft.ifftshift(
|
381
|
+
filter_mask,
|
382
|
+
axes=tuple(i for i in range(data_rfft.ndim - 1) if i != batch_dimension),
|
383
|
+
)
|
384
|
+
|
385
|
+
return {
|
386
|
+
"data": be.to_backend_array(filter_mask),
|
387
|
+
"is_multiplicative_filter": True,
|
388
|
+
}
|