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.
Files changed (32) hide show
  1. {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/PKG-INFO +2 -2
  2. {distnet2d-0.2.2 → distnet2d-0.2.3}/PKG-INFO +2 -2
  3. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/metrics_tf.py +9 -10
  4. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/objectwise_computation_tf.py +62 -21
  5. {distnet2d-0.2.2 → distnet2d-0.2.3}/setup.py +2 -2
  6. {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/SOURCES.txt +0 -0
  7. {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/dependency_links.txt +0 -0
  8. {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/requires.txt +0 -0
  9. {distnet2d-0.2.2 → distnet2d-0.2.3}/DiSTNet2D.egg-info/top_level.txt +0 -0
  10. {distnet2d-0.2.2 → distnet2d-0.2.3}/LICENSE.txt +0 -0
  11. {distnet2d-0.2.2 → distnet2d-0.2.3}/README.md +0 -0
  12. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/__init__.py +0 -0
  13. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/__init__.py +0 -0
  14. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/center_edm.py +0 -0
  15. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/dydx_iterator.py +0 -0
  16. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/medoid.py +0 -0
  17. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/data/swim1d.py +0 -0
  18. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/__init__.py +0 -0
  19. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/architectures.py +0 -0
  20. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/distnet_2d.py +0 -0
  21. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/distnet_2d_seg.py +0 -0
  22. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/gradient_accumulator.py +0 -0
  23. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/layers.py +0 -0
  24. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/model/spatial_attention.py +0 -0
  25. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/__init__.py +0 -0
  26. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/agc.py +0 -0
  27. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/helpers.py +0 -0
  28. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/image_derivatives_np.py +0 -0
  29. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/image_derivatives_tf.py +0 -0
  30. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/losses.py +0 -0
  31. {distnet2d-0.2.2 → distnet2d-0.2.3}/distnet_2d/utils/lovasz_loss.py +0 -0
  32. {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.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.2/distnet2d-0.2.2.tar.gz
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.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.2/distnet2d-0.2.2.tar.gz
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
- FPR
4
+ FP
5
5
 
6
6
 
7
- def get_metrics_fun(center_scale: float, max_objects_number: int = 0, category:bool = False, tracking:bool=True):
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
- center_scale
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.5, edm.dtype))
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, tolerance=False)
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 Rate (FPR) based on EDM
70
- #fpr = FPR(true_foreground, pred_foreground, tolerance=True)
71
- #metrics.append(-fpr)
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, tolerance:bool=False):
215
- true_inter = _dilate_mask(true_foreground) if tolerance else true_foreground
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 FPR(true_foreground, pred_foreground, tolerance:bool=False):
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 tolerance else false_positives
225
- num_fp = tf.reduce_sum(tf.cast(false_positives, tf.float32))
226
- num_tn = tf.reduce_sum(tf.cast(true_background, tf.float32))
227
- return tf.math.divide_no_nan(num_fp, num_tn)
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 _dilate_mask(maskBYX):
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
- conv = _convolve(maskBYX, tf.ones(shape=[3, 3], dtype=tf.int32))
233
- return tf.math.greater(conv, tf.cast(2, tf.int32))
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
- def _erode_mask(maskBYX):
237
- maskBYX = tf.cast(maskBYX, tf.int32)
238
- conv = _convolve(maskBYX, tf.ones(shape=[3, 3], dtype=tf.int32))
239
- return tf.math.greater_equal(conv, tf.cast(7, tf.int32))
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
- padded = tf.pad(imageBYX, [[0, 0], [1, 1], [1, 1]], 'SYMMETRIC')
255
- input = padded[..., tf.newaxis]
256
- conv = tf.nn.conv2d(input, kernel[:, :, tf.newaxis, tf.newaxis], strides=1, padding='VALID')
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.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.2/distnet2d-0.2.2.tar.gz',
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