cellprofiler-library-nightly 5.0.0.dev501__tar.gz → 5.0.0.dev512__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 (94) hide show
  1. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/PKG-INFO +1 -1
  2. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/_version.py +3 -3
  3. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/functions/image_processing.py +116 -2
  4. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/functions/measurement.py +109 -2
  5. cellprofiler_library_nightly-5.0.0.dev512/cellprofiler_library/modules/_measuregranularity.py +80 -0
  6. cellprofiler_library_nightly-5.0.0.dev512/cellprofiler_library/opts/measuregranularity.py +2 -0
  7. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library_nightly.egg-info/PKG-INFO +1 -1
  8. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library_nightly.egg-info/SOURCES.txt +2 -0
  9. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/LICENSE +0 -0
  10. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/README.md +0 -0
  11. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/__init__.py +0 -0
  12. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/functions/__init__.py +0 -0
  13. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/functions/file_processing.py +0 -0
  14. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/functions/object_processing.py +0 -0
  15. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/functions/segmentation.py +0 -0
  16. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/measurement_model.py +0 -0
  17. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/__init__.py +0 -0
  18. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_closing.py +0 -0
  19. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_colortogray.py +0 -0
  20. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_combineobjects.py +0 -0
  21. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_convertimagetoobjects.py +0 -0
  22. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_convertobjectstoimage.py +0 -0
  23. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_correctilluminationapply.py +0 -0
  24. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_crop.py +0 -0
  25. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_dilateimage.py +0 -0
  26. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_dilateobjects.py +0 -0
  27. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_enhanceedges.py +0 -0
  28. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_enhanceorsuppressfeatures.py +0 -0
  29. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_erodeimage.py +0 -0
  30. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_erodeobjects.py +0 -0
  31. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_expandorshrinkobjects.py +0 -0
  32. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_fillobjects.py +0 -0
  33. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_flipandrotate.py +0 -0
  34. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_gaussianfilter.py +0 -0
  35. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_graytocolor.py +0 -0
  36. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_identifyprimaryobjects.py +0 -0
  37. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_identifysecondaryobjects.py +0 -0
  38. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_identifytertiaryobjects.py +0 -0
  39. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_imagemath.py +0 -0
  40. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_measurecolocalization.py +0 -0
  41. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_measureimageoverlap.py +0 -0
  42. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_measureobjectsizeshape.py +0 -0
  43. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_medialaxis.py +0 -0
  44. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_medianfilter.py +0 -0
  45. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_morph.py +0 -0
  46. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_morphologicalskeleton.py +0 -0
  47. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_opening.py +0 -0
  48. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_overlayobjects.py +0 -0
  49. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_overlayoutlines.py +0 -0
  50. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_reducenoise.py +0 -0
  51. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_removeholes.py +0 -0
  52. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_resize.py +0 -0
  53. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_savecroppedobjects.py +0 -0
  54. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_shrinktoobjectcenters.py +0 -0
  55. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_smooth.py +0 -0
  56. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_threshold.py +0 -0
  57. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/modules/_watershed.py +0 -0
  58. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/__init__.py +0 -0
  59. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/colortogray.py +0 -0
  60. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/convertimagetoobjects.py +0 -0
  61. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/convertobjectstoimage.py +0 -0
  62. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/correctilluminationapply.py +0 -0
  63. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/crop.py +0 -0
  64. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/dilateimage.py +0 -0
  65. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/dilateobjects.py +0 -0
  66. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/enhanceedges.py +0 -0
  67. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/enhanceorsuppressfeatures.py +0 -0
  68. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/erodeimage.py +0 -0
  69. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/erodeobjects.py +0 -0
  70. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/flipandrotate.py +0 -0
  71. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/graytocolor.py +0 -0
  72. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/identifyprimaryobjects.py +0 -0
  73. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/identifysecondaryobjects.py +0 -0
  74. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/identifytertiaryobjects.py +0 -0
  75. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/imagemath.py +0 -0
  76. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/measurecolocalization.py +0 -0
  77. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/measureimageoverlap.py +0 -0
  78. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/morph.py +0 -0
  79. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/objectsizeshapefeatures.py +0 -0
  80. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/overlayoutlines.py +0 -0
  81. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/removeholes.py +0 -0
  82. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/resize.py +0 -0
  83. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/shrinktoobjectcenters.py +0 -0
  84. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/smooth.py +0 -0
  85. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/structuring_elements.py +0 -0
  86. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/opts/threshold.py +0 -0
  87. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/py.typed +0 -0
  88. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library/types.py +0 -0
  89. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library_nightly.egg-info/dependency_links.txt +0 -0
  90. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library_nightly.egg-info/requires.txt +0 -0
  91. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/cellprofiler_library_nightly.egg-info/top_level.txt +0 -0
  92. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/environment.yml +0 -0
  93. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/pyproject.toml +0 -0
  94. {cellprofiler_library_nightly-5.0.0.dev501 → cellprofiler_library_nightly-5.0.0.dev512}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellprofiler-library-nightly
3
- Version: 5.0.0.dev501
3
+ Version: 5.0.0.dev512
4
4
  Summary: cellprofiler-library implements CellProfiler's image processing and mathematical code, and is usable as a standalone library
5
5
  Author: Anne Carpenter, Thouis (Ray) Jones, Lee Kamentsky, Vebjorn Ljosa, David Logan, Mark Bray, Madison Swain-Bowden, Allen Goodman, Claire McQuinn, Alice Lucas, Callum Tromans-Coia
6
6
  Author-email: Beth Cimini <bcimini@broadinstitute.org>, David Stirling <dstirling@glencoesoftware.com>, Nodar Gogoberidze <ngogober@broadinstitute.org>
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '5.0.0.dev501'
32
- __version_tuple__ = version_tuple = (5, 0, 0, 'dev501')
31
+ __version__ = version = '5.0.0.dev512'
32
+ __version_tuple__ = version_tuple = (5, 0, 0, 'dev512')
33
33
 
34
- __commit_id__ = commit_id = 'gb8fc0acf1'
34
+ __commit_id__ = commit_id = 'g36bc7931b'
@@ -15,9 +15,9 @@ import scipy
15
15
  import scipy.interpolate
16
16
  import matplotlib
17
17
  import math
18
+ from numpy.typing import NDArray
18
19
  from centrosome.cpmorphology import fixup_scipy_ndimage_result as fix
19
20
  from typing import Any, Optional, Tuple, Callable, Union, List, cast, Dict, TypeVar
20
- from numpy.typing import NDArray
21
21
  from skimage.restoration import denoise_bilateral
22
22
  from cellprofiler_library.types import (
23
23
  ImageGrayscale, ImageGrayscaleMask,
@@ -262,7 +262,6 @@ def morphology_dilation(image: ImageAny, structuring_element: StructuringElement
262
262
  y_data = skimage.morphology.dilation(image, structuring_element)
263
263
  return y_data
264
264
 
265
-
266
265
  def median_filter(image, window_size, mode):
267
266
  return scipy.ndimage.median_filter(image, size=window_size, mode=mode)
268
267
 
@@ -2199,3 +2198,118 @@ def apply_threshold_to_objects(
2199
2198
  output_image_arr[mask] = (image >= scaled_image[segmented - 1])
2200
2199
 
2201
2200
  return output_image_arr
2201
+
2202
+
2203
+ ################################################################################
2204
+ # MeasureGranularity
2205
+ ################################################################################
2206
+
2207
+ def rescale_pixel_data_and_mask(
2208
+ new_shape: Union[Tuple[int, ...], NDArray[numpy.float64]],
2209
+ subsample_size: float,
2210
+ im_pixel_data: ImageGrayscale,
2211
+ im_mask: ImageGrayscaleMask,
2212
+ dimensions: int
2213
+ ) -> Tuple[ImageGrayscale, ImageGrayscaleMask]:
2214
+ if dimensions == 2:
2215
+ i, j = (
2216
+ numpy.mgrid[0 : new_shape[0], 0 : new_shape[1]].astype(float)
2217
+ / subsample_size
2218
+ )
2219
+ pixels = scipy.ndimage.map_coordinates(im_pixel_data, (i, j), order=1)
2220
+ mask = (
2221
+ scipy.ndimage.map_coordinates(im_mask.astype(float), (i, j)).astype(float) > 0.9
2222
+ )
2223
+ else:
2224
+ k, i, j = (
2225
+ numpy.mgrid[0 : new_shape[0], 0 : new_shape[1], 0 : new_shape[2]].astype(float)
2226
+ / subsample_size
2227
+ )
2228
+ pixels = scipy.ndimage.map_coordinates(im_pixel_data, (k, i, j), order=1)
2229
+ mask = (
2230
+ scipy.ndimage.map_coordinates(im_mask.astype(float), (k, i, j)).astype(float) > 0.9
2231
+ )
2232
+ return pixels, mask
2233
+
2234
+
2235
+ def restore_scale(
2236
+ dimensions: int,
2237
+ orig_shape: NDArray[numpy.float64],
2238
+ scaled_shape: NDArray[numpy.float64],
2239
+ scaled_pixels: ImageGrayscale
2240
+ ) -> ImageGrayscale:
2241
+ if dimensions == 2:
2242
+ i, j = numpy.mgrid[0 : orig_shape[0], 0 : orig_shape[1]].astype(float)
2243
+ #
2244
+ # Make sure the mapping only references the index range of
2245
+ # back_pixels.
2246
+ #
2247
+ i *= float(scaled_shape[0] - 1) / float(orig_shape[0] - 1)
2248
+ j *= float(scaled_shape[1] - 1) / float(orig_shape[1] - 1)
2249
+ scaled_pixels = scipy.ndimage.map_coordinates(scaled_pixels, (i, j), order=1).astype(float)
2250
+ else:
2251
+ k, i, j = numpy.mgrid[
2252
+ 0 : orig_shape[0], 0 : orig_shape[1], 0 : orig_shape[2]
2253
+ ].astype(float)
2254
+ k *= float(scaled_shape[0] - 1) / float(orig_shape[0] - 1)
2255
+ i *= float(scaled_shape[1] - 1) / float(orig_shape[1] - 1)
2256
+ j *= float(scaled_shape[2] - 1) / float(orig_shape[2] - 1)
2257
+ scaled_pixels = scipy.ndimage.map_coordinates(scaled_pixels, (k, i, j), order=1).astype(float)
2258
+ return scaled_pixels
2259
+
2260
+ def downsample_image_and_mask(
2261
+ im_pixel_data: ImageGrayscale,
2262
+ im_mask: ImageGrayscaleMask,
2263
+ dimensions: int,
2264
+ subsample_size: float
2265
+ ) -> Tuple[ImageGrayscale, ImageGrayscaleMask, NDArray[numpy.float64]]:
2266
+ #
2267
+ # Downsample the image and mask
2268
+ #
2269
+ new_shape = numpy.array(im_pixel_data.shape)
2270
+ if subsample_size < 1:
2271
+ new_shape = new_shape * subsample_size
2272
+ pixels, mask = rescale_pixel_data_and_mask(new_shape, subsample_size, im_pixel_data, im_mask, dimensions)
2273
+ else:
2274
+ pixels = im_pixel_data.copy()
2275
+ mask = im_mask.copy()
2276
+ return pixels, mask, new_shape
2277
+
2278
+ def apply_grayscale_tophat_filter(
2279
+ pixels: ImageGrayscale,
2280
+ mask: ImageGrayscaleMask,
2281
+ dimensions: int,
2282
+ image_sample_size: float,
2283
+ radius: int,
2284
+ new_shape: NDArray[numpy.float64]
2285
+ ) -> ImageGrayscale:
2286
+ back_pixels, back_mask, back_shape = downsample_image_and_mask(pixels, mask, dimensions, image_sample_size)
2287
+ # radius = element_size
2288
+ footprint = get_morphology_footprint(radius, dimensions)
2289
+ back_pixels = masked_erode(back_pixels, back_mask, footprint)
2290
+ back_pixels = masked_dilate(back_pixels, back_mask, footprint)
2291
+ if image_sample_size < 1:
2292
+ back_pixels = restore_scale(dimensions, new_shape, back_shape, back_pixels)
2293
+ pixels -= back_pixels
2294
+ pixels[pixels < 0] = 0
2295
+ return pixels
2296
+
2297
+ def masked_dilate(im, mask, footprint):
2298
+ im_mask = numpy.zeros_like(im)
2299
+ im_mask[mask == True] = im[mask == True]
2300
+ im = morphology_dilation(im_mask, footprint)
2301
+ return im
2302
+
2303
+ def masked_erode(im, mask, footprint):
2304
+ im_mask = numpy.zeros_like(im)
2305
+ im_mask[mask == True] = im[mask == True]
2306
+ im = morphology_erosion(im_mask, footprint)
2307
+ return im
2308
+
2309
+ def get_morphology_footprint(radius, dimensions):
2310
+ if dimensions == 2:
2311
+ footprint = skimage.morphology.disk(radius, dtype=bool)
2312
+ else:
2313
+ footprint = skimage.morphology.ball(radius, dtype=bool)
2314
+ return footprint
2315
+
@@ -11,7 +11,7 @@ import centrosome.fastemd
11
11
 
12
12
  from centrosome.cpmorphology import fixup_scipy_ndimage_result as fix
13
13
  from sklearn.cluster import KMeans
14
- from typing import Tuple, Optional, Dict, Callable
14
+ from typing import Tuple, Optional, Dict, Callable, List, Union
15
15
  from scipy.linalg import lstsq
16
16
  from numpy.typing import NDArray
17
17
 
@@ -21,11 +21,14 @@ from cellprofiler_library.functions.segmentation import indices_from_ijv
21
21
  from cellprofiler_library.functions.segmentation import count_from_ijv
22
22
  from cellprofiler_library.functions.segmentation import areas_from_ijv
23
23
  from cellprofiler_library.functions.segmentation import cast_labels_to_label_set
24
+ from cellprofiler_library.functions.image_processing import masked_erode, restore_scale, get_morphology_footprint
25
+
24
26
  from cellprofiler_library.opts.objectsizeshapefeatures import ObjectSizeShapeFeatures
25
- from cellprofiler_library.types import Pixel, ObjectLabel
27
+ from cellprofiler_library.types import Pixel, ObjectLabel, ImageGrayscale, ImageGrayscaleMask, ObjectSegmentation
26
28
  from cellprofiler_library.opts.measurecolocalization import CostesMethod
27
29
 
28
30
 
31
+
29
32
  def measure_image_overlap_statistics(
30
33
  ground_truth_image,
31
34
  test_image,
@@ -1377,3 +1380,107 @@ def linear_costes(
1377
1380
  except ValueError:
1378
1381
  break
1379
1382
  return thr_fi_c, thr_si_c
1383
+
1384
+
1385
+ ###############################################################################
1386
+ # Measure Granularity
1387
+ ###############################################################################
1388
+
1389
+ class ObjectRecord(object):
1390
+ def __init__(
1391
+ self,
1392
+ name: str,
1393
+ segmented: ObjectSegmentation,
1394
+ im_mask: Optional[ImageGrayscaleMask],
1395
+ im_pixel_data: Optional[ImageGrayscale]
1396
+ ):
1397
+ self.name = name
1398
+ self.labels = segmented
1399
+ self.nobjects = np.max(self.labels)
1400
+ if self.nobjects != 0:
1401
+ assert im_mask is not None
1402
+ assert im_pixel_data is not None
1403
+ self.range = np.arange(1, np.max(self.labels) + 1)
1404
+ self.labels = self.labels.copy()
1405
+ self.labels[~im_mask] = 0
1406
+ self.current_mean = fix(
1407
+ scipy.ndimage.mean(im_pixel_data, self.labels, self.range)
1408
+ )
1409
+ self.start_mean = np.maximum(
1410
+ self.current_mean, np.finfo(float).eps
1411
+ )
1412
+
1413
+
1414
+ def get_granularity_measurements(
1415
+ im_pixel_data: ImageGrayscale,
1416
+ pixels: ImageGrayscale,
1417
+ mask: ImageGrayscaleMask,
1418
+ new_shape: NDArray[numpy.float64],
1419
+ granular_spectrum_length: int,
1420
+ dimensions: int,
1421
+ object_records: List[ObjectRecord]
1422
+ ) -> Tuple[List[List[List[Union[str, NDArray[numpy.float64]]]]], List[float]]:
1423
+ # Transcribed from the Matlab module: granspectr function
1424
+ #
1425
+ # CALCULATES GRANULAR SPECTRUM, ALSO KNOWN AS SIZE DISTRIBUTION,
1426
+ # GRANULOMETRY, AND PATTERN SPECTRUM, SEE REF.:
1427
+ # J.Serra, Image Analysis and Mathematical Morphology, Vol. 1. Academic Press, London, 1989
1428
+ # Maragos,P. "Pattern spectrum and multiscale shape representation", IEEE Transactions on Pattern Analysis and Machine Intelligence, 11, N 7, pp. 701-716, 1989
1429
+ # L.Vincent "Granulometries and Opening Trees", Fundamenta Informaticae, 41, No. 1-2, pp. 57-90, IOS Press, 2000.
1430
+ # L.Vincent "Morphological Area Opening and Closing for Grayscale Images", Proc. NATO Shape in Picture Workshop, Driebergen, The Netherlands, pp. 197-208, 1992.
1431
+ # I.Ravkin, V.Temov "Bit representation techniques and image processing", Applied Informatics, v.14, pp. 41-90, Finances and Statistics, Moskow, 1988 (in Russian)
1432
+ # THIS IMPLEMENTATION INSTEAD OF OPENING USES EROSION FOLLOWED BY RECONSTRUCTION
1433
+ #
1434
+ footprint = get_morphology_footprint(1, dimensions)
1435
+ ng = granular_spectrum_length
1436
+ startmean = np.mean(pixels[mask])
1437
+ ero = pixels.copy()
1438
+ # Mask the test image so that masked pixels will have no effect
1439
+ # during reconstruction
1440
+ #
1441
+ ero[~mask] = 0
1442
+ currentmean = startmean
1443
+ startmean = max(startmean, np.finfo(float).eps)
1444
+ measurements_arr = []
1445
+ image_measurements_arr = []
1446
+
1447
+ for i in range(1, ng + 1):
1448
+ prevmean = currentmean
1449
+ ero = masked_erode(ero, mask, footprint)
1450
+ rec = skimage.morphology.reconstruction(ero, pixels, footprint=footprint)
1451
+ currentmean = np.mean(rec[mask])
1452
+ gs = (prevmean - currentmean) * 100 / startmean
1453
+ image_measurements_arr += [gs]
1454
+ # measurements.add_image_measurement(feature, gs)
1455
+ #
1456
+ # Restore the reconstructed image to the shape of the
1457
+ # original image so we can match against object labels
1458
+ #
1459
+ orig_shape = im_pixel_data.shape
1460
+ rec = restore_scale(dimensions, orig_shape, new_shape, rec)
1461
+
1462
+ #
1463
+ # Calculate the means for the objects
1464
+ #
1465
+ obj_measurements=[]
1466
+ for object_record in object_records:
1467
+ assert isinstance(object_record, ObjectRecord)
1468
+ if object_record.nobjects > 0:
1469
+ new_mean = fix(
1470
+ scipy.ndimage.mean(
1471
+ rec, object_record.labels, object_record.range
1472
+ )
1473
+ )
1474
+ gss = (
1475
+ (object_record.current_mean - new_mean)
1476
+ * 100
1477
+ / object_record.start_mean
1478
+ )
1479
+ object_record.current_mean = new_mean
1480
+ else:
1481
+ gss = np.zeros((0,))
1482
+ obj_measurements += [[object_record.name, gss]]
1483
+ measurements_arr += [obj_measurements]
1484
+ return measurements_arr, image_measurements_arr
1485
+
1486
+
@@ -0,0 +1,80 @@
1
+ from pydantic import validate_call, ConfigDict, Field
2
+ from typing import Annotated, List, Dict, Any, Tuple
3
+ from enum import Enum
4
+ import numpy as np
5
+
6
+ from cellprofiler_library.measurement_model import LibraryMeasurements
7
+ from cellprofiler_library.functions.measurement import get_granularity_measurements, ObjectRecord
8
+ from cellprofiler_library.functions.image_processing import apply_grayscale_tophat_filter, downsample_image_and_mask
9
+ from cellprofiler_library.types import ImageGrayscale, ImageGrayscaleMask
10
+
11
+ class GranularityMeasurementFormat(str, Enum):
12
+ GRANULARITY = "Granularity_%d_%s"
13
+
14
+ @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
15
+ def measure_granularity(
16
+ image_name: Annotated[str, Field(description="Name of the image")],
17
+ im_pixel_data: Annotated[ImageGrayscale, Field(description="Pixel values of the image")],
18
+ im_mask: Annotated[ImageGrayscaleMask, Field(description="Boolean mask of where the measurements should be made")],
19
+ subsample_size: Annotated[float, Field(description="Subsampling factor for granularity measurements")],
20
+ image_sample_size: Annotated[float, Field(description="Subsampling factor for background reduction")],
21
+ element_size: Annotated[int, Field(description="Radius of structuring element")],
22
+ object_records: Annotated[List[ObjectRecord], Field(description="Object records")],
23
+ granular_spectrum_length: Annotated[int, Field(description="Range of the granular spectrum")],
24
+ dimensions: Annotated[int, Field(description="Dimensionality of the image")] = 2,
25
+ ) -> Tuple[LibraryMeasurements, List[str]]:
26
+ #
27
+ # Downsample the image and mask
28
+ #
29
+ pixels, mask, new_shape = downsample_image_and_mask(im_pixel_data, im_mask, dimensions, subsample_size)
30
+
31
+ #
32
+ # Remove background pixels using a greyscale tophat filter
33
+ #
34
+ pixels = apply_grayscale_tophat_filter(pixels, mask, dimensions, image_sample_size, element_size, new_shape)
35
+
36
+ #
37
+ # Compute measurements
38
+ #
39
+ measurements_arr, image_measurements_arr = get_granularity_measurements(
40
+ im_pixel_data,
41
+ pixels,
42
+ mask,
43
+ new_shape,
44
+ granular_spectrum_length,
45
+ dimensions,
46
+ object_records
47
+ )
48
+
49
+ measurements = LibraryMeasurements()
50
+ stats_strings = []
51
+
52
+ # Process Image Measurements
53
+ for i, gs_value in enumerate(image_measurements_arr):
54
+ spectrum_index = i + 1
55
+ feature_name = GranularityMeasurementFormat.GRANULARITY % (spectrum_index, image_name)
56
+ measurements.add_image_measurement(feature_name, gs_value)
57
+ stats_strings.append("%.2f" % gs_value)
58
+
59
+ # Process Object Measurements
60
+ # measurements_arr is list of lists. Outer list index i corresponds to spectrum_index i+1.
61
+ for i, obj_measurements_list in enumerate(measurements_arr):
62
+ spectrum_index = i + 1
63
+ feature_name = GranularityMeasurementFormat.GRANULARITY % (spectrum_index, image_name)
64
+
65
+ for obj_name, obj_gss in obj_measurements_list:
66
+ measurements.add_measurement(obj_name, feature_name, obj_gss)
67
+
68
+ # Calculate stats for this object measurement and add to Image measurements
69
+ stat_name_base = f"{feature_name}_{obj_name}"
70
+
71
+ measurements.add_image_measurement(f"Mean_{stat_name_base}", np.mean(obj_gss) if len(obj_gss) > 0 else 0.0)
72
+ measurements.add_image_measurement(f"Median_{stat_name_base}", np.median(obj_gss) if len(obj_gss) > 0 else 0.0)
73
+ measurements.add_image_measurement(f"Max_{stat_name_base}", np.max(obj_gss) if len(obj_gss) > 0 else 0.0)
74
+ measurements.add_image_measurement(f"Min_{stat_name_base}", np.min(obj_gss) if len(obj_gss) > 0 else 0.0)
75
+ measurements.add_image_measurement(f"StDev_{stat_name_base}", np.std(obj_gss) if len(obj_gss) > 0 else 0.0)
76
+
77
+ # Summary for UI display
78
+ summary = [image_name] + stats_strings
79
+
80
+ return measurements, summary
@@ -0,0 +1,2 @@
1
+ class TemplateMeasurementFormat(str):
2
+ GRANULARITY = "Granularity_%s_%s"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellprofiler-library-nightly
3
- Version: 5.0.0.dev501
3
+ Version: 5.0.0.dev512
4
4
  Summary: cellprofiler-library implements CellProfiler's image processing and mathematical code, and is usable as a standalone library
5
5
  Author: Anne Carpenter, Thouis (Ray) Jones, Lee Kamentsky, Vebjorn Ljosa, David Logan, Mark Bray, Madison Swain-Bowden, Allen Goodman, Claire McQuinn, Alice Lucas, Callum Tromans-Coia
6
6
  Author-email: Beth Cimini <bcimini@broadinstitute.org>, David Stirling <dstirling@glencoesoftware.com>, Nodar Gogoberidze <ngogober@broadinstitute.org>
@@ -37,6 +37,7 @@ cellprofiler_library/modules/_identifysecondaryobjects.py
37
37
  cellprofiler_library/modules/_identifytertiaryobjects.py
38
38
  cellprofiler_library/modules/_imagemath.py
39
39
  cellprofiler_library/modules/_measurecolocalization.py
40
+ cellprofiler_library/modules/_measuregranularity.py
40
41
  cellprofiler_library/modules/_measureimageoverlap.py
41
42
  cellprofiler_library/modules/_measureobjectsizeshape.py
42
43
  cellprofiler_library/modules/_medialaxis.py
@@ -73,6 +74,7 @@ cellprofiler_library/opts/identifysecondaryobjects.py
73
74
  cellprofiler_library/opts/identifytertiaryobjects.py
74
75
  cellprofiler_library/opts/imagemath.py
75
76
  cellprofiler_library/opts/measurecolocalization.py
77
+ cellprofiler_library/opts/measuregranularity.py
76
78
  cellprofiler_library/opts/measureimageoverlap.py
77
79
  cellprofiler_library/opts/morph.py
78
80
  cellprofiler_library/opts/objectsizeshapefeatures.py