impy-array 2.4.7__tar.gz → 2.4.9__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.
- {impy_array-2.4.7 → impy_array-2.4.9}/PKG-INFO +2 -1
- {impy_array-2.4.7 → impy_array-2.4.9}/README.md +1 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/__init__.py +1 -1
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/_const.py +10 -10
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_filters.py +4 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/imgarray.py +90 -38
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/labeledarray.py +72 -15
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/lazy.py +56 -7
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/core.py +8 -16
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/_mrc.py +16 -9
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/_tiff.py +15 -7
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/lazy/core.py +3 -10
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/random.py +4 -4
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/utils/gauss.py +4 -1
- {impy_array-2.4.7 → impy_array-2.4.9}/.gitignore +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/LICENSE +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/__main__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/_types.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/array_api.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_imshow.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_corr.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_deconv.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_docs.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_glcm.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_linalg.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_misc.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_plot.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_process_numba.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_skimage.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_structures.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/_utils/_transform.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/axesmixin.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/bases/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/bases/metaarray.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/bases/overload.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/big.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/label.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/phasearray.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/specials.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/arrays/tiled.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/axes/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/axes/_axes.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/axes/_axes_tuple.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/axes/_axis.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/axes/_slicer.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/binder.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/collections.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/correlation.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/frame/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/frame/frames.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/_nd2.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/_npy.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/_registry.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/_utils.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/io/_zarr.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/lazy/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/lazy/random.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/roi.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/utils/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/utils/axesop.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/utils/deco.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/utils/misc.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/utils/slicer.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/utils/utilcls.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/viewer/__init__.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/viewer/utils.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/impy/viewer/viewer.py +0 -0
- {impy_array-2.4.7 → impy_array-2.4.9}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: impy-array
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.9
|
|
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>
|
|
@@ -131,6 +131,7 @@ img_prj.imsave("image_max.tif") # Save in the same place. Don't spend tim
|
|
|
131
131
|
`impy` automatically chooses the proper reader/writer according to the extension.
|
|
132
132
|
|
|
133
133
|
- Tiff file (".tif", ".tiff")
|
|
134
|
+
- LSM file (".lsm")
|
|
134
135
|
- MRC file (".mrc", ".rec", ".st", ".map", ".map.gz")
|
|
135
136
|
- Zarr file (".zarr")
|
|
136
137
|
- ND2 file (".nd2")
|
|
@@ -58,6 +58,7 @@ img_prj.imsave("image_max.tif") # Save in the same place. Don't spend tim
|
|
|
58
58
|
`impy` automatically chooses the proper reader/writer according to the extension.
|
|
59
59
|
|
|
60
60
|
- Tiff file (".tif", ".tiff")
|
|
61
|
+
- LSM file (".lsm")
|
|
61
62
|
- MRC file (".mrc", ".rec", ".st", ".map", ".map.gz")
|
|
62
63
|
- Zarr file (".zarr")
|
|
63
64
|
- ND2 file (".nd2")
|
|
@@ -8,13 +8,13 @@ MAX_GB_LIMIT = memory.total / 2 * 1e-9
|
|
|
8
8
|
|
|
9
9
|
class GlobalConstant(MutableMapping[str, Any]):
|
|
10
10
|
_const: dict[str, Any]
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
def __init__(self, **kwargs):
|
|
13
13
|
object.__setattr__(self, "_const", dict(**kwargs))
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def __len__(self) -> int:
|
|
16
16
|
return len(self._const)
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
def __iter__(self):
|
|
19
19
|
raise StopIteration
|
|
20
20
|
|
|
@@ -47,15 +47,15 @@ class GlobalConstant(MutableMapping[str, Any]):
|
|
|
47
47
|
dask.config.set(scheduler=v)
|
|
48
48
|
else:
|
|
49
49
|
raise RuntimeError("Cannot set new keys.")
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
self._const[k] = v
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
__getattr__ = __getitem__
|
|
54
54
|
__setattr__ = __setitem__
|
|
55
55
|
|
|
56
56
|
def __delitem__(self, v):
|
|
57
57
|
raise RuntimeError("Cannot delete any items.")
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
def __repr__(self):
|
|
60
60
|
return (
|
|
61
61
|
f"""
|
|
@@ -65,12 +65,12 @@ class GlobalConstant(MutableMapping[str, Any]):
|
|
|
65
65
|
SCHEDULER : {self['SCHEDULER']}
|
|
66
66
|
"""
|
|
67
67
|
)
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
def asdict(self) -> dict[str, Any]:
|
|
70
70
|
return self._const.copy()
|
|
71
71
|
|
|
72
72
|
Const = GlobalConstant(
|
|
73
|
-
MAX_GB = MAX_GB_LIMIT
|
|
73
|
+
MAX_GB = MAX_GB_LIMIT * 0.8,
|
|
74
74
|
ID_AXIS = "N",
|
|
75
75
|
RESOURCE = "numpy",
|
|
76
76
|
SCHEDULER = "threads",
|
|
@@ -80,12 +80,12 @@ class SetConst:
|
|
|
80
80
|
n_ongoing = 0
|
|
81
81
|
_locked_keys: set[str] = set()
|
|
82
82
|
_old_dict: dict[str, Any] = dict()
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
def __init__(self, dict_: dict[str, Any] | None =None, **kwargs):
|
|
85
85
|
dict_ = dict_ or {}
|
|
86
86
|
dict_.update(kwargs)
|
|
87
87
|
self._kwargs = dict_
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
def __enter__(self):
|
|
90
90
|
self.__class__.n_ongoing += 1
|
|
91
91
|
if self.__class__.n_ongoing == 1:
|
|
@@ -52,6 +52,8 @@ binary_closing = get_func("binary_closing")
|
|
|
52
52
|
closing = get_func("grey_closing")
|
|
53
53
|
gaussian_filter = get_func("gaussian_filter")
|
|
54
54
|
median_filter = get_func("median_filter")
|
|
55
|
+
min_filter = get_func("minimum_filter")
|
|
56
|
+
max_filter = get_func("maximum_filter")
|
|
55
57
|
spline_filter = get_func("spline_filter")
|
|
56
58
|
convolve = get_func("convolve")
|
|
57
59
|
white_tophat = get_func("white_tophat")
|
|
@@ -69,6 +71,8 @@ if TYPE_CHECKING:
|
|
|
69
71
|
closing = scipy_ndi.grey_closing
|
|
70
72
|
gaussian_filter = scipy_ndi.gaussian_filter
|
|
71
73
|
median_filter = scipy_ndi.median_filter
|
|
74
|
+
min_filter = scipy_ndi.minimum_filter
|
|
75
|
+
max_filter = scipy_ndi.maximum_filter
|
|
72
76
|
spline_filter = scipy_ndi.spline_filter
|
|
73
77
|
convolve = scipy_ndi.convolve
|
|
74
78
|
white_tophat = scipy_ndi.white_tophat
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import warnings
|
|
3
|
+
from functools import partial
|
|
4
|
+
from itertools import product
|
|
5
|
+
from typing import TYPE_CHECKING, Literal, Sequence, Iterable, Callable, overload, Any
|
|
6
|
+
|
|
3
7
|
import numpy as np
|
|
4
8
|
from numpy.typing import DTypeLike
|
|
5
|
-
from functools import partial
|
|
6
9
|
from scipy import ndimage as ndi
|
|
7
|
-
from typing import TYPE_CHECKING, Literal, Sequence, Iterable, Callable, overload, Any
|
|
8
10
|
|
|
9
11
|
from impy.arrays.labeledarray import LabeledArray
|
|
10
12
|
from impy.arrays.label import Label
|
|
@@ -706,8 +708,7 @@ class ImgArray(LabeledArray):
|
|
|
706
708
|
@dims_to_spatial_axes
|
|
707
709
|
@check_input_and_output
|
|
708
710
|
def structure_tensor_eig(self, sigma: nDFloat = 1, *, dims: Dims = None)-> tuple[ImgArray, ImgArray]:
|
|
709
|
-
"""
|
|
710
|
-
Calculate structure tensor's eigenvalues and eigenvectors.
|
|
711
|
+
"""Calculate structure tensor's eigenvalues and eigenvectors.
|
|
711
712
|
|
|
712
713
|
Parameters
|
|
713
714
|
----------
|
|
@@ -747,8 +748,7 @@ class ImgArray(LabeledArray):
|
|
|
747
748
|
dims: Dims = None,
|
|
748
749
|
update: bool = False
|
|
749
750
|
) -> ImgArray:
|
|
750
|
-
"""
|
|
751
|
-
Sobel filter. This filter is useful for edge detection.
|
|
751
|
+
"""Edge detection such as Sobel filter.
|
|
752
752
|
|
|
753
753
|
Parameters
|
|
754
754
|
----------
|
|
@@ -783,8 +783,7 @@ class ImgArray(LabeledArray):
|
|
|
783
783
|
dims: Dims = None,
|
|
784
784
|
update: bool = False,
|
|
785
785
|
) -> ImgArray:
|
|
786
|
-
"""
|
|
787
|
-
Butterworth low-pass filter.
|
|
786
|
+
"""Butterworth low-pass filter.
|
|
788
787
|
|
|
789
788
|
Parameters
|
|
790
789
|
----------
|
|
@@ -829,9 +828,10 @@ class ImgArray(LabeledArray):
|
|
|
829
828
|
dims: Dims = None,
|
|
830
829
|
update: bool = False
|
|
831
830
|
) -> ImgArray:
|
|
832
|
-
"""
|
|
833
|
-
|
|
834
|
-
Fourier transform of weight
|
|
831
|
+
"""Butterworth low-pass filter in real space.
|
|
832
|
+
|
|
833
|
+
Butterworth kernel is created first using inverse Fourier transform of weight
|
|
834
|
+
function.
|
|
835
835
|
|
|
836
836
|
Parameters
|
|
837
837
|
----------
|
|
@@ -874,8 +874,7 @@ class ImgArray(LabeledArray):
|
|
|
874
874
|
dims: Dims = None,
|
|
875
875
|
update: bool = False
|
|
876
876
|
) -> ImgArray:
|
|
877
|
-
"""
|
|
878
|
-
Butterworth high-pass filter.
|
|
877
|
+
"""Butterworth high-pass filter.
|
|
879
878
|
|
|
880
879
|
Parameters
|
|
881
880
|
----------
|
|
@@ -916,8 +915,7 @@ class ImgArray(LabeledArray):
|
|
|
916
915
|
dims: Dims = None,
|
|
917
916
|
update: bool = False
|
|
918
917
|
):
|
|
919
|
-
"""
|
|
920
|
-
Butterworth band-pass filter.
|
|
918
|
+
"""Butterworth band-pass filter.
|
|
921
919
|
|
|
922
920
|
Parameters
|
|
923
921
|
----------
|
|
@@ -961,8 +959,7 @@ class ImgArray(LabeledArray):
|
|
|
961
959
|
dims: Dims = None,
|
|
962
960
|
update: bool = False,
|
|
963
961
|
) -> ImgArray:
|
|
964
|
-
"""
|
|
965
|
-
General linear convolution by running kernel filtering.
|
|
962
|
+
"""General linear convolution by running kernel filtering.
|
|
966
963
|
|
|
967
964
|
Parameters
|
|
968
965
|
----------
|
|
@@ -996,8 +993,7 @@ class ImgArray(LabeledArray):
|
|
|
996
993
|
dims: Dims = None,
|
|
997
994
|
update: bool = False,
|
|
998
995
|
) -> ImgArray:
|
|
999
|
-
"""
|
|
1000
|
-
Morphological erosion.
|
|
996
|
+
"""Morphological erosion.
|
|
1001
997
|
|
|
1002
998
|
If input is binary image, the running function will automatically switched to
|
|
1003
999
|
``binary_erosion`` to speed up calculation.
|
|
@@ -1037,8 +1033,9 @@ class ImgArray(LabeledArray):
|
|
|
1037
1033
|
dims: Dims = None,
|
|
1038
1034
|
update: bool = False,
|
|
1039
1035
|
) -> ImgArray:
|
|
1040
|
-
"""
|
|
1041
|
-
|
|
1036
|
+
"""Morphological dilation.
|
|
1037
|
+
|
|
1038
|
+
If input is binary image, the running function will automatically switched to
|
|
1042
1039
|
``binary_dilation`` to speed up calculation.
|
|
1043
1040
|
|
|
1044
1041
|
Parameters
|
|
@@ -1076,8 +1073,9 @@ class ImgArray(LabeledArray):
|
|
|
1076
1073
|
dims: Dims = None,
|
|
1077
1074
|
update: bool = False,
|
|
1078
1075
|
) -> ImgArray:
|
|
1079
|
-
"""
|
|
1080
|
-
|
|
1076
|
+
"""Morphological opening.
|
|
1077
|
+
|
|
1078
|
+
If input is binary image, the running function will automatically switched to
|
|
1081
1079
|
``binary_opening`` to speed up calculation.
|
|
1082
1080
|
|
|
1083
1081
|
Parameters
|
|
@@ -1115,8 +1113,7 @@ class ImgArray(LabeledArray):
|
|
|
1115
1113
|
dims: Dims = None,
|
|
1116
1114
|
update: bool = False,
|
|
1117
1115
|
) -> ImgArray:
|
|
1118
|
-
"""
|
|
1119
|
-
Morphological closing.
|
|
1116
|
+
"""Morphological closing.
|
|
1120
1117
|
|
|
1121
1118
|
If input is binary image, the running function will automatically switched to
|
|
1122
1119
|
``binary_closing`` to speed up calculation.
|
|
@@ -1156,8 +1153,7 @@ class ImgArray(LabeledArray):
|
|
|
1156
1153
|
dims: Dims = None,
|
|
1157
1154
|
update: bool = False,
|
|
1158
1155
|
) -> ImgArray:
|
|
1159
|
-
"""
|
|
1160
|
-
Tophat morphological image processing. This is useful for background subtraction.
|
|
1156
|
+
"""Tophat morphological image processing. This is useful for background subtraction.
|
|
1161
1157
|
|
|
1162
1158
|
Parameters
|
|
1163
1159
|
----------
|
|
@@ -1188,8 +1184,7 @@ class ImgArray(LabeledArray):
|
|
|
1188
1184
|
*,
|
|
1189
1185
|
dims: Dims = None
|
|
1190
1186
|
) -> ImgArray:
|
|
1191
|
-
"""
|
|
1192
|
-
Smoothen binary mask image at its edges. This is useful to make a "soft mask".
|
|
1187
|
+
"""Smoothen binary mask image at its edges. This is useful to make a "soft mask".
|
|
1193
1188
|
|
|
1194
1189
|
This method applies erosion/dilation to a binary image and then smooth its edges by Gaussian.
|
|
1195
1190
|
The total value is always larger after Gaussian smoothing.
|
|
@@ -1241,8 +1236,7 @@ class ImgArray(LabeledArray):
|
|
|
1241
1236
|
cval: float = 0.0,
|
|
1242
1237
|
dims: Dims = None,
|
|
1243
1238
|
update: bool = False) -> ImgArray:
|
|
1244
|
-
"""
|
|
1245
|
-
Mean filter. Kernel is filled with same values.
|
|
1239
|
+
"""Mean filter. Kernel is filled with same values.
|
|
1246
1240
|
|
|
1247
1241
|
Parameters
|
|
1248
1242
|
----------
|
|
@@ -1262,6 +1256,65 @@ class ImgArray(LabeledArray):
|
|
|
1262
1256
|
kwargs=dict(mode=mode, cval=cval),
|
|
1263
1257
|
)
|
|
1264
1258
|
|
|
1259
|
+
|
|
1260
|
+
@_docs.write_docs
|
|
1261
|
+
@dims_to_spatial_axes
|
|
1262
|
+
@check_input_and_output
|
|
1263
|
+
def min_filter(
|
|
1264
|
+
self,
|
|
1265
|
+
radius: float = 1,
|
|
1266
|
+
*,
|
|
1267
|
+
mode: PaddingMode = "reflect",
|
|
1268
|
+
cval: float = 0.0,
|
|
1269
|
+
dims: Dims = None,
|
|
1270
|
+
) -> ImgArray:
|
|
1271
|
+
"""Minimum filter.
|
|
1272
|
+
|
|
1273
|
+
Parameters
|
|
1274
|
+
----------
|
|
1275
|
+
{radius}{mode}{cval}{dims}
|
|
1276
|
+
|
|
1277
|
+
Returns
|
|
1278
|
+
-------
|
|
1279
|
+
ImgArray
|
|
1280
|
+
Filtered image
|
|
1281
|
+
"""
|
|
1282
|
+
disk = _structures.ball_like(radius, len(dims))
|
|
1283
|
+
return self.as_float()._apply_dask(
|
|
1284
|
+
_filters.min_filter,
|
|
1285
|
+
c_axes=complement_axes(dims, self.axes),
|
|
1286
|
+
kwargs=dict(footprint=disk, mode=mode, cval=cval),
|
|
1287
|
+
)
|
|
1288
|
+
|
|
1289
|
+
@_docs.write_docs
|
|
1290
|
+
@dims_to_spatial_axes
|
|
1291
|
+
@check_input_and_output
|
|
1292
|
+
def max_filter(
|
|
1293
|
+
self,
|
|
1294
|
+
radius: float = 1,
|
|
1295
|
+
*,
|
|
1296
|
+
mode: PaddingMode = "reflect",
|
|
1297
|
+
cval: float = 0.0,
|
|
1298
|
+
dims: Dims = None,
|
|
1299
|
+
) -> ImgArray:
|
|
1300
|
+
"""Maximum filter.
|
|
1301
|
+
|
|
1302
|
+
Parameters
|
|
1303
|
+
----------
|
|
1304
|
+
{radius}{mode}{cval}{dims}
|
|
1305
|
+
|
|
1306
|
+
Returns
|
|
1307
|
+
-------
|
|
1308
|
+
ImgArray
|
|
1309
|
+
Filtered image
|
|
1310
|
+
"""
|
|
1311
|
+
disk = _structures.ball_like(radius, len(dims))
|
|
1312
|
+
return self.as_float()._apply_dask(
|
|
1313
|
+
_filters.max_filter,
|
|
1314
|
+
c_axes=complement_axes(dims, self.axes),
|
|
1315
|
+
kwargs=dict(footprint=disk, mode=mode, cval=cval),
|
|
1316
|
+
)
|
|
1317
|
+
|
|
1265
1318
|
@_docs.write_docs
|
|
1266
1319
|
@dims_to_spatial_axes
|
|
1267
1320
|
@check_input_and_output
|
|
@@ -3987,8 +4040,7 @@ class ImgArray(LabeledArray):
|
|
|
3987
4040
|
upsample_factor: int = 10,
|
|
3988
4041
|
max_shift: nDFloat | None = None,
|
|
3989
4042
|
) -> MarkerFrame:
|
|
3990
|
-
"""
|
|
3991
|
-
Calculate yx-directional drift using the method equivalent to
|
|
4043
|
+
"""Calculate yx-directional drift using the method equivalent to
|
|
3992
4044
|
``skimage.registration.phase_cross_correlation``.
|
|
3993
4045
|
|
|
3994
4046
|
Parameters
|
|
@@ -4063,9 +4115,10 @@ class ImgArray(LabeledArray):
|
|
|
4063
4115
|
dims: Dims = 2,
|
|
4064
4116
|
update: bool = False,
|
|
4065
4117
|
) -> ImgArray:
|
|
4066
|
-
"""
|
|
4067
|
-
|
|
4068
|
-
is not given, then it will be determined using
|
|
4118
|
+
"""Drift correction using iterative Affine translation.
|
|
4119
|
+
|
|
4120
|
+
If translation vectors ``shift`` is not given, then it will be determined using
|
|
4121
|
+
``track_drift`` method of ImgArray.
|
|
4069
4122
|
|
|
4070
4123
|
Parameters
|
|
4071
4124
|
----------
|
|
@@ -4092,7 +4145,7 @@ class ImgArray(LabeledArray):
|
|
|
4092
4145
|
Examples
|
|
4093
4146
|
--------
|
|
4094
4147
|
Drift correction of multichannel image using the first channel as the reference.
|
|
4095
|
-
|
|
4148
|
+
>>> img.drift_correction(ref=img["c=0"])
|
|
4096
4149
|
"""
|
|
4097
4150
|
|
|
4098
4151
|
if along is None:
|
|
@@ -4107,7 +4160,6 @@ class ImgArray(LabeledArray):
|
|
|
4107
4160
|
elif not isinstance(ref, ImgArray):
|
|
4108
4161
|
ref = self[ref]
|
|
4109
4162
|
if ref.axes != [along] + dims:
|
|
4110
|
-
from itertools import product
|
|
4111
4163
|
_c_axes = complement_axes([along] + dims, str(ref.axes))
|
|
4112
4164
|
fmt = slicer.get_formatter(_c_axes)
|
|
4113
4165
|
out = np.empty_like(self)
|
|
@@ -3,7 +3,7 @@ import numpy as np
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
import itertools
|
|
5
5
|
from functools import partial
|
|
6
|
-
from typing import TYPE_CHECKING, Any, Sequence, MutableMapping, Protocol
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Literal, Sequence, MutableMapping, Protocol
|
|
7
7
|
from warnings import warn
|
|
8
8
|
from scipy import ndimage as ndi
|
|
9
9
|
|
|
@@ -23,7 +23,7 @@ from impy.array_api import xp
|
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
25
|
from typing_extensions import Self
|
|
26
|
-
from numpy.typing import ArrayLike, DTypeLike
|
|
26
|
+
from numpy.typing import ArrayLike, DTypeLike, NDArray
|
|
27
27
|
from impy.frame import PathFrame
|
|
28
28
|
from impy.roi import RoiList
|
|
29
29
|
|
|
@@ -401,10 +401,18 @@ class LabeledArray(MetaArray):
|
|
|
401
401
|
out._set_info(self)
|
|
402
402
|
return out
|
|
403
403
|
|
|
404
|
-
def as_float(self) -> Self:
|
|
405
|
-
if
|
|
404
|
+
def as_float(self, *, depth: int = 32) -> Self:
|
|
405
|
+
if depth == 16:
|
|
406
|
+
dtype = np.float16
|
|
407
|
+
elif depth == 32:
|
|
408
|
+
dtype = np.float32
|
|
409
|
+
elif depth == 64:
|
|
410
|
+
dtype = np.float64
|
|
411
|
+
else:
|
|
412
|
+
raise ValueError(f"depth must be 16, 32, or 64, but got {depth}")
|
|
413
|
+
if self.dtype == dtype:
|
|
406
414
|
return self
|
|
407
|
-
out = self.value.astype(
|
|
415
|
+
out = self.value.astype(dtype).view(self.__class__)
|
|
408
416
|
out._set_info(self)
|
|
409
417
|
return out
|
|
410
418
|
|
|
@@ -417,8 +425,12 @@ class LabeledArray(MetaArray):
|
|
|
417
425
|
return self.as_uint16()
|
|
418
426
|
elif dtype == "uint8":
|
|
419
427
|
return self.as_uint8()
|
|
428
|
+
elif dtype == "float16":
|
|
429
|
+
return self.as_float(depth=16)
|
|
420
430
|
elif dtype == "float32":
|
|
421
|
-
return self.as_float()
|
|
431
|
+
return self.as_float(depth=32)
|
|
432
|
+
elif dtype == "float64":
|
|
433
|
+
return self.as_float(depth=64)
|
|
422
434
|
elif dtype == "bool":
|
|
423
435
|
return self.astype("bool")
|
|
424
436
|
elif dtype == "float64":
|
|
@@ -576,6 +588,7 @@ class LabeledArray(MetaArray):
|
|
|
576
588
|
*,
|
|
577
589
|
order: int = 3,
|
|
578
590
|
prefilter: bool | None = None,
|
|
591
|
+
how: Literal["pack", "equal"] = "pack",
|
|
579
592
|
) -> PropArray:
|
|
580
593
|
"""
|
|
581
594
|
Measure line profile (kymograph) iteratively for every slice of image. This
|
|
@@ -590,7 +603,12 @@ class LabeledArray(MetaArray):
|
|
|
590
603
|
`a = [[y0, x0], [y1, x1], ..., [yn, xn]]`
|
|
591
604
|
b : array-like, optional
|
|
592
605
|
Destination coordinate. If specified, `a` must be the source coordinate.
|
|
593
|
-
{order}
|
|
606
|
+
{order}{prefilter}
|
|
607
|
+
how : "pack" or "equal", default "pack"
|
|
608
|
+
How to sample points on the line. "pack" means that the points are sampled
|
|
609
|
+
at 1-px interval from the start point. "equal" means that the points are
|
|
610
|
+
sampled equally at the interval larger but neareset to 1-px so that the
|
|
611
|
+
points covers the entire line.
|
|
594
612
|
|
|
595
613
|
Returns
|
|
596
614
|
-------
|
|
@@ -616,7 +634,12 @@ class LabeledArray(MetaArray):
|
|
|
616
634
|
a = np.asarray(a, dtype=np.float32)
|
|
617
635
|
_, ndim = a.shape
|
|
618
636
|
seg = SegmentedLine(a)
|
|
619
|
-
|
|
637
|
+
if how == "pack":
|
|
638
|
+
coords = np.stack(seg.arange(), axis=0)
|
|
639
|
+
elif how == "equal":
|
|
640
|
+
coords = np.stack(seg.linspace(int(seg.length())), axis=0)
|
|
641
|
+
else:
|
|
642
|
+
raise ValueError(f"No option matches how={how}")
|
|
620
643
|
|
|
621
644
|
if ndim == self.ndim:
|
|
622
645
|
dims = self.axes
|
|
@@ -632,7 +655,11 @@ class LabeledArray(MetaArray):
|
|
|
632
655
|
axes=c_axes+[new_axis], propname="reslice")
|
|
633
656
|
|
|
634
657
|
out.set_scale(self)
|
|
635
|
-
|
|
658
|
+
axis = self.axes[dims[-1]]
|
|
659
|
+
if how == "equal":
|
|
660
|
+
out.set_scale({new_axis: axis.scale * seg.interv}, unit=axis.unit)
|
|
661
|
+
else:
|
|
662
|
+
out.set_scale({new_axis: axis.scale}, unit=axis.unit)
|
|
636
663
|
return out
|
|
637
664
|
|
|
638
665
|
@_docs.write_docs
|
|
@@ -1576,31 +1603,61 @@ class SegmentedLine:
|
|
|
1576
1603
|
dist = np.sqrt(np.sum(vec**2, axis=1))
|
|
1577
1604
|
dist_sum = np.sum(dist)
|
|
1578
1605
|
npoints = int(dist_sum)
|
|
1579
|
-
interv = dist_sum / npoints
|
|
1606
|
+
self.interv = dist_sum / npoints
|
|
1580
1607
|
|
|
1581
|
-
self.length = dist_sum
|
|
1582
1608
|
self.vec = vec
|
|
1583
1609
|
self.dist = dist
|
|
1584
1610
|
self.nodes = nodes
|
|
1585
|
-
self.interv = interv
|
|
1586
1611
|
|
|
1587
1612
|
def sample_points(self) -> np.ndarray:
|
|
1588
1613
|
res = 0
|
|
1589
1614
|
out = [self.nodes[0:1]]
|
|
1590
1615
|
npoints = 1
|
|
1616
|
+
interv = self.length() / int(self.length())
|
|
1591
1617
|
for v, d, p in zip(self.vec, self.dist, self.nodes[:-1]):
|
|
1592
1618
|
res0 = res
|
|
1593
|
-
d_int, res = divmod(d + res,
|
|
1594
|
-
idx =
|
|
1619
|
+
d_int, res = divmod(d + res, interv)
|
|
1620
|
+
idx = interv * (np.arange(d_int) + 1) - res0
|
|
1595
1621
|
xs = idx[:, np.newaxis] * v[np.newaxis]/d + p
|
|
1596
1622
|
out.append(xs)
|
|
1597
1623
|
npoints += xs.shape[0]
|
|
1598
1624
|
|
|
1599
|
-
if npoints <= int(self.length):
|
|
1625
|
+
if npoints <= int(self.length()):
|
|
1600
1626
|
out.append(self.nodes[-1:])
|
|
1601
1627
|
|
|
1602
1628
|
return np.concatenate(out, axis=0)
|
|
1603
1629
|
|
|
1630
|
+
def length(self) -> np.float64:
|
|
1631
|
+
return np.sum(self.lengths())
|
|
1632
|
+
|
|
1633
|
+
def lengths(self) -> NDArray[np.float64]:
|
|
1634
|
+
return np.sqrt(np.sum(np.diff(self.nodes, axis=0) ** 2, axis=1))
|
|
1635
|
+
|
|
1636
|
+
def linspace(self, num: int) -> tuple[NDArray[np.float64], ...]:
|
|
1637
|
+
"""Return a tuple of x and y coordinates of np.linspace along the line."""
|
|
1638
|
+
tnots = np.cumsum(
|
|
1639
|
+
np.concatenate([[0], self.lengths()], dtype=np.float64)
|
|
1640
|
+
)
|
|
1641
|
+
teval = np.linspace(0, tnots[-1], num)
|
|
1642
|
+
return tuple(
|
|
1643
|
+
np.interp(teval, tnots, self.nodes[:, i])
|
|
1644
|
+
for i in range(self.nodes.shape[1])
|
|
1645
|
+
)
|
|
1646
|
+
|
|
1647
|
+
def arange(
|
|
1648
|
+
self, step: float = 1.0
|
|
1649
|
+
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
|
|
1650
|
+
tnots = np.cumsum(
|
|
1651
|
+
np.concatenate([[0], self.lengths()], dtype=np.float64)
|
|
1652
|
+
)
|
|
1653
|
+
length = tnots[-1]
|
|
1654
|
+
num, rem = divmod(length, step)
|
|
1655
|
+
teval = np.linspace(0, length - rem, int(num + 1))
|
|
1656
|
+
return tuple(
|
|
1657
|
+
np.interp(teval, tnots, self.nodes[:, i])
|
|
1658
|
+
for i in range(self.nodes.shape[1])
|
|
1659
|
+
)
|
|
1660
|
+
|
|
1604
1661
|
def _count_list_depth(x) -> int:
|
|
1605
1662
|
n = 0
|
|
1606
1663
|
out = x
|
|
@@ -890,6 +890,47 @@ class LazyImgArray(AxesMixin):
|
|
|
890
890
|
kwargs=dict(footprint=disk, mode=mode, cval=cval),
|
|
891
891
|
)
|
|
892
892
|
|
|
893
|
+
@_docs.copy_docs(ImgArray.min_filter)
|
|
894
|
+
@dims_to_spatial_axes
|
|
895
|
+
@same_dtype
|
|
896
|
+
@check_input_and_output_lazy
|
|
897
|
+
def min_filter(
|
|
898
|
+
self,
|
|
899
|
+
radius: float = 1,
|
|
900
|
+
*,
|
|
901
|
+
mode: PaddingMode = "reflect",
|
|
902
|
+
cval: float = 0,
|
|
903
|
+
dims: Dims = None,
|
|
904
|
+
update: bool = False
|
|
905
|
+
) -> LazyImgArray:
|
|
906
|
+
disk = _structures.ball_like(radius, len(dims))
|
|
907
|
+
return self._apply_map_overlap(
|
|
908
|
+
xp.ndi.minimum_filter,
|
|
909
|
+
depth=_ceilint(radius),
|
|
910
|
+
c_axes=complement_axes(dims, self.axes),
|
|
911
|
+
kwargs=dict(footprint=disk, mode=mode, cval=cval),
|
|
912
|
+
)
|
|
913
|
+
|
|
914
|
+
@_docs.copy_docs(ImgArray.max_filter)
|
|
915
|
+
@dims_to_spatial_axes
|
|
916
|
+
@same_dtype
|
|
917
|
+
@check_input_and_output_lazy
|
|
918
|
+
def max_filter(
|
|
919
|
+
self,
|
|
920
|
+
radius: float = 1,
|
|
921
|
+
*,
|
|
922
|
+
mode: PaddingMode = "reflect",
|
|
923
|
+
cval: float = 0,
|
|
924
|
+
dims: Dims = None,
|
|
925
|
+
update: bool = False
|
|
926
|
+
) -> LazyImgArray:
|
|
927
|
+
disk = _structures.ball_like(radius, len(dims))
|
|
928
|
+
return self._apply_map_overlap(
|
|
929
|
+
xp.ndi.maximum_filter,
|
|
930
|
+
depth=_ceilint(radius),
|
|
931
|
+
c_axes=complement_axes(dims, self.axes),
|
|
932
|
+
kwargs=dict(footprint=disk, mode=mode, cval=cval),
|
|
933
|
+
)
|
|
893
934
|
|
|
894
935
|
@_docs.copy_docs(ImgArray.std_filter)
|
|
895
936
|
@dims_to_spatial_axes
|
|
@@ -1612,10 +1653,18 @@ class LazyImgArray(AxesMixin):
|
|
|
1612
1653
|
out._set_info(self)
|
|
1613
1654
|
return out
|
|
1614
1655
|
|
|
1615
|
-
def as_float(self) -> LazyImgArray:
|
|
1616
|
-
if
|
|
1656
|
+
def as_float(self, *, depth: int = 32) -> LazyImgArray:
|
|
1657
|
+
if depth == 16:
|
|
1658
|
+
dtype = np.float16
|
|
1659
|
+
elif depth == 32:
|
|
1660
|
+
dtype = np.float32
|
|
1661
|
+
elif depth == 64:
|
|
1662
|
+
dtype = np.float64
|
|
1663
|
+
else:
|
|
1664
|
+
raise ValueError(f"depth must be 16, 32, or 64, but got {depth}")
|
|
1665
|
+
if self.dtype == dtype:
|
|
1617
1666
|
return self
|
|
1618
|
-
out = self.value.astype(
|
|
1667
|
+
out = self.value.astype(dtype)
|
|
1619
1668
|
out = self.__class__(out)
|
|
1620
1669
|
out._set_info(self)
|
|
1621
1670
|
return out
|
|
@@ -1628,12 +1677,12 @@ class LazyImgArray(AxesMixin):
|
|
|
1628
1677
|
return self.as_uint16()
|
|
1629
1678
|
elif dtype == "uint8":
|
|
1630
1679
|
return self.as_uint8()
|
|
1680
|
+
elif dtype == "float16":
|
|
1681
|
+
return self.as_float(depth=16)
|
|
1631
1682
|
elif dtype == "float32":
|
|
1632
|
-
return self.as_float()
|
|
1683
|
+
return self.as_float(depth=32)
|
|
1633
1684
|
elif dtype == "float64":
|
|
1634
|
-
|
|
1635
|
-
UserWarning)
|
|
1636
|
-
return self.as_float()
|
|
1685
|
+
return self.as_float(depth=64)
|
|
1637
1686
|
elif dtype == "complex64":
|
|
1638
1687
|
out = self.value.astype(np.complex64)
|
|
1639
1688
|
out = self.__class__(out)
|
|
@@ -99,8 +99,7 @@ def array(
|
|
|
99
99
|
axes: str = None,
|
|
100
100
|
like: MetaArray | None = None,
|
|
101
101
|
) -> ImgArray:
|
|
102
|
-
"""
|
|
103
|
-
make an ImgArray object, like ``np.array(x)``
|
|
102
|
+
"""Make an ImgArray object, like ``np.array(x)``
|
|
104
103
|
|
|
105
104
|
Parameters
|
|
106
105
|
----------
|
|
@@ -116,12 +115,7 @@ def array(
|
|
|
116
115
|
|
|
117
116
|
"""
|
|
118
117
|
if isinstance(arr, np.ndarray) and dtype is None:
|
|
119
|
-
|
|
120
|
-
dtype = arr.dtype
|
|
121
|
-
elif arr.dtype.kind == "f":
|
|
122
|
-
dtype = np.float32
|
|
123
|
-
else:
|
|
124
|
-
dtype = arr.dtype
|
|
118
|
+
dtype = arr.dtype
|
|
125
119
|
|
|
126
120
|
axes, name = _normalize_params(axes, name, like)
|
|
127
121
|
|
|
@@ -150,8 +144,7 @@ def asarray(
|
|
|
150
144
|
axes: str | None = None,
|
|
151
145
|
like: MetaArray | None = None,
|
|
152
146
|
) -> ImgArray:
|
|
153
|
-
"""
|
|
154
|
-
make an ImgArray object, like ``np.asarray(x)``
|
|
147
|
+
"""Make an ImgArray object, like ``np.asarray(x)``
|
|
155
148
|
|
|
156
149
|
Parameters
|
|
157
150
|
----------
|
|
@@ -296,9 +289,8 @@ def _inject_numpy_function(func: Callable[_P, Any | None]) -> Callable[_P, ImgAr
|
|
|
296
289
|
return asarray(npfunc(*args, **kwargs), name=name, axes=axes, like=like)
|
|
297
290
|
|
|
298
291
|
_func.__doc__ = (
|
|
299
|
-
f"""
|
|
300
|
-
|
|
301
|
-
and ``name``. Original docstring follows.
|
|
292
|
+
f"""impy version of numpy.{func.__name__}. This function has additional
|
|
293
|
+
parameters ``axes`` and ``name``. Original docstring follows.
|
|
302
294
|
|
|
303
295
|
Additional Parameters
|
|
304
296
|
---------------------
|
|
@@ -396,7 +388,7 @@ def gaussian_kernel(
|
|
|
396
388
|
"""
|
|
397
389
|
if np.isscalar(sigma):
|
|
398
390
|
sigma = (sigma,)*len(shape)
|
|
399
|
-
g = gauss.GaussianParticle([(np.array(shape)-1)/2, sigma, peak, 0])
|
|
391
|
+
g = gauss.GaussianParticle([(np.array(shape) - 1) / 2, sigma, peak, 0])
|
|
400
392
|
ker = g.generate(shape)
|
|
401
393
|
ker = array(ker, name=name or "Gaussian-Kernel", axes=axes)
|
|
402
394
|
if axes is None and ker.ndim == 3:
|
|
@@ -551,12 +543,12 @@ def imread(
|
|
|
551
543
|
return _imread_stack(path, dtype=dtype, key=key, squeeze=squeeze)
|
|
552
544
|
elif "*" in path:
|
|
553
545
|
return _imread_glob(path, dtype=dtype, key=key, squeeze=squeeze)
|
|
554
|
-
elif not
|
|
546
|
+
elif not Path(path).exists():
|
|
555
547
|
raise FileNotFoundError(f"No such file or directory: {path}")
|
|
556
548
|
|
|
557
549
|
# read tif metadata
|
|
558
550
|
if not is_memmap:
|
|
559
|
-
size =
|
|
551
|
+
size = Path(path).stat().st_size / 2**30
|
|
560
552
|
if size > Const["MAX_GB"]:
|
|
561
553
|
raise MemoryError(f"Too large {size:.2f} GB")
|
|
562
554
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import TYPE_CHECKING
|
|
4
5
|
import warnings
|
|
5
6
|
import os
|
|
@@ -59,7 +60,13 @@ def _(path: str, img: ImpyArray, lazy: bool = False):
|
|
|
59
60
|
|
|
60
61
|
if img.dtype == "bool":
|
|
61
62
|
img = img.astype(np.int8)
|
|
62
|
-
|
|
63
|
+
elif img.dtype == "float64":
|
|
64
|
+
warnings.warn(
|
|
65
|
+
"MRC format does not support float64. Converting to float32.",
|
|
66
|
+
UserWarning,
|
|
67
|
+
stacklevel=2,
|
|
68
|
+
)
|
|
69
|
+
img = img.astype(np.float32)
|
|
63
70
|
if lazy:
|
|
64
71
|
from dask import array as da
|
|
65
72
|
|
|
@@ -75,9 +82,10 @@ def _(path: str, img: ImpyArray, lazy: bool = False):
|
|
|
75
82
|
# get voxel_size
|
|
76
83
|
if img.axes not in ("zyx", "yx"):
|
|
77
84
|
raise ImageAxesError(
|
|
78
|
-
f"Can only save zyx- or yx- image as a mrc file, but image has {img.axes}
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
f"Can only save zyx- or yx- image as a mrc file, but image has {img.axes} "
|
|
86
|
+
"axes."
|
|
87
|
+
)
|
|
88
|
+
if Path(path).exists():
|
|
81
89
|
with mrcfile.open(path, mode="r+") as mrc:
|
|
82
90
|
mrc.set_data(img.value)
|
|
83
91
|
mrc.voxel_size = voxel_size
|
|
@@ -98,13 +106,12 @@ _MRC_MODE = {
|
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
def _parse_mrcfile(mrc: MrcObject) -> ImageMetadata:
|
|
101
|
-
|
|
102
|
-
if ndim == 3:
|
|
103
|
-
axes = "zyx"
|
|
104
|
-
elif ndim == 2:
|
|
109
|
+
if mrc.is_single_image():
|
|
105
110
|
axes = "yx"
|
|
111
|
+
elif mrc.is_volume_stack():
|
|
112
|
+
axes = "tzyx"
|
|
106
113
|
else:
|
|
107
|
-
|
|
114
|
+
axes = "zyx"
|
|
108
115
|
|
|
109
116
|
scale = dict.fromkeys(axes, 1.0)
|
|
110
117
|
for a in axes:
|
|
@@ -14,7 +14,7 @@ from impy.utils.axesop import complement_axes
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from tifffile import TiffFile
|
|
16
16
|
|
|
17
|
-
@IO.mark_reader(".tif", ".tiff")
|
|
17
|
+
@IO.mark_reader(".tif", ".tiff", ".lsm")
|
|
18
18
|
def _(path: str, memmap: bool = False) -> ImageData:
|
|
19
19
|
"""The tif file reader."""
|
|
20
20
|
from tifffile import TiffFile
|
|
@@ -28,7 +28,7 @@ def _(path: str, memmap: bool = False) -> ImageData:
|
|
|
28
28
|
|
|
29
29
|
return ImageData.from_metadata(image, meta)
|
|
30
30
|
|
|
31
|
-
@IO.mark_header_reader(".tif", ".tiff")
|
|
31
|
+
@IO.mark_header_reader(".tif", ".tiff", ".lsm")
|
|
32
32
|
def _(path: str) -> ImageMetadata:
|
|
33
33
|
"""The tif header reader."""
|
|
34
34
|
from tifffile import TiffFile
|
|
@@ -39,7 +39,7 @@ def _(path: str) -> ImageMetadata:
|
|
|
39
39
|
return meta
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
@IO.mark_writer(".tif", ".tiff")
|
|
42
|
+
@IO.mark_writer(".tif", ".tiff", ".lsm")
|
|
43
43
|
def _(path: str, img: ImpyArray, lazy: bool = False):
|
|
44
44
|
"""The TIFF writer."""
|
|
45
45
|
from tifffile import imwrite, memmap
|
|
@@ -103,7 +103,7 @@ def _parse_tifffile(tif: TiffFile) -> ImageMetadata:
|
|
|
103
103
|
tags = {v.name: v.value for v in pagetag.values()}
|
|
104
104
|
|
|
105
105
|
labels = ijmeta.get("Labels")
|
|
106
|
-
scale =
|
|
106
|
+
scale: dict[str, float] = {}
|
|
107
107
|
dz = ijmeta.get("spacing", 1.0)
|
|
108
108
|
scale_unit: dict[str, float] = {}
|
|
109
109
|
try:
|
|
@@ -133,9 +133,9 @@ def _parse_tifffile(tif: TiffFile) -> ImageMetadata:
|
|
|
133
133
|
_unit = ijmeta.pop("unit", None)
|
|
134
134
|
for k in scale.keys():
|
|
135
135
|
scale_unit[k] = _unit
|
|
136
|
-
if tif.
|
|
136
|
+
if ome_meta := tif.ome_metadata:
|
|
137
137
|
try:
|
|
138
|
-
xml = xml2dict(
|
|
138
|
+
xml = xml2dict(ome_meta)
|
|
139
139
|
meta_data: dict[str, Any] = xml["OME"]["Image"]
|
|
140
140
|
if isinstance(meta_data, list):
|
|
141
141
|
meta_data = meta_data[0]
|
|
@@ -156,6 +156,14 @@ def _parse_tifffile(tif: TiffFile) -> ImageMetadata:
|
|
|
156
156
|
|
|
157
157
|
except Exception:
|
|
158
158
|
pass
|
|
159
|
+
if lsm_meta := tif.lsm_metadata:
|
|
160
|
+
scale_unit = "μm"
|
|
161
|
+
if voxel_size_x := lsm_meta.get("VoxelSizeX"):
|
|
162
|
+
scale["x"] = voxel_size_x * 1e6
|
|
163
|
+
if voxel_size_y := lsm_meta.get("VoxelSizeY"):
|
|
164
|
+
scale["y"] = voxel_size_y * 1e6
|
|
165
|
+
if voxel_size_z := lsm_meta.get("VoxelSizeZ"):
|
|
166
|
+
scale["z"] = voxel_size_z * 1e6
|
|
159
167
|
|
|
160
168
|
return ImageMetadata(
|
|
161
169
|
axes=axes,
|
|
@@ -188,7 +196,7 @@ def _get_ijmeta_from_img(img: ImpyArray, update_lut=True):
|
|
|
188
196
|
info = {}
|
|
189
197
|
metadata["Info"] = str(info)
|
|
190
198
|
scale_unit = img.scale_unit
|
|
191
|
-
if scale_unit[0] in ("μ", "\xb5", "\xc2"):
|
|
199
|
+
if scale_unit and scale_unit[0] in ("μ", "\xb5", "\xc2"):
|
|
192
200
|
scale_unit = "\\u00B5" + scale_unit[1:]
|
|
193
201
|
metadata["unit"] = scale_unit
|
|
194
202
|
|
|
@@ -108,8 +108,7 @@ def array(
|
|
|
108
108
|
axes: str = None,
|
|
109
109
|
like: MetaArray | None = None,
|
|
110
110
|
) -> LazyImgArray:
|
|
111
|
-
"""
|
|
112
|
-
make an LazyImgArray object, like ``np.array(x)``
|
|
111
|
+
"""Make an LazyImgArray object, like ``np.array(x)``
|
|
113
112
|
|
|
114
113
|
Parameters
|
|
115
114
|
----------
|
|
@@ -144,12 +143,7 @@ def array(
|
|
|
144
143
|
arr = da.asarray(arr)
|
|
145
144
|
|
|
146
145
|
if isinstance(arr, np.ndarray) and dtype is None:
|
|
147
|
-
|
|
148
|
-
dtype = arr.dtype
|
|
149
|
-
elif arr.dtype.kind == "f":
|
|
150
|
-
dtype = np.float32
|
|
151
|
-
else:
|
|
152
|
-
dtype = arr.dtype
|
|
146
|
+
dtype = arr.dtype
|
|
153
147
|
|
|
154
148
|
axes, name = _normalize_params(axes, name, like)
|
|
155
149
|
|
|
@@ -172,8 +166,7 @@ def asarray(
|
|
|
172
166
|
like: MetaArray | None = None,
|
|
173
167
|
chunks="auto",
|
|
174
168
|
) -> LazyImgArray:
|
|
175
|
-
"""
|
|
176
|
-
make an LazyImgArray object, like ``np.asarray(x)``
|
|
169
|
+
"""Make an LazyImgArray object, like ``np.asarray(x)``
|
|
177
170
|
|
|
178
171
|
Parameters
|
|
179
172
|
----------
|
|
@@ -127,7 +127,7 @@ class ImageGenerator:
|
|
|
127
127
|
def standard_normal(
|
|
128
128
|
self,
|
|
129
129
|
size: int | tuple[int, ...] | None = None,
|
|
130
|
-
dtype
|
|
130
|
+
dtype=np.float32,
|
|
131
131
|
*,
|
|
132
132
|
axes: AxesLike | None = None,
|
|
133
133
|
name: str | None = None,
|
|
@@ -142,7 +142,7 @@ class ImageGenerator:
|
|
|
142
142
|
def standard_exponential(
|
|
143
143
|
self,
|
|
144
144
|
size: int | tuple[int, ...] | None = None,
|
|
145
|
-
dtype
|
|
145
|
+
dtype=np.float32,
|
|
146
146
|
method: Literal["zig", "inv"] = None,
|
|
147
147
|
*,
|
|
148
148
|
axes: AxesLike | None = None,
|
|
@@ -159,7 +159,7 @@ class ImageGenerator:
|
|
|
159
159
|
def random(
|
|
160
160
|
self,
|
|
161
161
|
size: int | tuple[int, ...] | None = None,
|
|
162
|
-
dtype
|
|
162
|
+
dtype=np.float32,
|
|
163
163
|
*,
|
|
164
164
|
axes: AxesLike | None = None,
|
|
165
165
|
name: str | None = None,
|
|
@@ -187,7 +187,7 @@ class ImageGenerator:
|
|
|
187
187
|
arr = self._rng.normal(loc=loc, scale=scale, size=size)
|
|
188
188
|
if np.isscalar(arr):
|
|
189
189
|
return arr
|
|
190
|
-
return asarray(xp.asnumpy(arr), axes=axes, name=name)
|
|
190
|
+
return asarray(xp.asnumpy(arr), axes=axes, name=name).astype(np.float32)
|
|
191
191
|
|
|
192
192
|
def poisson(
|
|
193
193
|
self,
|
|
@@ -19,7 +19,10 @@ def diagonal_gaussian(r, *params):
|
|
|
19
19
|
ndim = len(params[:-2])//2
|
|
20
20
|
mu = params[:ndim]
|
|
21
21
|
sg = params[ndim:-2]
|
|
22
|
-
z_value = np.array(
|
|
22
|
+
z_value = np.array(
|
|
23
|
+
[(x0 - mu0) / sg0 for x0, mu0, sg0 in zip(r, mu, sg)],
|
|
24
|
+
dtype=np.float32
|
|
25
|
+
)
|
|
23
26
|
return a * np.exp(-np.sum(z_value**2, axis=0) / 2) + b
|
|
24
27
|
|
|
25
28
|
class Gaussian:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|