senoquant 1.0.0b1__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.
- senoquant/__init__.py +6 -0
- senoquant/_reader.py +7 -0
- senoquant/_widget.py +33 -0
- senoquant/napari.yaml +83 -0
- senoquant/reader/__init__.py +5 -0
- senoquant/reader/core.py +369 -0
- senoquant/tabs/__init__.py +15 -0
- senoquant/tabs/batch/__init__.py +10 -0
- senoquant/tabs/batch/backend.py +641 -0
- senoquant/tabs/batch/config.py +270 -0
- senoquant/tabs/batch/frontend.py +1283 -0
- senoquant/tabs/batch/io.py +326 -0
- senoquant/tabs/batch/layers.py +86 -0
- senoquant/tabs/quantification/__init__.py +1 -0
- senoquant/tabs/quantification/backend.py +228 -0
- senoquant/tabs/quantification/features/__init__.py +80 -0
- senoquant/tabs/quantification/features/base.py +142 -0
- senoquant/tabs/quantification/features/marker/__init__.py +5 -0
- senoquant/tabs/quantification/features/marker/config.py +69 -0
- senoquant/tabs/quantification/features/marker/dialog.py +437 -0
- senoquant/tabs/quantification/features/marker/export.py +879 -0
- senoquant/tabs/quantification/features/marker/feature.py +119 -0
- senoquant/tabs/quantification/features/marker/morphology.py +285 -0
- senoquant/tabs/quantification/features/marker/rows.py +654 -0
- senoquant/tabs/quantification/features/marker/thresholding.py +46 -0
- senoquant/tabs/quantification/features/roi.py +346 -0
- senoquant/tabs/quantification/features/spots/__init__.py +5 -0
- senoquant/tabs/quantification/features/spots/config.py +62 -0
- senoquant/tabs/quantification/features/spots/dialog.py +477 -0
- senoquant/tabs/quantification/features/spots/export.py +1292 -0
- senoquant/tabs/quantification/features/spots/feature.py +112 -0
- senoquant/tabs/quantification/features/spots/morphology.py +279 -0
- senoquant/tabs/quantification/features/spots/rows.py +241 -0
- senoquant/tabs/quantification/frontend.py +815 -0
- senoquant/tabs/segmentation/__init__.py +1 -0
- senoquant/tabs/segmentation/backend.py +131 -0
- senoquant/tabs/segmentation/frontend.py +1009 -0
- senoquant/tabs/segmentation/models/__init__.py +5 -0
- senoquant/tabs/segmentation/models/base.py +146 -0
- senoquant/tabs/segmentation/models/cpsam/details.json +65 -0
- senoquant/tabs/segmentation/models/cpsam/model.py +150 -0
- senoquant/tabs/segmentation/models/default_2d/details.json +69 -0
- senoquant/tabs/segmentation/models/default_2d/model.py +664 -0
- senoquant/tabs/segmentation/models/default_3d/details.json +69 -0
- senoquant/tabs/segmentation/models/default_3d/model.py +682 -0
- senoquant/tabs/segmentation/models/hf.py +71 -0
- senoquant/tabs/segmentation/models/nuclear_dilation/__init__.py +1 -0
- senoquant/tabs/segmentation/models/nuclear_dilation/details.json +26 -0
- senoquant/tabs/segmentation/models/nuclear_dilation/model.py +96 -0
- senoquant/tabs/segmentation/models/perinuclear_rings/__init__.py +1 -0
- senoquant/tabs/segmentation/models/perinuclear_rings/details.json +34 -0
- senoquant/tabs/segmentation/models/perinuclear_rings/model.py +132 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/__init__.py +2 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/__init__.py +3 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/__init__.py +6 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/generate.py +470 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/prepare.py +273 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/rawdata.py +112 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/transform.py +384 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/__init__.py +0 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/blocks.py +184 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/losses.py +79 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/nets.py +165 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/predict.py +467 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/probability.py +67 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/train.py +148 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/io/__init__.py +163 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/__init__.py +52 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/base_model.py +329 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_isotropic.py +160 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_projection.py +178 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_standard.py +446 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_upsampling.py +54 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/config.py +254 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/pretrained.py +119 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/scripts/__init__.py +0 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/scripts/care_predict.py +180 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/__init__.py +5 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/plot_utils.py +159 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/six.py +18 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/tf.py +644 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/utils.py +272 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/version.py +1 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/docs/source/conf.py +368 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/setup.py +68 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_datagen.py +169 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_models.py +462 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_utils.py +166 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tools/create_zip_contents.py +34 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/__init__.py +30 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/big.py +624 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/bioimageio_utils.py +494 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/data/__init__.py +39 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/__init__.py +10 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/geom2d.py +215 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/geom3d.py +349 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/matching.py +483 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/__init__.py +28 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/base.py +1217 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/model2d.py +594 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/model3d.py +696 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/nms.py +384 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/__init__.py +2 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/plot.py +74 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/render.py +298 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/rays3d.py +373 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/sample_patches.py +65 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/__init__.py +0 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/predict2d.py +90 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/predict3d.py +93 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/utils.py +408 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/version.py +1 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/__init__.py +45 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/__init__.py +17 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/cli.py +55 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/core.py +285 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/__init__.py +15 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/cli.py +36 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/divisibility.py +193 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/probe.py +100 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/receptive_field.py +182 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/rf_cli.py +48 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/valid_sizes.py +278 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/post/__init__.py +8 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/post/core.py +157 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/pre/__init__.py +17 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/pre/core.py +226 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/predict/__init__.py +5 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/predict/core.py +401 -0
- senoquant/tabs/settings/__init__.py +1 -0
- senoquant/tabs/settings/backend.py +29 -0
- senoquant/tabs/settings/frontend.py +19 -0
- senoquant/tabs/spots/__init__.py +1 -0
- senoquant/tabs/spots/backend.py +139 -0
- senoquant/tabs/spots/frontend.py +800 -0
- senoquant/tabs/spots/models/__init__.py +5 -0
- senoquant/tabs/spots/models/base.py +94 -0
- senoquant/tabs/spots/models/rmp/details.json +61 -0
- senoquant/tabs/spots/models/rmp/model.py +499 -0
- senoquant/tabs/spots/models/udwt/details.json +103 -0
- senoquant/tabs/spots/models/udwt/model.py +482 -0
- senoquant/utils.py +25 -0
- senoquant-1.0.0b1.dist-info/METADATA +193 -0
- senoquant-1.0.0b1.dist-info/RECORD +148 -0
- senoquant-1.0.0b1.dist-info/WHEEL +5 -0
- senoquant-1.0.0b1.dist-info/entry_points.txt +2 -0
- senoquant-1.0.0b1.dist-info/licenses/LICENSE +28 -0
- senoquant-1.0.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
from __future__ import print_function, unicode_literals, absolute_import, division
|
|
2
|
+
from six.moves import range, zip, map, reduce, filter
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from ..utils import _raise, consume, normalize_mi_ma, axes_dict, axes_check_and_normalize, move_image_axes
|
|
6
|
+
import warnings
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
from six import add_metaclass
|
|
11
|
+
from abc import ABCMeta, abstractmethod, abstractproperty
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@add_metaclass(ABCMeta)
|
|
16
|
+
class Normalizer():
|
|
17
|
+
"""Abstract base class for normalization methods."""
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def before(self, x, axes):
|
|
21
|
+
"""Normalization of the raw input image (method stub).
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
x : :class:`numpy.ndarray`
|
|
26
|
+
Raw input image.
|
|
27
|
+
axes : str
|
|
28
|
+
Axes of input image x
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
:class:`numpy.ndarray`
|
|
33
|
+
Normalized input image with suitable values for neural network input.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def after(self, mean, scale, axes):
|
|
38
|
+
"""Possible adjustment of predicted restored image (method stub).
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
mean : :class:`numpy.ndarray`
|
|
43
|
+
Predicted restored image or per-pixel ``mean`` of Laplace distributions
|
|
44
|
+
for probabilistic model.
|
|
45
|
+
scale: :class:`numpy.ndarray` or None
|
|
46
|
+
Per-pixel ``scale`` of Laplace distributions for probabilistic model (``None`` otherwise.)
|
|
47
|
+
axes : str
|
|
48
|
+
Axes of ``mean`` and ``scale``
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
:class:`numpy.ndarray`
|
|
53
|
+
Adjusted restored image(s).
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __call__(self, x, axes):
|
|
57
|
+
"""Alias for :func:`before` to make this callable."""
|
|
58
|
+
return self.before(x, axes)
|
|
59
|
+
|
|
60
|
+
@abstractproperty
|
|
61
|
+
def do_after(self):
|
|
62
|
+
"""bool : Flag to indicate whether :func:`after` should be called."""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class NoNormalizer(Normalizer):
|
|
66
|
+
"""No normalization.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
do_after : bool
|
|
71
|
+
Flag to indicate whether to undo normalization.
|
|
72
|
+
|
|
73
|
+
Raises
|
|
74
|
+
------
|
|
75
|
+
ValueError
|
|
76
|
+
If :func:`after` is called, but parameter `do_after` was set to ``False`` in the constructor.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, do_after=False):
|
|
80
|
+
self._do_after = do_after
|
|
81
|
+
|
|
82
|
+
def before(self, x, axes):
|
|
83
|
+
return x
|
|
84
|
+
|
|
85
|
+
def after(self, mean, scale, axes):
|
|
86
|
+
self.do_after or _raise(ValueError())
|
|
87
|
+
return mean, scale
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def do_after(self):
|
|
91
|
+
return self._do_after
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class PercentileNormalizer(Normalizer):
|
|
95
|
+
"""Percentile-based image normalization.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
pmin : float
|
|
100
|
+
Low percentile.
|
|
101
|
+
pmax : float
|
|
102
|
+
High percentile.
|
|
103
|
+
do_after : bool
|
|
104
|
+
Flag to indicate whether to undo normalization (original data type will not be restored).
|
|
105
|
+
dtype : type
|
|
106
|
+
Data type after normalization.
|
|
107
|
+
kwargs : dict
|
|
108
|
+
Keyword arguments for :func:`csbdeep.utils.normalize_mi_ma`.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
def __init__(self, pmin=2, pmax=99.8, do_after=True, dtype=np.float32, **kwargs):
|
|
112
|
+
"""TODO."""
|
|
113
|
+
(np.isscalar(pmin) and np.isscalar(pmax) and 0 <= pmin < pmax <= 100) or _raise(ValueError())
|
|
114
|
+
self.pmin = pmin
|
|
115
|
+
self.pmax = pmax
|
|
116
|
+
self._do_after = do_after
|
|
117
|
+
self.dtype = dtype
|
|
118
|
+
self.kwargs = kwargs
|
|
119
|
+
|
|
120
|
+
def before(self, x, axes):
|
|
121
|
+
"""Percentile-based normalization of raw input image.
|
|
122
|
+
|
|
123
|
+
See :func:`csbdeep.predict.Normalizer.before` for parameter descriptions.
|
|
124
|
+
Note that percentiles are computed individually for each channel (if present in `axes`).
|
|
125
|
+
"""
|
|
126
|
+
self.axes_before = axes_check_and_normalize(axes,x.ndim)
|
|
127
|
+
axis = tuple(d for d,a in enumerate(self.axes_before) if a != 'C')
|
|
128
|
+
self.mi = np.percentile(x,self.pmin,axis=axis,keepdims=True).astype(self.dtype,copy=False)
|
|
129
|
+
self.ma = np.percentile(x,self.pmax,axis=axis,keepdims=True).astype(self.dtype,copy=False)
|
|
130
|
+
return normalize_mi_ma(x, self.mi, self.ma, dtype=self.dtype, **self.kwargs)
|
|
131
|
+
|
|
132
|
+
def after(self, mean, scale, axes):
|
|
133
|
+
"""Undo percentile-based normalization to map restored image to similar range as input image.
|
|
134
|
+
|
|
135
|
+
See :func:`csbdeep.predict.Normalizer.after` for parameter descriptions.
|
|
136
|
+
|
|
137
|
+
Raises
|
|
138
|
+
------
|
|
139
|
+
ValueError
|
|
140
|
+
If parameter `do_after` was set to ``False`` in the constructor.
|
|
141
|
+
|
|
142
|
+
"""
|
|
143
|
+
self.do_after or _raise(ValueError())
|
|
144
|
+
self.axes_after = axes_check_and_normalize(axes,mean.ndim)
|
|
145
|
+
mi = move_image_axes(self.mi, self.axes_before, self.axes_after, True)
|
|
146
|
+
ma = move_image_axes(self.ma, self.axes_before, self.axes_after, True)
|
|
147
|
+
alpha = ma - mi
|
|
148
|
+
beta = mi
|
|
149
|
+
return (
|
|
150
|
+
( alpha*mean+beta ).astype(self.dtype,copy=False),
|
|
151
|
+
( alpha*scale ).astype(self.dtype,copy=False) if scale is not None else None
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def do_after(self):
|
|
156
|
+
"""``do_after`` parameter from constructor."""
|
|
157
|
+
return self._do_after
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@add_metaclass(ABCMeta)
|
|
162
|
+
class Resizer():
|
|
163
|
+
"""Abstract base class for resizing methods."""
|
|
164
|
+
|
|
165
|
+
@abstractmethod
|
|
166
|
+
def before(self, x, axes, axes_div_by):
|
|
167
|
+
"""Resizing of the raw input image (method stub).
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
x : :class:`numpy.ndarray`
|
|
172
|
+
Raw input image.
|
|
173
|
+
axes : str
|
|
174
|
+
Axes of input image x
|
|
175
|
+
axes_div_by : iterable of int
|
|
176
|
+
Resized image must be evenly divisible by the provided values for each axis.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
:class:`numpy.ndarray`
|
|
181
|
+
Resized input image.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
@abstractmethod
|
|
185
|
+
def after(self, x, axes):
|
|
186
|
+
"""Resizing of the restored image (method stub).
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
x : :class:`numpy.ndarray`
|
|
191
|
+
Restored image.
|
|
192
|
+
axes : str
|
|
193
|
+
Axes of restored image x
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
:class:`numpy.ndarray`
|
|
198
|
+
Resized restored image.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class NoResizer(Resizer):
|
|
203
|
+
"""No resizing.
|
|
204
|
+
|
|
205
|
+
Raises
|
|
206
|
+
------
|
|
207
|
+
ValueError
|
|
208
|
+
In :func:`before`, if image resizing is necessary.
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
def before(self, x, axes, axes_div_by):
|
|
212
|
+
axes = axes_check_and_normalize(axes,x.ndim)
|
|
213
|
+
consume (
|
|
214
|
+
(s%div_n==0) or _raise(ValueError('%d (axis %s) is not divisible by %d.' % (s,a,div_n)))
|
|
215
|
+
for a, div_n, s in zip(axes, axes_div_by, x.shape)
|
|
216
|
+
)
|
|
217
|
+
return x
|
|
218
|
+
|
|
219
|
+
def after(self, x, axes):
|
|
220
|
+
return x
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class PadAndCropResizer(Resizer):
|
|
224
|
+
"""Resize image by padding and cropping.
|
|
225
|
+
|
|
226
|
+
If necessary, input image is padded before prediction
|
|
227
|
+
and restored image is cropped back to size of input image
|
|
228
|
+
after prediction.
|
|
229
|
+
|
|
230
|
+
Parameters
|
|
231
|
+
----------
|
|
232
|
+
mode : str
|
|
233
|
+
Parameter ``mode`` of :func:`numpy.pad` that
|
|
234
|
+
controls how the image is padded.
|
|
235
|
+
kwargs : dict
|
|
236
|
+
Keyword arguments for :func:`numpy.pad`.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
def __init__(self, mode='reflect', **kwargs):
|
|
240
|
+
"""TODO."""
|
|
241
|
+
self.mode = mode
|
|
242
|
+
self.kwargs = kwargs
|
|
243
|
+
|
|
244
|
+
def before(self, x, axes, axes_div_by):
|
|
245
|
+
"""Pad input image.
|
|
246
|
+
|
|
247
|
+
See :func:`csbdeep.predict.Resizer.before` for parameter descriptions.
|
|
248
|
+
"""
|
|
249
|
+
axes = axes_check_and_normalize(axes,x.ndim)
|
|
250
|
+
def _split(v):
|
|
251
|
+
a = v // 2
|
|
252
|
+
return a, v-a
|
|
253
|
+
self.pad = {
|
|
254
|
+
a : _split((div_n-s%div_n)%div_n)
|
|
255
|
+
for a, div_n, s in zip(axes, axes_div_by, x.shape)
|
|
256
|
+
}
|
|
257
|
+
# print(self.pad)
|
|
258
|
+
x_pad = np.pad(x, tuple(self.pad[a] for a in axes), mode=self.mode, **self.kwargs)
|
|
259
|
+
return x_pad
|
|
260
|
+
|
|
261
|
+
def after(self, x, axes):
|
|
262
|
+
"""Crop restored image to retain size of input image.
|
|
263
|
+
|
|
264
|
+
See :func:`csbdeep.predict.Resizer.after` for parameter descriptions.
|
|
265
|
+
"""
|
|
266
|
+
axes = axes_check_and_normalize(axes,x.ndim)
|
|
267
|
+
all(a in self.pad for a in axes) or _raise(ValueError())
|
|
268
|
+
crop = tuple (
|
|
269
|
+
slice(p[0], -p[1] if p[1]>0 else None)
|
|
270
|
+
for p in (self.pad[a] for a in axes)
|
|
271
|
+
)
|
|
272
|
+
# print(crop)
|
|
273
|
+
return x[crop]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import print_function, unicode_literals, absolute_import, division
|
|
3
|
+
from six.moves import zip
|
|
4
|
+
from tifffile import imread
|
|
5
|
+
from collections import namedtuple
|
|
6
|
+
from itertools import chain
|
|
7
|
+
|
|
8
|
+
from ..utils import _raise, consume, axes_check_and_normalize
|
|
9
|
+
from ..utils.six import Path, FileNotFoundError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RawData(namedtuple('RawData' ,('generator' ,'size' ,'description'))):
|
|
14
|
+
""":func:`collections.namedtuple` with three fields: `generator`, `size`, and `description`.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
generator : function
|
|
19
|
+
Function without arguments that returns a generator that yields tuples `(x,y,axes,mask)`,
|
|
20
|
+
where `x` is a source image (e.g., with low SNR) with `y` being the corresponding target image
|
|
21
|
+
(e.g., with high SNR); `mask` can either be `None` or a boolean array that denotes which
|
|
22
|
+
pixels are eligible to extracted in :func:`create_patches`. Note that `x`, `y`, and `mask`
|
|
23
|
+
must all be of type :class:`numpy.ndarray` and are assumed to have the same shape, where the
|
|
24
|
+
string `axes` indicates the order and presence of axes of all three arrays.
|
|
25
|
+
size : int
|
|
26
|
+
Number of tuples that the `generator` will yield.
|
|
27
|
+
description : str
|
|
28
|
+
Textual description of the raw data.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def from_folder(basepath, source_dirs, target_dir, axes='CZYX', pattern='*.tif*'):
|
|
33
|
+
"""Get pairs of corresponding TIFF images read from folders.
|
|
34
|
+
|
|
35
|
+
Two images correspond to each other if they have the same file name, but are located in different folders.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
basepath : str
|
|
40
|
+
Base folder that contains sub-folders with images.
|
|
41
|
+
source_dirs : list or tuple
|
|
42
|
+
List of folder names relative to `basepath` that contain the source images (e.g., with low SNR).
|
|
43
|
+
target_dir : str
|
|
44
|
+
Folder name relative to `basepath` that contains the target images (e.g., with high SNR).
|
|
45
|
+
axes : str
|
|
46
|
+
Semantics of axes of loaded images (assumed to be the same for all images).
|
|
47
|
+
pattern : str
|
|
48
|
+
Glob-style pattern to match the desired TIFF images.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
RawData
|
|
53
|
+
:obj:`RawData` object, whose `generator` is used to yield all matching TIFF pairs.
|
|
54
|
+
The generator will return a tuple `(x,y,axes,mask)`, where `x` is from
|
|
55
|
+
`source_dirs` and `y` is the corresponding image from the `target_dir`;
|
|
56
|
+
`mask` is set to `None`.
|
|
57
|
+
|
|
58
|
+
Raises
|
|
59
|
+
------
|
|
60
|
+
FileNotFoundError
|
|
61
|
+
If an image found in a `source_dir` does not exist in `target_dir`.
|
|
62
|
+
|
|
63
|
+
Example
|
|
64
|
+
--------
|
|
65
|
+
>>> !tree data
|
|
66
|
+
data
|
|
67
|
+
├── GT
|
|
68
|
+
│ ├── imageA.tif
|
|
69
|
+
│ ├── imageB.tif
|
|
70
|
+
│ └── imageC.tif
|
|
71
|
+
├── source1
|
|
72
|
+
│ ├── imageA.tif
|
|
73
|
+
│ └── imageB.tif
|
|
74
|
+
└── source2
|
|
75
|
+
├── imageA.tif
|
|
76
|
+
└── imageC.tif
|
|
77
|
+
|
|
78
|
+
>>> data = RawData.from_folder(basepath='data', source_dirs=['source1','source2'], target_dir='GT', axes='YX')
|
|
79
|
+
>>> n_images = data.size
|
|
80
|
+
>>> for source_x, target_y, axes, mask in data.generator():
|
|
81
|
+
... pass
|
|
82
|
+
|
|
83
|
+
"""
|
|
84
|
+
p = Path(basepath)
|
|
85
|
+
pairs = [(f, p/target_dir/f.name) for f in chain(*((p/source_dir).glob(pattern) for source_dir in source_dirs))]
|
|
86
|
+
len(pairs) > 0 or _raise(FileNotFoundError("Didn't find any images."))
|
|
87
|
+
consume(t.exists() or _raise(FileNotFoundError(t)) for s,t in pairs)
|
|
88
|
+
axes = axes_check_and_normalize(axes)
|
|
89
|
+
n_images = len(pairs)
|
|
90
|
+
description = "{p}: target='{o}', sources={s}, axes='{a}', pattern='{pt}'".format(p=basepath, s=list(source_dirs),
|
|
91
|
+
o=target_dir, a=axes, pt=pattern)
|
|
92
|
+
|
|
93
|
+
def _gen():
|
|
94
|
+
for fx, fy in pairs:
|
|
95
|
+
x, y = imread(str(fx)), imread(str(fy))
|
|
96
|
+
len(axes) >= x.ndim or _raise(ValueError())
|
|
97
|
+
yield x, y, axes[-x.ndim:], None
|
|
98
|
+
|
|
99
|
+
return RawData(_gen, n_images, description)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def from_arrays(X, Y, axes='CZYX'):
|
|
105
|
+
"""Get pairs of corresponding images from numpy arrays."""
|
|
106
|
+
|
|
107
|
+
def _gen():
|
|
108
|
+
for x, y in zip(X ,Y):
|
|
109
|
+
len(axes) >= x.ndim or _raise(ValueError())
|
|
110
|
+
yield x, y, axes[-x.ndim:], None
|
|
111
|
+
|
|
112
|
+
return RawData(_gen, len(X), "numpy array")
|