impy-array 2.4.3__tar.gz → 2.4.4__tar.gz

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.
Files changed (65) hide show
  1. {impy_array-2.4.3 → impy_array-2.4.4}/PKG-INFO +8 -10
  2. {impy_array-2.4.3 → impy_array-2.4.4}/README.md +7 -9
  3. {impy_array-2.4.3 → impy_array-2.4.4}/impy/__init__.py +1 -1
  4. {impy_array-2.4.3 → impy_array-2.4.4}/impy/array_api.py +14 -22
  5. impy_array-2.4.4/impy/arrays/__init__.py +17 -0
  6. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_corr.py +37 -37
  7. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_deconv.py +4 -13
  8. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_misc.py +2 -2
  9. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_transform.py +2 -2
  10. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/bases/metaarray.py +140 -137
  11. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/bases/overload.py +14 -14
  12. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/big.py +1 -1
  13. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/labeledarray.py +212 -212
  14. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/lazy.py +230 -233
  15. {impy_array-2.4.3 → impy_array-2.4.4}/impy/axes/_axes.py +2 -2
  16. {impy_array-2.4.3 → impy_array-2.4.4}/impy/correlation.py +119 -119
  17. {impy_array-2.4.3 → impy_array-2.4.4}/impy/io.py +1 -1
  18. {impy_array-2.4.3 → impy_array-2.4.4}/impy/random.py +1 -1
  19. {impy_array-2.4.3 → impy_array-2.4.4}/impy/viewer/utils.py +1 -1
  20. impy_array-2.4.3/impy/arrays/__init__.py +0 -17
  21. {impy_array-2.4.3 → impy_array-2.4.4}/.gitignore +0 -0
  22. {impy_array-2.4.3 → impy_array-2.4.4}/LICENSE +0 -0
  23. {impy_array-2.4.3 → impy_array-2.4.4}/impy/__main__.py +0 -0
  24. {impy_array-2.4.3 → impy_array-2.4.4}/impy/_const.py +0 -0
  25. {impy_array-2.4.3 → impy_array-2.4.4}/impy/_types.py +0 -0
  26. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_imshow.py +0 -0
  27. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/__init__.py +0 -0
  28. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_docs.py +0 -0
  29. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_filters.py +0 -0
  30. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_glcm.py +0 -0
  31. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_linalg.py +0 -0
  32. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_plot.py +0 -0
  33. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_process_numba.py +0 -0
  34. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_skimage.py +0 -0
  35. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/_utils/_structures.py +0 -0
  36. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/axesmixin.py +0 -0
  37. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/bases/__init__.py +0 -0
  38. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/imgarray.py +0 -0
  39. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/label.py +0 -0
  40. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/phasearray.py +0 -0
  41. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/specials.py +0 -0
  42. {impy_array-2.4.3 → impy_array-2.4.4}/impy/arrays/tiled.py +0 -0
  43. {impy_array-2.4.3 → impy_array-2.4.4}/impy/axes/__init__.py +0 -0
  44. {impy_array-2.4.3 → impy_array-2.4.4}/impy/axes/_axes_tuple.py +0 -0
  45. {impy_array-2.4.3 → impy_array-2.4.4}/impy/axes/_axis.py +0 -0
  46. {impy_array-2.4.3 → impy_array-2.4.4}/impy/axes/_slicer.py +0 -0
  47. {impy_array-2.4.3 → impy_array-2.4.4}/impy/binder.py +0 -0
  48. {impy_array-2.4.3 → impy_array-2.4.4}/impy/collections.py +0 -0
  49. {impy_array-2.4.3 → impy_array-2.4.4}/impy/core.py +0 -0
  50. {impy_array-2.4.3 → impy_array-2.4.4}/impy/frame/__init__.py +0 -0
  51. {impy_array-2.4.3 → impy_array-2.4.4}/impy/frame/frames.py +0 -0
  52. {impy_array-2.4.3 → impy_array-2.4.4}/impy/lazy/__init__.py +0 -0
  53. {impy_array-2.4.3 → impy_array-2.4.4}/impy/lazy/core.py +0 -0
  54. {impy_array-2.4.3 → impy_array-2.4.4}/impy/lazy/random.py +0 -0
  55. {impy_array-2.4.3 → impy_array-2.4.4}/impy/roi.py +0 -0
  56. {impy_array-2.4.3 → impy_array-2.4.4}/impy/utils/__init__.py +0 -0
  57. {impy_array-2.4.3 → impy_array-2.4.4}/impy/utils/axesop.py +0 -0
  58. {impy_array-2.4.3 → impy_array-2.4.4}/impy/utils/deco.py +0 -0
  59. {impy_array-2.4.3 → impy_array-2.4.4}/impy/utils/gauss.py +0 -0
  60. {impy_array-2.4.3 → impy_array-2.4.4}/impy/utils/misc.py +0 -0
  61. {impy_array-2.4.3 → impy_array-2.4.4}/impy/utils/slicer.py +0 -0
  62. {impy_array-2.4.3 → impy_array-2.4.4}/impy/utils/utilcls.py +0 -0
  63. {impy_array-2.4.3 → impy_array-2.4.4}/impy/viewer/__init__.py +0 -0
  64. {impy_array-2.4.3 → impy_array-2.4.4}/impy/viewer/viewer.py +0 -0
  65. {impy_array-2.4.3 → impy_array-2.4.4}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: impy-array
3
- Version: 2.4.3
3
+ Version: 2.4.4
4
4
  Summary: Speed up coding/extending image analysis in Python.
5
5
  Project-URL: Download, https://github.com/hanjinliu/impy
6
6
  Author-email: Hanjin Liu <liuhanjin-sc@g.ecc.u-tokyo.ac.jp>
@@ -74,13 +74,10 @@ Description-Content-Type: text/markdown
74
74
  [![Python package index download statistics](https://img.shields.io/pypi/dm/impy-array.svg)](https://pypistats.org/packages/impy-array)
75
75
  [![PyPI version](https://badge.fury.io/py/impy-array.svg)](https://badge.fury.io/py/impy-array)
76
76
 
77
- # A numpy extension for efficient and powerful image analysis workflow
77
+ # impy
78
78
 
79
- `impy` is an all-in-one image analysis library, equipped with parallel processing, GPU
80
- support, GUI-based tools and so on.
81
-
82
- The core array, `ImgArray`, is a subclass of `numpy.ndarray`, tagged with information
83
- such as:
79
+ `impy` is an all-in-one multi-dimensional image analysis library. The core array,
80
+ `ImgArray`, is a subclass of `numpy.ndarray`, tagged with information such as:
84
81
 
85
82
  - image axes
86
83
  - scale of each axis
@@ -125,7 +122,7 @@ img["z=3;t=0"].imshow() # Plot image slice at z=3 and t=0.
125
122
  img["y=N//4:N//4*3"].imshow() # `N` for the size of the axis.
126
123
  img_fil = img.gaussian_filter(sigma=2) # Paralell batch denoising. No more for loop!
127
124
  img_prj = np.max(img_fil, axis="z") # Z-projection (numpy is aware of image axes!).
128
- img_prj.imsave(f"Max-{img.name}") # Save in the same place. Don't spend time on searching for the directory!
125
+ img_prj.imsave("image_max.tif") # Save in the same place. Don't spend time on searching for the directory!
129
126
  ```
130
127
 
131
128
  ### Supports many file formats
@@ -165,8 +162,8 @@ ip.Const["RESOURCE"] = "cupy" # <- globally use GPU
165
162
  ### Seamless interface between `napari`
166
163
 
167
164
  [napari](https://github.com/napari/napari) is an interactive viewer for multi-dimensional
168
- images. `impy` has a **simple and efficient interface** with it, via the object `ip.gui`.
169
- Since `ImgArray` is tagged with image metadata, you don't have to care about axes or
165
+ images. `impy` has a **simple and efficient interface** with it, via the object `ip.gui`.
166
+ Since `ImgArray` is tagged with image metadata, you don't have to care about axes or
170
167
  scales. Just run
171
168
 
172
169
  ```python
@@ -214,6 +211,7 @@ For more complex procedures, it is possible to send images directly to `IPython`
214
211
  ```
215
212
  impy path/to/image.tif -i
216
213
  ```
214
+
217
215
  ```python
218
216
  thr = img.gaussian_filter().threshold()
219
217
  ```
@@ -2,13 +2,10 @@
2
2
  [![Python package index download statistics](https://img.shields.io/pypi/dm/impy-array.svg)](https://pypistats.org/packages/impy-array)
3
3
  [![PyPI version](https://badge.fury.io/py/impy-array.svg)](https://badge.fury.io/py/impy-array)
4
4
 
5
- # A numpy extension for efficient and powerful image analysis workflow
5
+ # impy
6
6
 
7
- `impy` is an all-in-one image analysis library, equipped with parallel processing, GPU
8
- support, GUI-based tools and so on.
9
-
10
- The core array, `ImgArray`, is a subclass of `numpy.ndarray`, tagged with information
11
- such as:
7
+ `impy` is an all-in-one multi-dimensional image analysis library. The core array,
8
+ `ImgArray`, is a subclass of `numpy.ndarray`, tagged with information such as:
12
9
 
13
10
  - image axes
14
11
  - scale of each axis
@@ -53,7 +50,7 @@ img["z=3;t=0"].imshow() # Plot image slice at z=3 and t=0.
53
50
  img["y=N//4:N//4*3"].imshow() # `N` for the size of the axis.
54
51
  img_fil = img.gaussian_filter(sigma=2) # Paralell batch denoising. No more for loop!
55
52
  img_prj = np.max(img_fil, axis="z") # Z-projection (numpy is aware of image axes!).
56
- img_prj.imsave(f"Max-{img.name}") # Save in the same place. Don't spend time on searching for the directory!
53
+ img_prj.imsave("image_max.tif") # Save in the same place. Don't spend time on searching for the directory!
57
54
  ```
58
55
 
59
56
  ### Supports many file formats
@@ -93,8 +90,8 @@ ip.Const["RESOURCE"] = "cupy" # <- globally use GPU
93
90
  ### Seamless interface between `napari`
94
91
 
95
92
  [napari](https://github.com/napari/napari) is an interactive viewer for multi-dimensional
96
- images. `impy` has a **simple and efficient interface** with it, via the object `ip.gui`.
97
- Since `ImgArray` is tagged with image metadata, you don't have to care about axes or
93
+ images. `impy` has a **simple and efficient interface** with it, via the object `ip.gui`.
94
+ Since `ImgArray` is tagged with image metadata, you don't have to care about axes or
98
95
  scales. Just run
99
96
 
100
97
  ```python
@@ -142,6 +139,7 @@ For more complex procedures, it is possible to send images directly to `IPython`
142
139
  ```
143
140
  impy path/to/image.tif -i
144
141
  ```
142
+
145
143
  ```python
146
144
  thr = img.gaussian_filter().threshold()
147
145
  ```
@@ -1,4 +1,4 @@
1
- __version__ = "2.4.3"
1
+ __version__ = "2.4.4"
2
2
  __author__ = "Hanjin Liu"
3
3
  __email__ = "liuhanjin-sc@g.ecc.u-tokyo.ac.jp"
4
4
 
@@ -1,11 +1,5 @@
1
-
2
1
  from functools import wraps
3
2
  import numpy as np
4
- from typing import TYPE_CHECKING
5
-
6
- if TYPE_CHECKING:
7
- from scipy import ndimage as scipy_ndi, fft as scipy_fft
8
- from types import ModuleType
9
3
 
10
4
  def cupy_dispatcher(function):
11
5
  @wraps(function)
@@ -16,24 +10,21 @@ def cupy_dispatcher(function):
16
10
  return xp.asnumpy(out)
17
11
  return func
18
12
 
19
- # CUDA <= ver.8 does not have gradient
13
+ # CUDA <= ver.8 does not have gradient
20
14
  def _gradient(a, axis=None):
21
15
  out = np.gradient(a.get(), axis=axis)
22
16
  return xp.asarray(out)
23
17
 
24
- class XP:
18
+ class XP:
25
19
  def __init__(self):
26
20
  self.state = ""
27
21
  self._reset_namespace()
28
22
  self.setNumpy()
29
-
30
- def __getattr__(self, key: str):
31
- return getattr(self._module, key)
32
-
23
+
33
24
  def _reset_namespace(self):
34
25
  self._signal = None
35
26
  self._fft = None
36
-
27
+
37
28
  @property
38
29
  def signal(self):
39
30
  if self._signal is not None:
@@ -47,7 +38,7 @@ class XP:
47
38
  else:
48
39
  raise ValueError(self.state)
49
40
  return self._signal
50
-
41
+
51
42
  @property
52
43
  def fft(self):
53
44
  if self._fft is not None:
@@ -61,13 +52,13 @@ class XP:
61
52
  else:
62
53
  raise ValueError(self.state)
63
54
  return self._fft
64
-
55
+
65
56
  def setNumpy(self) -> None:
66
57
  from scipy import ndimage as scipy_ndi
67
58
 
68
59
  if self.state == "numpy":
69
60
  return
70
-
61
+
71
62
  self._reset_namespace()
72
63
  self._module = np
73
64
  self.linalg = np.linalg
@@ -117,11 +108,12 @@ class XP:
117
108
  self.argmin = np.argmin
118
109
  self.pad = np.pad
119
110
  self.isnan = np.isnan
120
-
111
+ self.eye = np.eye
112
+
121
113
  self.state = "numpy"
122
114
  from ._const import Const
123
115
  Const["SCHEDULER"] = "threads"
124
-
116
+
125
117
  def setCupy(self) -> None:
126
118
  if self.state == "cupy":
127
119
  return
@@ -131,10 +123,10 @@ class XP:
131
123
  if dtype is None:
132
124
  return out
133
125
  return out.astype(dtype)
134
-
126
+
135
127
  from cupyx.scipy import ndimage as cp_ndi
136
128
  from cupy import linalg as cp_linalg
137
-
129
+
138
130
  self._reset_namespace()
139
131
  self._module = cp
140
132
  self.linalg = cp_linalg
@@ -187,10 +179,10 @@ class XP:
187
179
  self.argmin = cp.argmin
188
180
  self.pad = cp.pad
189
181
  self.isnan = cp.isnan
182
+ self.eye = cp.eye
190
183
  self.state = "cupy"
191
-
184
+
192
185
  from ._const import Const
193
186
  Const["SCHEDULER"] = "single-threaded"
194
187
 
195
188
  xp = XP()
196
-
@@ -0,0 +1,17 @@
1
+ from impy.arrays.imgarray import ImgArray
2
+ from impy.arrays.labeledarray import LabeledArray
3
+ from impy.arrays.label import Label
4
+ from impy.arrays.phasearray import PhaseArray
5
+ from impy.arrays.specials import PropArray
6
+ from impy.arrays.lazy import LazyImgArray
7
+ from impy.arrays.big import BigImgArray
8
+
9
+ __all__ = [
10
+ "ImgArray",
11
+ "LabeledArray",
12
+ "Label",
13
+ "PhaseArray",
14
+ "PropArray",
15
+ "LazyImgArray",
16
+ "BigImgArray",
17
+ ]
@@ -10,8 +10,8 @@ from ...array_api import xp
10
10
  # TODO: if max_shifts is small, DFT should be used in place of FFT
11
11
 
12
12
  def _pcc_and_power_spec(
13
- f0: xp.ndarray,
14
- f1: xp.ndarray,
13
+ f0: np.ndarray,
14
+ f1: np.ndarray,
15
15
  max_shifts: tuple[float, ...] | None = None,
16
16
  ):
17
17
  product = f0 * f1.conj()
@@ -23,20 +23,20 @@ def _pcc_and_power_spec(
23
23
  return power, product
24
24
 
25
25
  def draw_pcc_landscape(
26
- f0: xp.ndarray,
27
- f1: xp.ndarray,
26
+ f0: np.ndarray,
27
+ f1: np.ndarray,
28
28
  max_shifts: tuple[float, ...] | None = None,
29
29
  ):
30
30
  power = _pcc_and_power_spec(f0, f1, max_shifts)[0]
31
31
  return xp.fft.fftshift(power)
32
32
 
33
33
  def subpixel_pcc(
34
- f0: xp.ndarray,
35
- f1: xp.ndarray,
34
+ f0: np.ndarray,
35
+ f1: np.ndarray,
36
36
  upsample_factor: int,
37
37
  max_shifts: tuple[float, ...] | None = None,
38
38
  ):
39
- power, product = _pcc_and_power_spec(f0, f1, max_shifts)
39
+ power, product = _pcc_and_power_spec(f0, f1, max_shifts)
40
40
  maxima = xp.unravel_index(xp.argmax(power), power.shape)
41
41
  midpoints = xp.array([np.fix(axis_size / 2) for axis_size in power.shape])
42
42
 
@@ -58,13 +58,13 @@ def subpixel_pcc(
58
58
  ).conj()
59
59
  # Locate maximum and map back to original pixel grid
60
60
  power = abs2(cross_correlation)
61
-
61
+
62
62
  if max_shifts is not None:
63
63
  max_shifts = xp.asarray(max_shifts)
64
64
  _upsampled_left_shifts = (shifts + max_shifts) * upsample_factor
65
65
  _upsampled_right_shifts = (max_shifts - shifts) * upsample_factor
66
66
  power = crop_by_max_shifts(power, _upsampled_left_shifts, _upsampled_right_shifts)
67
-
67
+
68
68
  maxima = xp.unravel_index(xp.argmax(power), power.shape)
69
69
  maxima = xp.asarray(maxima, dtype=np.float32) - dftshift
70
70
  shifts = shifts + maxima / upsample_factor
@@ -74,11 +74,11 @@ def subpixel_pcc(
74
74
  return shifts, pcc
75
75
 
76
76
  def _upsampled_dft(
77
- data: xp.ndarray,
78
- upsampled_region_size: np.ndarray,
79
- upsample_factor: int,
80
- axis_offsets: xp.ndarray
81
- ) -> xp.ndarray:
77
+ data: np.ndarray,
78
+ upsampled_region_size: np.ndarray,
79
+ upsample_factor: int,
80
+ axis_offsets: np.ndarray
81
+ ) -> np.ndarray:
82
82
  # if people pass in an integer, expand it to a list of equal-sized sections
83
83
  upsampled_region_size = [upsampled_region_size,] * data.ndim
84
84
 
@@ -92,14 +92,14 @@ def _upsampled_dft(
92
92
  data = xp.tensordot(kernel, data, axes=(1, -1))
93
93
  return data
94
94
 
95
- def abs2(a: xp.ndarray) -> xp.ndarray:
95
+ def abs2(a: np.ndarray) -> np.ndarray:
96
96
  return a.real**2 + a.imag**2
97
97
 
98
- def crop_by_max_shifts(power: xp.ndarray, left, right):
98
+ def crop_by_max_shifts(power: np.ndarray, left, right):
99
99
  shifted_power = xp.fft.fftshift(power)
100
100
  centers = tuple(s//2 for s in power.shape)
101
101
  slices = tuple(
102
- slice(max(c - int(shiftl), 0), min(c + int(shiftr) + 1, s), None)
102
+ slice(max(c - int(shiftl), 0), min(c + int(shiftr) + 1, s), None)
103
103
  for c, shiftl, shiftr, s in zip(centers, left, right, power.shape)
104
104
  )
105
105
  return xp.fft.ifftshift(shifted_power[slices])
@@ -107,8 +107,8 @@ def crop_by_max_shifts(power: xp.ndarray, left, right):
107
107
  # Normalized cross correlation
108
108
 
109
109
  def _draw_ncc_landscape_no_crop(
110
- img0: xp.ndarray,
111
- img1: xp.ndarray,
110
+ img0: np.ndarray,
111
+ img1: np.ndarray,
112
112
  max_shifts: tuple[float, ...] | None = None,
113
113
  ):
114
114
  ndim = img1.ndim
@@ -116,30 +116,30 @@ def _draw_ncc_landscape_no_crop(
116
116
  max_shifts = tuple(max_shifts)
117
117
  pad_width, sl = _get_padding_params(img0.shape, img1.shape, max_shifts)
118
118
  padimg = xp.pad(img0[sl], pad_width=pad_width, mode="constant", constant_values=0)
119
-
119
+
120
120
  corr = xp.signal.fftconvolve(
121
121
  padimg, img1[(slice(None, None, -1),)*ndim], mode="valid"
122
122
  )[(slice(1, -1, None),)*ndim]
123
-
123
+
124
124
  _win_sum = _window_sum_2d if ndim == 2 else _window_sum_3d
125
125
  win_sum1 = _win_sum(padimg, img1.shape)
126
126
  win_sum2 = _win_sum(padimg**2, img1.shape)
127
-
127
+
128
128
  template_mean = xp.mean(img1)
129
129
  template_volume = xp.prod(xp.array(img1.shape))
130
130
  template_ssd = xp.sum((img1 - template_mean)**2)
131
-
131
+
132
132
  var = (win_sum2 - win_sum1**2 / template_volume) * template_ssd
133
-
133
+
134
134
  # zero division happens when perfectly matched
135
135
  response = xp.zeros_like(corr)
136
136
  mask = var > 0
137
137
  response[mask] = (corr - win_sum1 * template_mean)[mask] / _safe_sqrt(var, fill=np.inf)[mask]
138
138
  return response
139
-
139
+
140
140
  def draw_ncc_landscape(
141
- img0: xp.ndarray,
142
- img1: xp.ndarray,
141
+ img0: np.ndarray,
142
+ img1: np.ndarray,
143
143
  max_shifts: tuple[float, ...] | None = None,
144
144
  ):
145
145
  response = _draw_ncc_landscape_no_crop(img0, img1, max_shifts)
@@ -149,12 +149,12 @@ def draw_ncc_landscape(
149
149
  pad_width_eff = tuple((s - int(m) * 2 - 1)//2 for m, s in zip(max_shifts, response.shape))
150
150
  sl_res = tuple(slice(w, -w, None) for w in pad_width_eff)
151
151
  response_center = response[sl_res]
152
-
152
+
153
153
  return response_center
154
154
 
155
155
  def subpixel_ncc(
156
- img0: xp.ndarray,
157
- img1: xp.ndarray,
156
+ img0: np.ndarray,
157
+ img1: np.ndarray,
158
158
  upsample_factor: int,
159
159
  max_shifts: tuple[float, ...] | None = None,
160
160
  ):
@@ -167,7 +167,7 @@ def subpixel_ncc(
167
167
  response_center = response[sl_res]
168
168
  maxima = xp.unravel_index(xp.argmax(response_center), response_center.shape)
169
169
  midpoints = xp.asarray(response_center.shape) // 2
170
-
170
+
171
171
  if upsample_factor > 1:
172
172
  coords = _create_mesh(upsample_factor, maxima, max_shifts, midpoints, pad_width_eff, xp.state)
173
173
  local_response = xp.ndi.map_coordinates(
@@ -179,7 +179,7 @@ def subpixel_ncc(
179
179
  else:
180
180
  zncc = response[maxima]
181
181
  shifts = xp.array(maxima) - midpoints
182
-
182
+
183
183
  return xp.asarray(shifts, dtype=np.float32), zncc
184
184
 
185
185
  # Identical to skimage.feature.template, but compatible between numpy and cupy.
@@ -202,7 +202,7 @@ def _window_sum_3d(image, window_shape):
202
202
 
203
203
  return window_sum
204
204
 
205
- def _safe_sqrt(a: xp.ndarray, fill=0):
205
+ def _safe_sqrt(a: np.ndarray, fill=0):
206
206
  out = xp.full(a.shape, fill, dtype=np.float32)
207
207
  out = xp.zeros_like(a)
208
208
  mask = a > 0
@@ -211,7 +211,7 @@ def _safe_sqrt(a: xp.ndarray, fill=0):
211
211
 
212
212
  @lru_cache(maxsize=12)
213
213
  def _get_padding_params(
214
- shape0: tuple[int, ...],
214
+ shape0: tuple[int, ...],
215
215
  shape1: tuple[int, ...],
216
216
  max_shifts: tuple[int, ...] | None,
217
217
  ) -> tuple[list[tuple[int, ...]], list[slice] | slice]:
@@ -230,13 +230,13 @@ def _get_padding_params(
230
230
  pad_width.append((0,) * 2)
231
231
  sl.append(slice(-w_int, w_int, None))
232
232
  sl = tuple(sl)
233
-
233
+
234
234
  return pad_width, sl
235
235
 
236
236
 
237
237
  def _create_mesh(
238
238
  upsample_factor: int,
239
- maxima: tuple[int, ...],
239
+ maxima: tuple[int, ...],
240
240
  max_shifts: tuple[int, ...] | None,
241
241
  midpoints: tuple[int, ...],
242
242
  pad_width_eff: tuple[int, ...],
@@ -256,7 +256,7 @@ def _create_mesh(
256
256
  local_shifts = ([-upsample_factor, upsample_factor],) * len(maxima)
257
257
  mesh = xp.meshgrid(
258
258
  *[xp.arange(s0, s1+1)/upsample_factor + m + w
259
- for (s0, s1), m, w in zip(local_shifts, maxima, pad_width_eff)],
259
+ for (s0, s1), m, w in zip(local_shifts, maxima, pad_width_eff)],
260
260
  indexing="ij",
261
261
  )
262
262
  return xp.stack(mesh, axis=0)
@@ -4,15 +4,6 @@ from functools import partial
4
4
  import numpy as np
5
5
  from impy.array_api import xp
6
6
 
7
- try:
8
- gradient = xp.gradient
9
- except AttributeError:
10
- # CUDA <= ver.8 does not have gradient
11
- import numpy
12
- def gradient(a, axis=None):
13
- out = numpy.gradient(a.get(), axis=axis)
14
- return xp.asarray(out)
15
-
16
7
  __all__ = ["wiener", "richardson_lucy", "richardson_lucy_tv", "check_psf"]
17
8
 
18
9
  def wiener(obs, psf_ft, psf_ft_conj, lmd):
@@ -30,7 +21,7 @@ def richardson_lucy(obs, psf_ft, psf_ft_conj, niter, eps):
30
21
  obs = xp.asarray(obs)
31
22
  fft = xp.fft.rfftn
32
23
  ifft = partial(xp.fft.irfftn, s=obs.shape)
33
- conv = factor = xp.empty(obs.shape, dtype=xp.float32) # placeholder
24
+ conv = factor = xp.empty(obs.shape, dtype=np.float32) # placeholder
34
25
  estimated = xp.real(ifft(fft(obs) * psf_ft)) # initialization
35
26
 
36
27
  for _ in range(niter):
@@ -45,16 +36,16 @@ def richardson_lucy_tv(obs, psf_ft, psf_ft_conj, max_iter, lmd, tol, eps):
45
36
  fft = xp.fft.rfftn
46
37
  ifft = partial(xp.fft.irfftn, s=obs.shape)
47
38
  est_old = ifft(fft(obs) * psf_ft).real
48
- est_new = xp.empty(obs.shape, dtype=xp.float32)
39
+ est_new = xp.empty(obs.shape, dtype=np.float32)
49
40
  conv = factor = norm = gg = xp.empty(obs.shape, dtype=np.float32) # placeholder
50
41
 
51
42
  for _ in range(max_iter):
52
43
  conv[:] = ifft(fft(est_old) * psf_ft).real
53
44
  factor[:] = ifft(fft(_safe_div(obs, conv, eps=eps)) * psf_ft_conj).real
54
45
  est_new[:] = est_old * factor
55
- grad = gradient(est_old)
46
+ grad = xp.gradient(est_old)
56
47
  norm[:] = xp.sqrt(sum(g**2 for g in grad))
57
- gg[:] = sum(gradient(_safe_div(grad[i], norm, eps=1e-8), axis=i)
48
+ gg[:] = sum(xp.gradient(_safe_div(grad[i], norm, eps=1e-8), axis=i)
58
49
  for i in range(obs.ndim))
59
50
  est_new /= (1 - lmd * gg)
60
51
  gain = xp.sum(xp.abs(est_new - est_old))/xp.sum(xp.abs(est_old))
@@ -69,7 +69,7 @@ def make_pad(pad_width, dims, all_axes, **kwargs):
69
69
 
70
70
  return pad_width_
71
71
 
72
- def dft(img: xp.ndarray, exps: list[xp.ndarray] = None):
72
+ def dft(img: np.ndarray, exps: list[np.ndarray] = None):
73
73
  """Discrete Fourier Transform."""
74
74
  img = xp.asarray(img)
75
75
  for ker in reversed(exps):
@@ -77,7 +77,7 @@ def dft(img: xp.ndarray, exps: list[xp.ndarray] = None):
77
77
  img = xp.tensordot(xp.asarray(ker), img, axes=(1, -1))
78
78
  return img
79
79
 
80
- def inpaint_mean(img: xp.ndarray, mask: xp.ndarray):
80
+ def inpaint_mean(img: np.ndarray, mask: np.ndarray):
81
81
  """Inpaint missing values with mean of surrounding pixels."""
82
82
  img = xp.asarray(img)
83
83
  mask = xp.asarray(mask)
@@ -343,9 +343,9 @@ def get_fourier_filter(size: int, filter_name: str):
343
343
  cosine_filter = xp.fft.fftshift(xp.sin(freq))
344
344
  fourier_filter *= cosine_filter
345
345
  elif filter_name == "hamming":
346
- fourier_filter *= xp.fft.fftshift(xp.hamming(size))
346
+ fourier_filter *= xp.fft.fftshift(xp._module.hamming(size))
347
347
  elif filter_name == "hann":
348
- fourier_filter *= xp.fft.fftshift(xp.hanning(size))
348
+ fourier_filter *= xp.fft.fftshift(xp._module.hanning(size))
349
349
  elif filter_name is None:
350
350
  fourier_filter[:] = 1
351
351
  else: