DiSTNet2D 0.2.2__tar.gz → 0.2.3__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.
- {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/PKG-INFO +2 -2
- {distnet2d-0.2.2 → distnet2d-0.2.3}/PKG-INFO +2 -2
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/metrics_tf.py +9 -10
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/objectwise_computation_tf.py +62 -21
- {distnet2d-0.2.2 → distnet2d-0.2.3}/setup.py +2 -2
- {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/SOURCES.txt +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/dependency_links.txt +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/requires.txt +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/top_level.txt +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/LICENSE.txt +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/README.md +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/__init__.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/__init__.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/center_edm.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/dydx_iterator.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/medoid.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/swim1d.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/__init__.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/architectures.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/distnet_2d.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/distnet_2d_seg.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/gradient_accumulator.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/layers.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/spatial_attention.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/__init__.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/agc.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/helpers.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/image_derivatives_np.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/image_derivatives_tf.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/losses.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/lovasz_loss.py +0 -0
- {distnet2d-0.2.2 → distnet2d-0.2.3}/setup.cfg +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DiSTNet2D
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: tensorflow/keras implementation of DiSTNet 2D
|
|
5
5
|
Home-page: https://github.com/jeanollion/distnet2d
|
|
6
|
-
Download-URL: https://github.com/jeanollion/distnet2d/releases/download/v0.2.
|
|
6
|
+
Download-URL: https://github.com/jeanollion/distnet2d/releases/download/v0.2.3/distnet2d-0.2.3.tar.gz
|
|
7
7
|
Author: Jean Ollion
|
|
8
8
|
Author-email: jean.ollion@sabilab.fr
|
|
9
9
|
Keywords: Segmentation,Tracking,Cell,Tensorflow,Keras
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DiSTNet2D
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: tensorflow/keras implementation of DiSTNet 2D
|
|
5
5
|
Home-page: https://github.com/jeanollion/distnet2d
|
|
6
|
-
Download-URL: https://github.com/jeanollion/distnet2d/releases/download/v0.2.
|
|
6
|
+
Download-URL: https://github.com/jeanollion/distnet2d/releases/download/v0.2.3/distnet2d-0.2.3.tar.gz
|
|
7
7
|
Author: Jean Ollion
|
|
8
8
|
Author-email: jean.ollion@sabilab.fr
|
|
9
9
|
Keywords: Segmentation,Tracking,Cell,Tensorflow,Keras
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import tensorflow as tf
|
|
2
2
|
from .objectwise_computation_tf import get_max_by_object_fun, coord_distance_fun, get_argmax_2d_by_object_fun, \
|
|
3
3
|
get_mean_by_object_fun, get_label_size, IoU, objectwise_compute, objectwise_compute_channel, reduce_pop_size, \
|
|
4
|
-
|
|
4
|
+
FP
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def get_metrics_fun(
|
|
7
|
+
def get_metrics_fun(scale: float, max_objects_number: int = 0, category:bool = False, tracking:bool=True):
|
|
8
8
|
"""
|
|
9
9
|
return metric function for disnet2D
|
|
10
10
|
assumes iterator in return_central_only= True mode (thus framewindow = 1 and next = true)
|
|
11
11
|
Parameters
|
|
12
12
|
----------
|
|
13
|
-
|
|
13
|
+
scale
|
|
14
14
|
max_objects_number
|
|
15
15
|
reduce
|
|
16
16
|
|
|
@@ -19,7 +19,6 @@ def get_metrics_fun(center_scale: float, max_objects_number: int = 0, category:b
|
|
|
19
19
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
scale = tf.cast(center_scale, tf.float32)
|
|
23
22
|
coord_distance_function = coord_distance_fun(max=True, sqrt=True, pop_fraction=0.25)
|
|
24
23
|
spa_max_fun = get_argmax_2d_by_object_fun()
|
|
25
24
|
mean_fun = get_mean_by_object_fun()
|
|
@@ -41,7 +40,7 @@ def get_metrics_fun(center_scale: float, max_objects_number: int = 0, category:b
|
|
|
41
40
|
labels = tf.transpose(labels, perm=[2, 0, 1]) # (1, Y, X)
|
|
42
41
|
edm = tf.transpose(edm, perm=[2, 0, 1]) # (1, Y, X)
|
|
43
42
|
gdcm = tf.transpose(gdcm, perm=[2, 0, 1]) # (1, Y, X)
|
|
44
|
-
center_values = tf.math.exp(-tf.math.square(tf.math.divide(gdcm, scale)))
|
|
43
|
+
center_values = tf.math.exp(-tf.math.square(tf.math.divide(gdcm, tf.cast(scale/2., tf.float32))))
|
|
45
44
|
ids, sizes, N = get_label_size(labels, max_objects_number) # (1, N), (1, N)
|
|
46
45
|
ids = ids[0]
|
|
47
46
|
sizes = sizes[0]
|
|
@@ -61,14 +60,14 @@ def get_metrics_fun(center_scale: float, max_objects_number: int = 0, category:b
|
|
|
61
60
|
metrics = []
|
|
62
61
|
|
|
63
62
|
# EDM : foreground/background IoU
|
|
64
|
-
pred_foreground = tf.math.greater(edm, tf.cast(0
|
|
63
|
+
pred_foreground = tf.math.greater(edm, tf.cast(0, edm.dtype))
|
|
65
64
|
true_foreground = tf.math.greater(labels, tf.cast(0, labels.dtype))
|
|
66
|
-
edm_IoU = IoU(true_foreground, pred_foreground,
|
|
65
|
+
edm_IoU = IoU(true_foreground, pred_foreground, tolerance_radius=scale / 8.) #
|
|
67
66
|
metrics.append(edm_IoU)
|
|
68
67
|
|
|
69
|
-
# Surface-based False Positive
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
# Surface-based False Positive Density (FPD) based on EDM
|
|
69
|
+
fp = FP(true_foreground, pred_foreground, rate=False, tolerance_radius=scale / 4.) #
|
|
70
|
+
metrics.append(-fp)
|
|
72
71
|
|
|
73
72
|
# contour IoU : problem: true positive contours are usually not precise enough.
|
|
74
73
|
#pred_contours = tf.math.logical_and(tf.math.greater(edm, tf.cast(0.5, edm.dtype)), tf.math.less_equal(edm, tf.cast(1.5, edm.dtype)))
|
|
@@ -211,32 +211,71 @@ def _generate_kernel(sizeY, sizeX, C=1, O=0):
|
|
|
211
211
|
return kernel
|
|
212
212
|
|
|
213
213
|
|
|
214
|
-
def IoU(true_foreground, pred_foreground,
|
|
215
|
-
true_inter = _dilate_mask(true_foreground) if
|
|
214
|
+
def IoU(true_foreground, pred_foreground, tolerance_radius:float=0):
|
|
215
|
+
true_inter = _dilate_mask(true_foreground, radius=tolerance_radius, symmetric_padding=True) if tolerance_radius>=1 else true_foreground
|
|
216
216
|
intersection = tf.math.count_nonzero(tf.math.logical_and(true_inter, pred_foreground), keepdims=False)
|
|
217
217
|
union = tf.math.count_nonzero(tf.math.logical_or(true_foreground, pred_foreground), keepdims=False)
|
|
218
218
|
return tf.cond(tf.math.equal(union, tf.cast(0, union.dtype)), lambda: tf.cast(1., tf.float32), lambda: tf.math.divide(tf.cast(intersection, tf.float32), tf.cast(union, tf.float32))) # if union is null -> metric is 1
|
|
219
219
|
|
|
220
220
|
|
|
221
|
-
def
|
|
221
|
+
def FP(true_foreground, pred_foreground, rate:bool = False, tolerance_radius:float=0):
|
|
222
222
|
true_background = tf.math.logical_not(true_foreground)
|
|
223
223
|
false_positives = tf.logical_and(pred_foreground, true_background)
|
|
224
|
-
false_positives = _erode_mask(false_positives) if
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
224
|
+
false_positives = _erode_mask(false_positives, radius=tolerance_radius, symmetric_padding=False) if tolerance_radius>=1 else false_positives
|
|
225
|
+
fp = tf.math.count_nonzero(false_positives, keepdims=False)
|
|
226
|
+
if rate: # FPR
|
|
227
|
+
tn = tf.math.count_nonzero(true_background, keepdims=False) # for FRP
|
|
228
|
+
return tf.math.divide_no_nan(tf.cast(fp, tf.float32), tf.cast(tn, tf.float32))
|
|
229
|
+
else: # FPD
|
|
230
|
+
#return tf.cast(fp, tf.float32)
|
|
231
|
+
npix = tf.reduce_prod(tf.shape(true_background)) # for FPD
|
|
232
|
+
return tf.math.divide(tf.cast(fp, tf.float32), tf.cast(npix, tf.float32))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _dilate_mask(maskBYX, radius:float=1.5, tolerance:float=0.25, symmetric_padding:bool=True):
|
|
236
|
+
assert 0<=tolerance<0.5
|
|
237
|
+
maskBYX = tf.cast(maskBYX, tf.int32)
|
|
238
|
+
ker, rad = circular_kernel(radius)
|
|
239
|
+
thld = tf.math.floor(tf.cast(tf.math.reduce_sum(ker), tf.float32) * tf.cast(tolerance, tf.float32))
|
|
240
|
+
conv = _convolve(maskBYX, ker, rad, symmetric_padding=symmetric_padding)
|
|
241
|
+
return tf.math.greater(conv, tf.cast(thld, tf.int32))
|
|
228
242
|
|
|
229
243
|
|
|
230
|
-
def
|
|
244
|
+
def _erode_mask(maskBYX, radius:float=1.5, tolerance:float=0.25, symmetric_padding:bool=False):
|
|
245
|
+
assert 0 <= tolerance < 0.5
|
|
231
246
|
maskBYX = tf.cast(maskBYX, tf.int32)
|
|
232
|
-
|
|
233
|
-
|
|
247
|
+
ker, rad = circular_kernel(radius)
|
|
248
|
+
thld = tf.math.ceil(tf.cast(tf.math.reduce_sum(ker), tf.float32) * tf.cast(1 - tolerance, tf.float32))
|
|
249
|
+
conv = _convolve(maskBYX, ker, rad, symmetric_padding=symmetric_padding)
|
|
250
|
+
return tf.math.greater_equal(conv, tf.cast(thld, tf.int32))
|
|
234
251
|
|
|
235
252
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
253
|
+
|
|
254
|
+
def circular_kernel(radius: float) :
|
|
255
|
+
"""
|
|
256
|
+
Create a circular 2D kernel of ones with a given float radius.
|
|
257
|
+
Args:
|
|
258
|
+
radius: The radius of the circle (float).
|
|
259
|
+
Returns:
|
|
260
|
+
A 2D TensorFlow tensor representing the circular kernel (dtype: tf.int32).
|
|
261
|
+
"""
|
|
262
|
+
radius_int = tf.cast(radius, tf.int32)
|
|
263
|
+
diameter = tf.cast(2 * radius_int + 1, tf.int32)
|
|
264
|
+
center = diameter // 2
|
|
265
|
+
|
|
266
|
+
# Create a grid of coordinates
|
|
267
|
+
y = tf.range(-center, diameter - center, dtype=tf.float32)
|
|
268
|
+
x = tf.range(-center, diameter - center, dtype=tf.float32)
|
|
269
|
+
y_grid, x_grid = tf.meshgrid(y, x, indexing='ij')
|
|
270
|
+
|
|
271
|
+
# Compute the distance from the center
|
|
272
|
+
distance = tf.math.sqrt(x_grid**2 + y_grid**2)
|
|
273
|
+
|
|
274
|
+
# Create the circular kernel
|
|
275
|
+
kernel = tf.zeros((diameter, diameter), dtype=tf.int32)
|
|
276
|
+
kernel = tf.where(distance <= radius, tf.ones_like(kernel, dtype=tf.int32), kernel)
|
|
277
|
+
|
|
278
|
+
return kernel, radius_int
|
|
240
279
|
|
|
241
280
|
|
|
242
281
|
def _contour_IoU_fun(pred_contour, mask, size):
|
|
@@ -245,13 +284,15 @@ def _contour_IoU_fun(pred_contour, mask, size):
|
|
|
245
284
|
|
|
246
285
|
|
|
247
286
|
def _compute_contours(maskBYX):
|
|
248
|
-
kernel = [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]
|
|
249
|
-
conv = _convolve(maskBYX, kernel)
|
|
250
|
-
return tf.math.greater(conv, 0) # detect at least one zero in the neighborhood
|
|
287
|
+
kernel = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]])
|
|
288
|
+
conv = _convolve(maskBYX, kernel, 1, symmetric_padding=True)
|
|
289
|
+
return tf.math.greater(conv, tf.cast(0, conv.dtype)) # detect at least one zero in the neighborhood
|
|
251
290
|
|
|
252
291
|
|
|
253
|
-
def _convolve(imageBYX, kernel):
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
292
|
+
def _convolve(imageBYX, kernel, radius, symmetric_padding:bool):
|
|
293
|
+
if symmetric_padding:
|
|
294
|
+
imageBYX = tf.pad(imageBYX, [[0, 0], [radius, radius], [radius, radius]], 'SYMMETRIC')
|
|
295
|
+
imageBYX = imageBYX[..., tf.newaxis]
|
|
296
|
+
kernel = tf.cast(kernel, imageBYX.dtype)
|
|
297
|
+
conv = tf.nn.conv2d(imageBYX, kernel[:, :, tf.newaxis, tf.newaxis], strides=1, padding='VALID' if symmetric_padding else "SAME")
|
|
257
298
|
return conv[..., 0]
|
|
@@ -5,14 +5,14 @@ with open("README.md", "r") as fh:
|
|
|
5
5
|
|
|
6
6
|
setuptools.setup(
|
|
7
7
|
name="DiSTNet2D",
|
|
8
|
-
version="0.2.
|
|
8
|
+
version="0.2.3",
|
|
9
9
|
author="Jean Ollion",
|
|
10
10
|
author_email="jean.ollion@sabilab.fr",
|
|
11
11
|
description="tensorflow/keras implementation of DiSTNet 2D",
|
|
12
12
|
long_description=long_description,
|
|
13
13
|
long_description_content_type="text/markdown",
|
|
14
14
|
url="https://github.com/jeanollion/distnet2d",
|
|
15
|
-
download_url='https://github.com/jeanollion/distnet2d/releases/download/v0.2.
|
|
15
|
+
download_url='https://github.com/jeanollion/distnet2d/releases/download/v0.2.3/distnet2d-0.2.3.tar.gz',
|
|
16
16
|
packages=setuptools.find_packages(),
|
|
17
17
|
keywords=['Segmentation', 'Tracking', 'Cell', 'Tensorflow', 'Keras'],
|
|
18
18
|
classifiers=[
|
|
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
|