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.
Files changed (148) hide show
  1. senoquant/__init__.py +6 -0
  2. senoquant/_reader.py +7 -0
  3. senoquant/_widget.py +33 -0
  4. senoquant/napari.yaml +83 -0
  5. senoquant/reader/__init__.py +5 -0
  6. senoquant/reader/core.py +369 -0
  7. senoquant/tabs/__init__.py +15 -0
  8. senoquant/tabs/batch/__init__.py +10 -0
  9. senoquant/tabs/batch/backend.py +641 -0
  10. senoquant/tabs/batch/config.py +270 -0
  11. senoquant/tabs/batch/frontend.py +1283 -0
  12. senoquant/tabs/batch/io.py +326 -0
  13. senoquant/tabs/batch/layers.py +86 -0
  14. senoquant/tabs/quantification/__init__.py +1 -0
  15. senoquant/tabs/quantification/backend.py +228 -0
  16. senoquant/tabs/quantification/features/__init__.py +80 -0
  17. senoquant/tabs/quantification/features/base.py +142 -0
  18. senoquant/tabs/quantification/features/marker/__init__.py +5 -0
  19. senoquant/tabs/quantification/features/marker/config.py +69 -0
  20. senoquant/tabs/quantification/features/marker/dialog.py +437 -0
  21. senoquant/tabs/quantification/features/marker/export.py +879 -0
  22. senoquant/tabs/quantification/features/marker/feature.py +119 -0
  23. senoquant/tabs/quantification/features/marker/morphology.py +285 -0
  24. senoquant/tabs/quantification/features/marker/rows.py +654 -0
  25. senoquant/tabs/quantification/features/marker/thresholding.py +46 -0
  26. senoquant/tabs/quantification/features/roi.py +346 -0
  27. senoquant/tabs/quantification/features/spots/__init__.py +5 -0
  28. senoquant/tabs/quantification/features/spots/config.py +62 -0
  29. senoquant/tabs/quantification/features/spots/dialog.py +477 -0
  30. senoquant/tabs/quantification/features/spots/export.py +1292 -0
  31. senoquant/tabs/quantification/features/spots/feature.py +112 -0
  32. senoquant/tabs/quantification/features/spots/morphology.py +279 -0
  33. senoquant/tabs/quantification/features/spots/rows.py +241 -0
  34. senoquant/tabs/quantification/frontend.py +815 -0
  35. senoquant/tabs/segmentation/__init__.py +1 -0
  36. senoquant/tabs/segmentation/backend.py +131 -0
  37. senoquant/tabs/segmentation/frontend.py +1009 -0
  38. senoquant/tabs/segmentation/models/__init__.py +5 -0
  39. senoquant/tabs/segmentation/models/base.py +146 -0
  40. senoquant/tabs/segmentation/models/cpsam/details.json +65 -0
  41. senoquant/tabs/segmentation/models/cpsam/model.py +150 -0
  42. senoquant/tabs/segmentation/models/default_2d/details.json +69 -0
  43. senoquant/tabs/segmentation/models/default_2d/model.py +664 -0
  44. senoquant/tabs/segmentation/models/default_3d/details.json +69 -0
  45. senoquant/tabs/segmentation/models/default_3d/model.py +682 -0
  46. senoquant/tabs/segmentation/models/hf.py +71 -0
  47. senoquant/tabs/segmentation/models/nuclear_dilation/__init__.py +1 -0
  48. senoquant/tabs/segmentation/models/nuclear_dilation/details.json +26 -0
  49. senoquant/tabs/segmentation/models/nuclear_dilation/model.py +96 -0
  50. senoquant/tabs/segmentation/models/perinuclear_rings/__init__.py +1 -0
  51. senoquant/tabs/segmentation/models/perinuclear_rings/details.json +34 -0
  52. senoquant/tabs/segmentation/models/perinuclear_rings/model.py +132 -0
  53. senoquant/tabs/segmentation/stardist_onnx_utils/__init__.py +2 -0
  54. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/__init__.py +3 -0
  55. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/__init__.py +6 -0
  56. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/generate.py +470 -0
  57. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/prepare.py +273 -0
  58. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/rawdata.py +112 -0
  59. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/transform.py +384 -0
  60. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/__init__.py +0 -0
  61. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/blocks.py +184 -0
  62. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/losses.py +79 -0
  63. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/nets.py +165 -0
  64. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/predict.py +467 -0
  65. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/probability.py +67 -0
  66. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/train.py +148 -0
  67. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/io/__init__.py +163 -0
  68. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/__init__.py +52 -0
  69. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/base_model.py +329 -0
  70. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_isotropic.py +160 -0
  71. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_projection.py +178 -0
  72. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_standard.py +446 -0
  73. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_upsampling.py +54 -0
  74. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/config.py +254 -0
  75. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/pretrained.py +119 -0
  76. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/scripts/__init__.py +0 -0
  77. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/scripts/care_predict.py +180 -0
  78. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/__init__.py +5 -0
  79. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/plot_utils.py +159 -0
  80. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/six.py +18 -0
  81. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/tf.py +644 -0
  82. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/utils.py +272 -0
  83. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/version.py +1 -0
  84. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/docs/source/conf.py +368 -0
  85. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/setup.py +68 -0
  86. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_datagen.py +169 -0
  87. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_models.py +462 -0
  88. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_utils.py +166 -0
  89. senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tools/create_zip_contents.py +34 -0
  90. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/__init__.py +30 -0
  91. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/big.py +624 -0
  92. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/bioimageio_utils.py +494 -0
  93. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/data/__init__.py +39 -0
  94. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/__init__.py +10 -0
  95. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/geom2d.py +215 -0
  96. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/geom3d.py +349 -0
  97. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/matching.py +483 -0
  98. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/__init__.py +28 -0
  99. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/base.py +1217 -0
  100. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/model2d.py +594 -0
  101. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/model3d.py +696 -0
  102. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/nms.py +384 -0
  103. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/__init__.py +2 -0
  104. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/plot.py +74 -0
  105. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/render.py +298 -0
  106. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/rays3d.py +373 -0
  107. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/sample_patches.py +65 -0
  108. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/__init__.py +0 -0
  109. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/predict2d.py +90 -0
  110. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/predict3d.py +93 -0
  111. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/utils.py +408 -0
  112. senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/version.py +1 -0
  113. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/__init__.py +45 -0
  114. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/__init__.py +17 -0
  115. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/cli.py +55 -0
  116. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/core.py +285 -0
  117. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/__init__.py +15 -0
  118. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/cli.py +36 -0
  119. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/divisibility.py +193 -0
  120. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/probe.py +100 -0
  121. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/receptive_field.py +182 -0
  122. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/rf_cli.py +48 -0
  123. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/valid_sizes.py +278 -0
  124. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/post/__init__.py +8 -0
  125. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/post/core.py +157 -0
  126. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/pre/__init__.py +17 -0
  127. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/pre/core.py +226 -0
  128. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/predict/__init__.py +5 -0
  129. senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/predict/core.py +401 -0
  130. senoquant/tabs/settings/__init__.py +1 -0
  131. senoquant/tabs/settings/backend.py +29 -0
  132. senoquant/tabs/settings/frontend.py +19 -0
  133. senoquant/tabs/spots/__init__.py +1 -0
  134. senoquant/tabs/spots/backend.py +139 -0
  135. senoquant/tabs/spots/frontend.py +800 -0
  136. senoquant/tabs/spots/models/__init__.py +5 -0
  137. senoquant/tabs/spots/models/base.py +94 -0
  138. senoquant/tabs/spots/models/rmp/details.json +61 -0
  139. senoquant/tabs/spots/models/rmp/model.py +499 -0
  140. senoquant/tabs/spots/models/udwt/details.json +103 -0
  141. senoquant/tabs/spots/models/udwt/model.py +482 -0
  142. senoquant/utils.py +25 -0
  143. senoquant-1.0.0b1.dist-info/METADATA +193 -0
  144. senoquant-1.0.0b1.dist-info/RECORD +148 -0
  145. senoquant-1.0.0b1.dist-info/WHEEL +5 -0
  146. senoquant-1.0.0b1.dist-info/entry_points.txt +2 -0
  147. senoquant-1.0.0b1.dist-info/licenses/LICENSE +28 -0
  148. senoquant-1.0.0b1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,384 @@
1
+ from __future__ import print_function, unicode_literals, absolute_import, division
2
+ import numpy as np
3
+ from time import time
4
+ from .utils import _normalize_grid
5
+
6
+ def _ind_prob_thresh(prob, prob_thresh, b=2):
7
+ if b is not None and np.isscalar(b):
8
+ b = ((b,b),)*prob.ndim
9
+
10
+ ind_thresh = prob > prob_thresh
11
+ if b is not None:
12
+ _ind_thresh = np.zeros_like(ind_thresh)
13
+ ss = tuple(slice(_bs[0] if _bs[0]>0 else None,
14
+ -_bs[1] if _bs[1]>0 else None) for _bs in b)
15
+ _ind_thresh[ss] = True
16
+ ind_thresh &= _ind_thresh
17
+ return ind_thresh
18
+
19
+
20
+ def _non_maximum_suppression_old(coord, prob, grid=(1,1), b=2, nms_thresh=0.5, prob_thresh=0.5, verbose=False, max_bbox_search=True):
21
+ """2D coordinates of the polys that survive from a given prediction (prob, coord)
22
+
23
+ prob.shape = (Ny,Nx)
24
+ coord.shape = (Ny,Nx,2,n_rays)
25
+
26
+ b: don't use pixel closer than b pixels to the image boundary
27
+
28
+ returns retained points
29
+ """
30
+ from .lib.stardist2d import c_non_max_suppression_inds_old
31
+
32
+ # TODO: using b>0 with grid>1 can suppress small/cropped objects at the image boundary
33
+
34
+ assert prob.ndim == 2
35
+ assert coord.ndim == 4
36
+ grid = _normalize_grid(grid,2)
37
+
38
+ # mask = prob > prob_thresh
39
+ # if b is not None and b > 0:
40
+ # _mask = np.zeros_like(mask)
41
+ # _mask[b:-b,b:-b] = True
42
+ # mask &= _mask
43
+
44
+ mask = _ind_prob_thresh(prob, prob_thresh, b)
45
+
46
+ polygons = coord[mask]
47
+ scores = prob[mask]
48
+
49
+ # sort scores descendingly
50
+ ind = np.argsort(scores)[::-1]
51
+ survivors = np.zeros(len(ind), bool)
52
+ polygons = polygons[ind]
53
+ scores = scores[ind]
54
+
55
+ if max_bbox_search:
56
+ # map pixel indices to ids of sorted polygons (-1 => polygon at that pixel not a candidate)
57
+ mapping = -np.ones(mask.shape,np.int32)
58
+ mapping.flat[ np.flatnonzero(mask)[ind] ] = range(len(ind))
59
+ else:
60
+ mapping = np.empty((0,0),np.int32)
61
+
62
+ if verbose:
63
+ t = time()
64
+
65
+ survivors[ind] = c_non_max_suppression_inds_old(np.ascontiguousarray(polygons.astype(np.int32)),
66
+ mapping, np.float32(nms_thresh), np.int32(max_bbox_search),
67
+ np.int32(grid[0]), np.int32(grid[1]),np.int32(verbose))
68
+
69
+ if verbose:
70
+ print("keeping %s/%s polygons" % (np.count_nonzero(survivors), len(polygons)))
71
+ print("NMS took %.4f s" % (time() - t))
72
+
73
+ points = np.stack([ii[survivors] for ii in np.nonzero(mask)],axis=-1)
74
+ return points
75
+
76
+
77
+ def non_maximum_suppression(dist, prob, grid=(1,1), b=2, nms_thresh=0.5, prob_thresh=0.5,
78
+ use_bbox=True, use_kdtree=True, verbose=False):
79
+ """Non-Maximum-Supression of 2D polygons
80
+
81
+ Retains only polygons whose overlap is smaller than nms_thresh
82
+
83
+ dist.shape = (Ny,Nx, n_rays)
84
+ prob.shape = (Ny,Nx)
85
+
86
+ returns the retained points, probabilities, and distances:
87
+
88
+ points, prob, dist = non_maximum_suppression(dist, prob, ....
89
+
90
+ """
91
+
92
+ # TODO: using b>0 with grid>1 can suppress small/cropped objects at the image boundary
93
+
94
+ assert prob.ndim == 2 and dist.ndim == 3 and prob.shape == dist.shape[:2]
95
+ dist = np.asarray(dist)
96
+ prob = np.asarray(prob)
97
+ n_rays = dist.shape[-1]
98
+
99
+ grid = _normalize_grid(grid,2)
100
+
101
+ # mask = prob > prob_thresh
102
+ # if b is not None and b > 0:
103
+ # _mask = np.zeros_like(mask)
104
+ # _mask[b:-b,b:-b] = True
105
+ # mask &= _mask
106
+
107
+ mask = _ind_prob_thresh(prob, prob_thresh, b)
108
+ points = np.stack(np.where(mask), axis=1)
109
+
110
+ dist = dist[mask]
111
+ scores = prob[mask]
112
+
113
+ # sort scores descendingly
114
+ ind = np.argsort(scores)[::-1]
115
+ dist = dist[ind]
116
+ scores = scores[ind]
117
+ points = points[ind]
118
+
119
+ points = (points * np.array(grid).reshape((1,2)))
120
+
121
+ if verbose:
122
+ t = time()
123
+
124
+ inds = non_maximum_suppression_inds(dist, points.astype(np.int32, copy=False), scores=scores,
125
+ use_bbox=use_bbox, use_kdtree=use_kdtree,
126
+ thresh=nms_thresh, verbose=verbose)
127
+
128
+ if verbose:
129
+ print("keeping %s/%s polygons" % (np.count_nonzero(inds), len(inds)))
130
+ print("NMS took %.4f s" % (time() - t))
131
+
132
+ return points[inds], scores[inds], dist[inds]
133
+
134
+
135
+ def non_maximum_suppression_sparse(dist, prob, points, b=2, nms_thresh=0.5,
136
+ use_bbox=True, use_kdtree = True, verbose=False):
137
+ """Non-Maximum-Supression of 2D polygons from a list of dists, probs (scores), and points
138
+
139
+ Retains only polyhedra whose overlap is smaller than nms_thresh
140
+
141
+ dist.shape = (n_polys, n_rays)
142
+ prob.shape = (n_polys,)
143
+ points.shape = (n_polys,2)
144
+
145
+ returns the retained instances
146
+
147
+ (pointsi, probi, disti, indsi)
148
+
149
+ with
150
+ pointsi = points[indsi] ...
151
+
152
+ """
153
+
154
+ # TODO: using b>0 with grid>1 can suppress small/cropped objects at the image boundary
155
+
156
+ dist = np.asarray(dist)
157
+ prob = np.asarray(prob)
158
+ points = np.asarray(points)
159
+ n_rays = dist.shape[-1]
160
+
161
+ assert dist.ndim == 2 and prob.ndim == 1 and points.ndim == 2 and \
162
+ points.shape[-1]==2 and len(prob) == len(dist) == len(points)
163
+
164
+ verbose and print("predicting instances with nms_thresh = {nms_thresh}".format(nms_thresh=nms_thresh), flush=True)
165
+
166
+ inds_original = np.arange(len(prob))
167
+ _sorted = np.argsort(prob)[::-1]
168
+ probi = prob[_sorted]
169
+ disti = dist[_sorted]
170
+ pointsi = points[_sorted]
171
+ inds_original = inds_original[_sorted]
172
+
173
+ if verbose:
174
+ print("non-maximum suppression...")
175
+ t = time()
176
+
177
+ inds = non_maximum_suppression_inds(disti, pointsi, scores=probi, thresh=nms_thresh, use_kdtree = use_kdtree, verbose=verbose)
178
+
179
+ if verbose:
180
+ print("keeping %s/%s polyhedra" % (np.count_nonzero(inds), len(inds)))
181
+ print("NMS took %.4f s" % (time() - t))
182
+
183
+ return pointsi[inds], probi[inds], disti[inds], inds_original[inds]
184
+
185
+
186
+ def non_maximum_suppression_inds(dist, points, scores, thresh=0.5, use_bbox=True, use_kdtree = True, verbose=1):
187
+ """
188
+ Applies non maximum supression to ray-convex polygons given by dists and points
189
+ sorted by scores and IoU threshold
190
+
191
+ P1 will suppress P2, if IoU(P1,P2) > thresh
192
+
193
+ with IoU(P1,P2) = Ainter(P1,P2) / min(A(P1),A(P2))
194
+
195
+ i.e. the smaller thresh, the more polygons will be supressed
196
+
197
+ dist.shape = (n_poly, n_rays)
198
+ point.shape = (n_poly, 2)
199
+ score.shape = (n_poly,)
200
+
201
+ returns indices of selected polygons
202
+ """
203
+
204
+ from .lib.stardist2d import c_non_max_suppression_inds
205
+
206
+ assert dist.ndim == 2
207
+ assert points.ndim == 2
208
+
209
+ n_poly = dist.shape[0]
210
+
211
+ if scores is None:
212
+ scores = np.ones(n_poly)
213
+
214
+ assert len(scores) == n_poly
215
+ assert points.shape[0] == n_poly
216
+
217
+ def _prep(x, dtype):
218
+ return np.ascontiguousarray(x.astype(dtype, copy=False))
219
+
220
+ inds = c_non_max_suppression_inds(_prep(dist, np.float32),
221
+ _prep(points, np.float32),
222
+ int(use_kdtree),
223
+ int(use_bbox),
224
+ int(verbose),
225
+ np.float32(thresh))
226
+
227
+ return inds
228
+
229
+
230
+ #########
231
+
232
+
233
+ def non_maximum_suppression_3d(dist, prob, rays, grid=(1,1,1), b=2, nms_thresh=0.5, prob_thresh=0.5, use_bbox=True, use_kdtree=True, verbose=False):
234
+ """Non-Maximum-Supression of 3D polyhedra
235
+
236
+ Retains only polyhedra whose overlap is smaller than nms_thresh
237
+
238
+ dist.shape = (Nz,Ny,Nx, n_rays)
239
+ prob.shape = (Nz,Ny,Nx)
240
+
241
+ returns the retained points, probabilities, and distances:
242
+
243
+ points, prob, dist = non_maximum_suppression_3d(dist, prob, ....
244
+ """
245
+
246
+ # TODO: using b>0 with grid>1 can suppress small/cropped objects at the image boundary
247
+
248
+ dist = np.asarray(dist)
249
+ prob = np.asarray(prob)
250
+
251
+ assert prob.ndim == 3 and dist.ndim == 4 and dist.shape[-1] == len(rays) and prob.shape == dist.shape[:3]
252
+
253
+ grid = _normalize_grid(grid,3)
254
+
255
+ verbose and print("predicting instances with prob_thresh = {prob_thresh} and nms_thresh = {nms_thresh}".format(prob_thresh=prob_thresh, nms_thresh=nms_thresh), flush=True)
256
+
257
+ # ind_thresh = prob > prob_thresh
258
+ # if b is not None and b > 0:
259
+ # _ind_thresh = np.zeros_like(ind_thresh)
260
+ # _ind_thresh[b:-b,b:-b,b:-b] = True
261
+ # ind_thresh &= _ind_thresh
262
+
263
+ ind_thresh = _ind_prob_thresh(prob, prob_thresh, b)
264
+ points = np.stack(np.where(ind_thresh), axis=1)
265
+ verbose and print("found %s candidates"%len(points))
266
+ probi = prob[ind_thresh]
267
+ disti = dist[ind_thresh]
268
+
269
+ _sorted = np.argsort(probi)[::-1]
270
+ probi = probi[_sorted]
271
+ disti = disti[_sorted]
272
+ points = points[_sorted]
273
+
274
+ verbose and print("non-maximum suppression...")
275
+ points = (points * np.array(grid).reshape((1,3)))
276
+
277
+ inds = non_maximum_suppression_3d_inds(disti, points, rays=rays, scores=probi, thresh=nms_thresh,
278
+ use_bbox=use_bbox, use_kdtree = use_kdtree,
279
+ verbose=verbose)
280
+
281
+ verbose and print("keeping %s/%s polyhedra" % (np.count_nonzero(inds), len(inds)))
282
+ return points[inds], probi[inds], disti[inds]
283
+
284
+
285
+ def non_maximum_suppression_3d_sparse(dist, prob, points, rays, b=2, nms_thresh=0.5, use_kdtree = True, verbose=False):
286
+ """Non-Maximum-Supression of 3D polyhedra from a list of dists, probs and points
287
+
288
+ Retains only polyhedra whose overlap is smaller than nms_thresh
289
+ dist.shape = (n_polys, n_rays)
290
+ prob.shape = (n_polys,)
291
+ points.shape = (n_polys,3)
292
+
293
+ returns the retained instances
294
+
295
+ (pointsi, probi, disti, indsi)
296
+
297
+ with
298
+ pointsi = points[indsi] ...
299
+ """
300
+
301
+ # TODO: using b>0 with grid>1 can suppress small/cropped objects at the image boundary
302
+
303
+ dist = np.asarray(dist)
304
+ prob = np.asarray(prob)
305
+ points = np.asarray(points)
306
+
307
+ assert dist.ndim == 2 and prob.ndim == 1 and points.ndim == 2 and \
308
+ dist.shape[-1] == len(rays) and points.shape[-1]==3 and len(prob) == len(dist) == len(points)
309
+
310
+ verbose and print("predicting instances with nms_thresh = {nms_thresh}".format(nms_thresh=nms_thresh), flush=True)
311
+
312
+ inds_original = np.arange(len(prob))
313
+ _sorted = np.argsort(prob)[::-1]
314
+ probi = prob[_sorted]
315
+ disti = dist[_sorted]
316
+ pointsi = points[_sorted]
317
+ inds_original = inds_original[_sorted]
318
+
319
+ verbose and print("non-maximum suppression...")
320
+
321
+ inds = non_maximum_suppression_3d_inds(disti, pointsi, rays=rays, scores=probi, thresh=nms_thresh, use_kdtree = use_kdtree, verbose=verbose)
322
+
323
+ verbose and print("keeping %s/%s polyhedra" % (np.count_nonzero(inds), len(inds)))
324
+ return pointsi[inds], probi[inds], disti[inds], inds_original[inds]
325
+
326
+
327
+ def non_maximum_suppression_3d_inds(dist, points, rays, scores, thresh=0.5, use_bbox=True, use_kdtree = True, verbose=1):
328
+ """
329
+ Applies non maximum supression to ray-convex polyhedra given by dists and rays
330
+ sorted by scores and IoU threshold
331
+
332
+ P1 will suppress P2, if IoU(P1,P2) > thresh
333
+
334
+ with IoU(P1,P2) = Ainter(P1,P2) / min(A(P1),A(P2))
335
+
336
+ i.e. the smaller thresh, the more polygons will be supressed
337
+
338
+ dist.shape = (n_poly, n_rays)
339
+ point.shape = (n_poly, 3)
340
+ score.shape = (n_poly,)
341
+
342
+ returns indices of selected polygons
343
+ """
344
+ from .lib.stardist3d import c_non_max_suppression_inds
345
+
346
+ assert dist.ndim == 2
347
+ assert points.ndim == 2
348
+ assert dist.shape[1] == len(rays)
349
+
350
+ n_poly = dist.shape[0]
351
+
352
+ if scores is None:
353
+ scores = np.ones(n_poly)
354
+
355
+ assert len(scores) == n_poly
356
+ assert points.shape[0] == n_poly
357
+
358
+ # sort scores descendingly
359
+ ind = np.argsort(scores)[::-1]
360
+ survivors = np.ones(n_poly, bool)
361
+ dist = dist[ind]
362
+ points = points[ind]
363
+ scores = scores[ind]
364
+
365
+ def _prep(x, dtype):
366
+ return np.ascontiguousarray(x.astype(dtype, copy=False))
367
+
368
+ if verbose:
369
+ t = time()
370
+
371
+ survivors[ind] = c_non_max_suppression_inds(_prep(dist, np.float32),
372
+ _prep(points, np.float32),
373
+ _prep(rays.vertices, np.float32),
374
+ _prep(rays.faces, np.int32),
375
+ _prep(scores, np.float32),
376
+ int(use_bbox),
377
+ int(use_kdtree),
378
+ int(verbose),
379
+ np.float32(thresh))
380
+
381
+ if verbose:
382
+ print("NMS took %.4f s" % (time() - t))
383
+
384
+ return survivors
@@ -0,0 +1,2 @@
1
+ from .plot import *
2
+ from .render import *
@@ -0,0 +1,74 @@
1
+ from __future__ import print_function, unicode_literals, absolute_import, division
2
+ import numpy as np
3
+ from warnings import warn
4
+ from csbdeep.utils import normalize
5
+ from ..utils import _normalize_grid
6
+ from ..matching import matching
7
+
8
+ def random_label_cmap(n=2**16, h = (0,1), l = (.4,1), s =(.2,.8), seed=None):
9
+ import matplotlib
10
+ import colorsys
11
+ # cols = np.random.rand(n,3)
12
+ # cols = np.random.uniform(0.1,1.0,(n,3))
13
+ rng = np.random.default_rng(seed)
14
+
15
+ h, l, s = rng.uniform(*h, n), rng.uniform(*l, n), rng.uniform(*s, n)
16
+ cols = np.stack([colorsys.hls_to_rgb(_h,_l,_s) for _h,_l,_s in zip(h,l,s)],axis=0)
17
+ cols[0] = 0
18
+ return matplotlib.colors.ListedColormap(cols)
19
+
20
+
21
+ def _plot_polygon(x,y,score,color):
22
+ import matplotlib.pyplot as plt
23
+ a,b = list(x),list(y)
24
+ a += a[:1]
25
+ b += b[:1]
26
+ plt.plot(a,b,'--', alpha=1, linewidth=score, zorder=1, color=color)
27
+
28
+
29
+ def draw_polygons(coord, score, poly_idx, grid=(1,1), cmap=None, show_dist=False):
30
+ """poly_idx is a N x 2 array with row-col coordinate indices"""
31
+ grid = _normalize_grid(grid,2)
32
+ return _draw_polygons(polygons=coord[poly_idx[:,0],poly_idx[:,1]],
33
+ points=poly_idx*np.array(grid),
34
+ scores=score[poly_idx[:,0],poly_idx[:,1]],
35
+ cmap=cmap, show_dist=show_dist)
36
+
37
+
38
+ def _draw_polygons(polygons, points=None, scores=None, grid=None, cmap=None, show_dist=False):
39
+ """
40
+ polygons is a list/array of x,y coordinate lists/arrays
41
+ points is a list/array of x,y coordinates
42
+ scores is a list/array of scalar values between 0 and 1
43
+ """
44
+ # TODO: better name for this function?
45
+ import matplotlib.pyplot as plt
46
+ from matplotlib.collections import LineCollection
47
+
48
+ if grid is not None:
49
+ warn("parameter 'grid' has no effect anymore, please remove")
50
+ if points is None:
51
+ points = [None]*len(polygons)
52
+ if scores is None:
53
+ scores = np.ones(len(polygons))
54
+ if cmap is None:
55
+ cmap = random_label_cmap(len(polygons)+1)
56
+
57
+ assert len(polygons) == len(scores)
58
+ assert len(cmap.colors[1:]) >= len(polygons)
59
+ assert not show_dist or all(p is not None for p in points)
60
+
61
+ for point,poly,score,c in zip(points,polygons,scores,cmap.colors[1:]):
62
+ if point is not None:
63
+ plt.plot(point[1], point[0], '.', markersize=8*score, color=c)
64
+
65
+ if show_dist:
66
+ dist_lines = np.empty((poly.shape[-1],2,2))
67
+ dist_lines[:,0,0] = poly[1]
68
+ dist_lines[:,0,1] = poly[0]
69
+ dist_lines[:,1,0] = point[1]
70
+ dist_lines[:,1,1] = point[0]
71
+ plt.gca().add_collection(LineCollection(dist_lines, colors=c, linewidths=0.4))
72
+
73
+ _plot_polygon(poly[1], poly[0], 3*score, color=c)
74
+