cellprofiler-library-nightly 5.0.0.dev592__tar.gz → 5.0.0.dev610__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 (110) hide show
  1. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/PKG-INFO +1 -1
  2. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/_version.py +3 -3
  3. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/functions/measurement.py +261 -0
  4. cellprofiler_library_nightly-5.0.0.dev610/cellprofiler_library/modules/_measureimagequality.py +302 -0
  5. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_threshold.py +2 -0
  6. cellprofiler_library_nightly-5.0.0.dev610/cellprofiler_library/opts/measureimagequality.py +89 -0
  7. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library_nightly.egg-info/PKG-INFO +1 -1
  8. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library_nightly.egg-info/SOURCES.txt +2 -0
  9. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/LICENSE +0 -0
  10. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/README.md +0 -0
  11. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/__init__.py +0 -0
  12. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/functions/__init__.py +0 -0
  13. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/functions/file_processing.py +0 -0
  14. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/functions/image_processing.py +0 -0
  15. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/functions/object_processing.py +0 -0
  16. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/functions/segmentation.py +0 -0
  17. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/measurement_model.py +0 -0
  18. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/__init__.py +0 -0
  19. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_closing.py +0 -0
  20. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_colortogray.py +0 -0
  21. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_combineobjects.py +0 -0
  22. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_convertimagetoobjects.py +0 -0
  23. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_convertobjectstoimage.py +0 -0
  24. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_correctilluminationapply.py +0 -0
  25. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_crop.py +0 -0
  26. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_dilateimage.py +0 -0
  27. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_dilateobjects.py +0 -0
  28. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_enhanceedges.py +0 -0
  29. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_enhanceorsuppressfeatures.py +0 -0
  30. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_erodeimage.py +0 -0
  31. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_erodeobjects.py +0 -0
  32. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_expandorshrinkobjects.py +0 -0
  33. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_fillobjects.py +0 -0
  34. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_flipandrotate.py +0 -0
  35. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_gaussianfilter.py +0 -0
  36. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_graytocolor.py +0 -0
  37. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_identifyprimaryobjects.py +0 -0
  38. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_identifysecondaryobjects.py +0 -0
  39. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_identifytertiaryobjects.py +0 -0
  40. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_imagemath.py +0 -0
  41. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measurecolocalization.py +0 -0
  42. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measuregranularity.py +0 -0
  43. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureimageareaoccupied.py +0 -0
  44. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureimageintensity.py +0 -0
  45. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureimageoverlap.py +0 -0
  46. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureimageskeleton.py +0 -0
  47. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureobjectintensity.py +0 -0
  48. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureobjectneighbors.py +0 -0
  49. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureobjectoverlap.py +0 -0
  50. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureobjectsizeshape.py +0 -0
  51. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_measureobjectskeleton.py +0 -0
  52. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_medialaxis.py +0 -0
  53. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_medianfilter.py +0 -0
  54. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_morph.py +0 -0
  55. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_morphologicalskeleton.py +0 -0
  56. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_opening.py +0 -0
  57. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_overlayobjects.py +0 -0
  58. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_overlayoutlines.py +0 -0
  59. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_reducenoise.py +0 -0
  60. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_removeholes.py +0 -0
  61. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_resize.py +0 -0
  62. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_savecroppedobjects.py +0 -0
  63. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_shrinktoobjectcenters.py +0 -0
  64. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_smooth.py +0 -0
  65. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/modules/_watershed.py +0 -0
  66. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/__init__.py +0 -0
  67. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/colortogray.py +0 -0
  68. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/convertimagetoobjects.py +0 -0
  69. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/convertobjectstoimage.py +0 -0
  70. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/correctilluminationapply.py +0 -0
  71. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/crop.py +0 -0
  72. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/dilateimage.py +0 -0
  73. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/dilateobjects.py +0 -0
  74. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/enhanceedges.py +0 -0
  75. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/enhanceorsuppressfeatures.py +0 -0
  76. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/erodeimage.py +0 -0
  77. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/erodeobjects.py +0 -0
  78. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/flipandrotate.py +0 -0
  79. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/graytocolor.py +0 -0
  80. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/identifyprimaryobjects.py +0 -0
  81. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/identifysecondaryobjects.py +0 -0
  82. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/identifytertiaryobjects.py +0 -0
  83. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/imagemath.py +0 -0
  84. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measurecolocalization.py +0 -0
  85. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measuregranularity.py +0 -0
  86. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureimageareaoccupied.py +0 -0
  87. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureimageintensity.py +0 -0
  88. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureimageoverlap.py +0 -0
  89. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureimageskeleton.py +0 -0
  90. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureobjectintensity.py +0 -0
  91. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureobjectneighbors.py +0 -0
  92. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureobjectoverlap.py +0 -0
  93. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/measureobjectskeleton.py +0 -0
  94. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/morph.py +0 -0
  95. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/objectsizeshapefeatures.py +0 -0
  96. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/overlayoutlines.py +0 -0
  97. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/removeholes.py +0 -0
  98. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/resize.py +0 -0
  99. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/shrinktoobjectcenters.py +0 -0
  100. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/smooth.py +0 -0
  101. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/structuring_elements.py +0 -0
  102. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/opts/threshold.py +0 -0
  103. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/py.typed +0 -0
  104. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library/types.py +0 -0
  105. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library_nightly.egg-info/dependency_links.txt +0 -0
  106. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library_nightly.egg-info/requires.txt +0 -0
  107. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/cellprofiler_library_nightly.egg-info/top_level.txt +0 -0
  108. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/environment.yml +0 -0
  109. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/pyproject.toml +0 -0
  110. {cellprofiler_library_nightly-5.0.0.dev592 → cellprofiler_library_nightly-5.0.0.dev610}/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.dev592
3
+ Version: 5.0.0.dev610
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.dev592'
32
- __version_tuple__ = version_tuple = (5, 0, 0, 'dev592')
31
+ __version__ = version = '5.0.0.dev610'
32
+ __version_tuple__ = version_tuple = (5, 0, 0, 'dev610')
33
33
 
34
- __commit_id__ = commit_id = 'g9880bd09c'
34
+ __commit_id__ = commit_id = 'g53b2372ff'
@@ -10,6 +10,9 @@ import centrosome.propagate
10
10
  import centrosome.fastemd
11
11
  import centrosome.index
12
12
  import centrosome.cpmorphology
13
+ import centrosome.threshold
14
+ import centrosome.haralick
15
+ import centrosome.radial_power_spectrum
13
16
  from centrosome.outline import outline
14
17
  from functools import reduce
15
18
  from sklearn.cluster import KMeans
@@ -2173,6 +2176,264 @@ def compute_earth_movers_distance_objects(
2173
2176
  return emd
2174
2177
 
2175
2178
 
2179
+ ###############################################################################
2180
+ # MeasureImageQuality
2181
+ ###############################################################################
2182
+
2183
+ def get_focus_score_for_scale_group(
2184
+ scale_groups: Sequence[int],
2185
+ pixel_data: ImageGrayscale,
2186
+ dimensions: int,
2187
+ image_mask: Optional[ImageGrayscaleMask]=None,
2188
+ ) -> Tuple[
2189
+ NDArray[numpy.float_],
2190
+ int,
2191
+ Sequence[numpy.float_]
2192
+ ]:
2193
+ if image_mask is not None:
2194
+ masked_pixel_data = pixel_data[image_mask]
2195
+ else:
2196
+ masked_pixel_data = pixel_data
2197
+ shape = pixel_data.shape
2198
+ local_focus_score = []
2199
+ focus_score = 0
2200
+ for scale in scale_groups:
2201
+ focus_score = 0
2202
+ if len(masked_pixel_data):
2203
+ mean_image_value = numpy.mean(masked_pixel_data)
2204
+ squared_normalized_image = (masked_pixel_data - mean_image_value) ** 2
2205
+ if mean_image_value > 0:
2206
+ focus_score = numpy.sum(squared_normalized_image) / (
2207
+ numpy.product(masked_pixel_data.shape) * mean_image_value
2208
+ )
2209
+ #
2210
+ # Create a labels matrix that grids the image to the dimensions
2211
+ # of the window size
2212
+ #
2213
+ if dimensions == 2:
2214
+ i, j = numpy.mgrid[0 : shape[0], 0 : shape[1]].astype(float)
2215
+ m, n = (numpy.array(shape) + scale - 1) // scale
2216
+ i = (i * float(m) / float(shape[0])).astype(int)
2217
+ j = (j * float(n) / float(shape[1])).astype(int)
2218
+ grid = i * n + j + 1
2219
+ grid_range = numpy.arange(0, m * n + 1, dtype=numpy.int32)
2220
+ elif dimensions == 3:
2221
+ k, i, j = numpy.mgrid[
2222
+ 0 : shape[0], 0 : shape[1], 0 : shape[2]
2223
+ ].astype(float)
2224
+ o, m, n = (numpy.array(shape) + scale - 1) // scale
2225
+ k = (k * float(o) / float(shape[0])).astype(int)
2226
+ i = (i * float(m) / float(shape[1])).astype(int)
2227
+ j = (j * float(n) / float(shape[2])).astype(int)
2228
+ grid = k * o + i * n + j + 1 # hmm
2229
+ grid_range = numpy.arange(0, m * n * o + 1, dtype=numpy.int32)
2230
+ else:
2231
+ raise ValueError("Image dimensions must be 2 or 3")
2232
+ if image_mask is not None:
2233
+ grid[numpy.logical_not(image_mask)] = 0
2234
+
2235
+ #
2236
+ # Do the math per label
2237
+ #
2238
+ local_means = centrosome.cpmorphology.fixup_scipy_ndimage_result(
2239
+ scipy.ndimage.mean(pixel_data, grid, grid_range)
2240
+ )
2241
+ local_squared_normalized_image = (
2242
+ pixel_data - local_means[grid]
2243
+ ) ** 2
2244
+ #
2245
+ # Compute the sum of local_squared_normalized_image values for each
2246
+ # grid for means > 0. Exclude grid label = 0 because that's masked
2247
+ #
2248
+ grid_mask = (local_means != 0) & ~numpy.isnan(local_means)
2249
+ nz_grid_range = grid_range[grid_mask]
2250
+ if len(nz_grid_range) and nz_grid_range[0] == 0:
2251
+ nz_grid_range = nz_grid_range[1:]
2252
+ local_means = local_means[1:]
2253
+ grid_mask = grid_mask[1:]
2254
+ local_focus_score += [
2255
+ 0
2256
+ ] # assume the worst - that we can't calculate it
2257
+ if len(nz_grid_range):
2258
+ sums = centrosome.cpmorphology.fixup_scipy_ndimage_result(
2259
+ scipy.ndimage.sum(
2260
+ local_squared_normalized_image, grid, nz_grid_range
2261
+ )
2262
+ )
2263
+ pixel_counts = centrosome.cpmorphology.fixup_scipy_ndimage_result(
2264
+ scipy.ndimage.sum(numpy.ones(shape), grid, nz_grid_range)
2265
+ )
2266
+ local_norm_var = sums / (pixel_counts * local_means[grid_mask])
2267
+ local_norm_median = numpy.median(local_norm_var)
2268
+ if numpy.isfinite(local_norm_median) and local_norm_median > 0:
2269
+ local_focus_score[-1] = (
2270
+ numpy.var(local_norm_var) / local_norm_median
2271
+ )
2272
+ return focus_score, scale, local_focus_score
2273
+
2274
+ def get_correlation_for_scale_group(
2275
+ pixel_data: ImageGrayscale,
2276
+ scale_groups: Sequence[int],
2277
+ image_mask: Optional[ImageGrayscaleMask]=None
2278
+ ) -> Dict[int, numpy.float_]:
2279
+ # Compute Haralick's correlation texture for the given scales
2280
+ image_labels = numpy.ones(pixel_data.shape, int)
2281
+ if image_mask is not None:
2282
+ image_labels[~image_mask] = 0
2283
+ scale_measurements = {}
2284
+ for scale in scale_groups:
2285
+ scale_measurements[scale] = get_correlation_for_scale(pixel_data, image_labels, scale)
2286
+ return scale_measurements
2287
+
2288
+ def get_correlation_for_scale(
2289
+ pixel_data: ImageGrayscale,
2290
+ image_labels: NDArray[numpy.int_],
2291
+ scale: int
2292
+ ) -> float:
2293
+ # Compute Haralick's correlation texture for the given scale
2294
+ value = centrosome.haralick.Haralick(pixel_data, image_labels, 0, scale).H3()
2295
+
2296
+ if len(value) != 1 or not numpy.isfinite(value[0]):
2297
+ value = 0.0
2298
+ else:
2299
+ value = float(value)
2300
+ return value
2301
+
2302
+
2303
+ def get_saturation_value(
2304
+ pixel_data: ImageGrayscale,
2305
+ image_mask: Optional[ImageGrayscaleMask]=None
2306
+ ) -> Tuple[
2307
+ float,
2308
+ float
2309
+ ]:
2310
+ if image_mask is not None:
2311
+ pixel_data = pixel_data[image_mask]
2312
+ pixel_count = numpy.product(pixel_data.shape)
2313
+ if pixel_count == 0:
2314
+ percent_maximal = 0
2315
+ percent_minimal = 0
2316
+ else:
2317
+ number_pixels_maximal = numpy.sum(pixel_data == numpy.max(pixel_data))
2318
+ number_pixels_minimal = numpy.sum(pixel_data == numpy.min(pixel_data))
2319
+ percent_maximal = (
2320
+ 100.0 * float(number_pixels_maximal) / float(pixel_count)
2321
+ )
2322
+ percent_minimal = (
2323
+ 100.0 * float(number_pixels_minimal) / float(pixel_count)
2324
+ )
2325
+ return percent_minimal, percent_maximal
2326
+
2327
+
2328
+ def get_intensity_measurement_values(
2329
+ pixels: ImageGrayscale,
2330
+ image_mask: Optional[ImageGrayscaleMask]=None
2331
+ ) -> Tuple[
2332
+ numpy.int_,
2333
+ numpy.float_,
2334
+ numpy.float_,
2335
+ numpy.float_,
2336
+ numpy.float_,
2337
+ numpy.float_,
2338
+ numpy.float_,
2339
+ numpy.float_
2340
+ ]:
2341
+ if image_mask is not None:
2342
+ pixels = pixels[image_mask]
2343
+
2344
+ pixel_count = numpy.product(pixels.shape)
2345
+ if pixel_count == 0:
2346
+ pixel_sum = 0
2347
+ pixel_mean = 0
2348
+ pixel_std = 0
2349
+ pixel_mad = 0
2350
+ pixel_median = 0
2351
+ pixel_min = 0
2352
+ pixel_max = 0
2353
+ else:
2354
+ pixel_sum = numpy.sum(pixels)
2355
+ pixel_mean = pixel_sum / float(pixel_count)
2356
+ pixel_std = numpy.std(pixels)
2357
+ pixel_median = numpy.median(pixels)
2358
+ pixel_mad = numpy.median(numpy.abs(pixels - pixel_median))
2359
+ pixel_min = numpy.min(pixels)
2360
+ pixel_max = numpy.max(pixels)
2361
+ return pixel_count, pixel_sum, pixel_mean, pixel_std, pixel_mad, pixel_median, pixel_min, pixel_max
2362
+
2363
+
2364
+ def get_power_spectrum_measurement_values(
2365
+ pixel_data: ImageGrayscale,
2366
+ image_mask: Optional[ImageGrayscaleMask]=None,
2367
+ dimensions: int = 2
2368
+ ) -> float:
2369
+ if dimensions == 3:
2370
+ # TODO: cannot calculate "radial power spectrum" for volumes: Not implemented.
2371
+ pass
2372
+
2373
+ if image_mask is not None:
2374
+ pixel_data = numpy.array(pixel_data) # make a copy
2375
+ masked_pixels = pixel_data[image_mask]
2376
+ pixel_count = numpy.product(masked_pixels.shape)
2377
+ if pixel_count > 0:
2378
+ pixel_data[~image_mask] = numpy.mean(masked_pixels)
2379
+ else:
2380
+ pixel_data[~image_mask] = 0
2381
+
2382
+ radii, magnitude, power = centrosome.radial_power_spectrum.rps(pixel_data)
2383
+ if sum(magnitude) > 0 and len(numpy.unique(pixel_data)) > 1:
2384
+ valid = magnitude > 0
2385
+ radii = radii[valid].reshape((-1, 1))
2386
+ power = power[valid].reshape((-1, 1))
2387
+ if radii.shape[0] > 1:
2388
+ idx = numpy.isfinite(numpy.log(power))
2389
+ powerslope = scipy.linalg.basic.lstsq(
2390
+ numpy.hstack(
2391
+ (
2392
+ numpy.log(radii)[idx][:, numpy.newaxis],
2393
+ numpy.ones(radii.shape)[idx][:, numpy.newaxis],
2394
+ )
2395
+ ),
2396
+ numpy.log(power)[idx][:, numpy.newaxis],
2397
+ )[0][0]
2398
+ else:
2399
+ powerslope = 0.
2400
+ else:
2401
+ powerslope = 0.
2402
+ return powerslope
2403
+
2404
+
2405
+ def calculate_threshold_for_threshold_group(
2406
+ image_pixel_data: ImageGrayscale = numpy.ones((100, 100)),
2407
+ mask: Optional[ImageGrayscaleMask] = None,
2408
+ algorithm: str = centrosome.threshold.TM_OTSU,
2409
+ object_fraction: float = 0.1,
2410
+ two_class_otsu: bool = True,
2411
+ use_weighted_variance: bool = True,
2412
+ assign_middle_to_foreground: bool = True,
2413
+ ) -> float:
2414
+ if mask is not None:
2415
+ _, global_threshold = centrosome.threshold.get_threshold(
2416
+ algorithm,
2417
+ centrosome.threshold.TM_GLOBAL,
2418
+ image_pixel_data,
2419
+ mask = mask,
2420
+ object_fraction=object_fraction,
2421
+ two_class_otsu=two_class_otsu,
2422
+ use_weighted_variance=use_weighted_variance,
2423
+ assign_middle_to_foreground=assign_middle_to_foreground,
2424
+ )
2425
+ else:
2426
+ _, global_threshold = centrosome.threshold.get_threshold(
2427
+ algorithm,
2428
+ centrosome.threshold.TM_GLOBAL,
2429
+ image_pixel_data,
2430
+ object_fraction=object_fraction,
2431
+ two_class_otsu=two_class_otsu,
2432
+ use_weighted_variance=use_weighted_variance,
2433
+ assign_middle_to_foreground=assign_middle_to_foreground,
2434
+ )
2435
+ return global_threshold
2436
+
2176
2437
  ###############################################################################
2177
2438
  # Measure Image Skeleton
2178
2439
  ###############################################################################
@@ -0,0 +1,302 @@
1
+ import numpy
2
+ from numpy.typing import NDArray
3
+ from typing import Optional, List, Sequence, Annotated, Union, Tuple, Any
4
+ from pydantic import BaseModel, Field, validate_call, ConfigDict
5
+ from cellprofiler_library.types import ImageGrayscale, ImageGrayscaleMask
6
+ from cellprofiler_library.measurement_model import LibraryMeasurements
7
+ from cellprofiler_library.opts.measureimagequality import (
8
+ Feature, ScaledThresholdMethod, TemplateMeasurementFormat
9
+ )
10
+ from cellprofiler_library.functions.measurement import (
11
+ get_focus_score_for_scale_group,
12
+ get_correlation_for_scale_group,
13
+ get_saturation_value,
14
+ get_intensity_measurement_values,
15
+ get_power_spectrum_measurement_values,
16
+ calculate_threshold_for_threshold_group
17
+ )
18
+
19
+ ImageQualityMesVal = Union[
20
+ # image scaling, blur powerslope, saturation percent_minimal|percent_maximal, threshold global_threshold
21
+ float,
22
+ # blur focus_score
23
+ NDArray[numpy.float_],
24
+ # intensity pixel_count
25
+ numpy.int_,
26
+ # blur local_focus_score
27
+ # intensity
28
+ # pixel_sum|pixel_mean|pixel_std|pixel_mad|pixel_median|pixel_min|pixel_max
29
+ numpy.float_,
30
+ # converted stat vals
31
+ str
32
+ ]
33
+ ImageQualityStatistics = List[Tuple[str, ImageQualityMesVal]]
34
+
35
+ class ImageQualityDisplayData(BaseModel):
36
+ model_config = ConfigDict(
37
+ arbitrary_types_allowed=True,
38
+ populate_by_name=True
39
+ )
40
+
41
+ statistics: ImageQualityStatistics
42
+
43
+ class ThresholdConfig(BaseModel):
44
+ algorithm: str
45
+ object_fraction: float = 0.1
46
+ two_class_otsu: bool = True
47
+ use_weighted_variance: bool = True
48
+ assign_middle_to_foreground: bool = True
49
+
50
+ def get_scale_string(self) -> Optional[str]:
51
+ if self.algorithm == ScaledThresholdMethod.OTSU.value:
52
+ scale = "2" if self.two_class_otsu else "3"
53
+ if not self.two_class_otsu:
54
+ scale += "F" if self.assign_middle_to_foreground else "B"
55
+ scale += "W" if self.use_weighted_variance else "S"
56
+ return scale
57
+ elif self.algorithm == ScaledThresholdMethod.MOG.value:
58
+ return str(int(self.object_fraction * 100))
59
+ return None
60
+
61
+ @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
62
+ def measure_image_quality(
63
+ image: Annotated[ImageGrayscale, Field(description="The image to measure.")],
64
+ image_name: Annotated[str, Field(description="The name of the image.")],
65
+ image_mask: Annotated[Optional[ImageGrayscaleMask], Field(description="The mask for the image.")] = None,
66
+ volumetric: Annotated[bool, Field(description="Whether the image is volumetric (3D).")] = False,
67
+ include_image_scalings: Annotated[bool, Field(description="Whether to include image scalings in the measurements.")] = False,
68
+ image_scale_value: Annotated[float, Field(description="The scaling value of the image.")] = numpy.nan,
69
+ check_blur: Annotated[bool, Field(description="Whether to calculate blur metrics.")] = False,
70
+ blur_scales: Annotated[Optional[Sequence[int]], Field(description="List of scales (window sizes) for blur metrics.")] = None,
71
+ check_saturation: Annotated[bool, Field(description="Whether to calculate saturation metrics.")] = False,
72
+ check_intensity: Annotated[bool, Field(description="Whether to calculate intensity metrics.")] = False,
73
+ calculate_threshold: Annotated[bool, Field(description="Whether to calculate threshold metrics.")] = False,
74
+ threshold_groups: Annotated[Optional[List[ThresholdConfig]], Field(description="List of threshold configurations.")] = None,
75
+ return_visualization_data: Annotated[bool, Field(description="Return data for display")] = False,
76
+ ) -> Union[LibraryMeasurements, Tuple[LibraryMeasurements, ImageQualityDisplayData]]:
77
+ """
78
+ Measure image quality metrics.
79
+
80
+ Args:
81
+ image: Input image.
82
+ image_name: Name of the image.
83
+ image_mask: Optional mask for the image.
84
+ volumetric: Whether the image is volumetric (3D).
85
+ include_image_scalings: Whether to record image scaling.
86
+ image_scale_value: The scaling value of the image.
87
+ check_blur: Whether to calculate blur metrics.
88
+ blur_scales: List of scales (window sizes) for blur metrics.
89
+ check_saturation: Whether to calculate saturation metrics.
90
+ check_intensity: Whether to calculate intensity metrics.
91
+ calculate_threshold: Whether to calculate threshold metrics.
92
+ threshold_groups: List of threshold configurations.
93
+
94
+ Returns:
95
+ LibraryMeasurements object containing the measurements.
96
+ """
97
+ measurements = LibraryMeasurements()
98
+ statistics: ImageQualityStatistics = []
99
+
100
+ dimensions = image.ndim
101
+
102
+ feat_stat_name_map = {
103
+ TemplateMeasurementFormat.IQ_SCALING: f"{image_name} scaling",
104
+ TemplateMeasurementFormat.IQ_POWER_SPECTRUM_SLOPE: f"{image_name} {Feature.POWER_SPECTRUM_SLOPE.value}",
105
+ TemplateMeasurementFormat.IQ_PERCENT_MAXIMAL: f"{image_name} maximal",
106
+ TemplateMeasurementFormat.IQ_PERCENT_MINIMAL: f"{image_name} minimal",
107
+ TemplateMeasurementFormat.IQ_TOTAL_AREA: f"{image_name} Total Area",
108
+ TemplateMeasurementFormat.IQ_TOTAL_VOLUME: f"{image_name} Total Volume",
109
+ TemplateMeasurementFormat.IQ_TOTAL_INTENSITY: f"{image_name} Total intensity",
110
+ TemplateMeasurementFormat.IQ_MEAN_INTENSITY: f"{image_name} Mean intensity",
111
+ TemplateMeasurementFormat.IQ_MEDIAN_INTENSITY: f"{image_name} Median intensity",
112
+ TemplateMeasurementFormat.IQ_STD_INTENSITY: f"{image_name} Std intensity",
113
+ TemplateMeasurementFormat.IQ_MAD_INTENSITY: f"{image_name} MAD intensity",
114
+ TemplateMeasurementFormat.IQ_MIN_INTENSITY: f"{image_name} Min intensity",
115
+ TemplateMeasurementFormat.IQ_MAX_INTENSITY: f"{image_name} Max intensity",
116
+ # template stat names
117
+ TemplateMeasurementFormat.IQ_FOCUS_SCORE: f"{image_name} focus score @%d",
118
+ TemplateMeasurementFormat.IQ_LOCAL_FOCUS_SCORE: f"{image_name} local focus score @%d",
119
+ TemplateMeasurementFormat.IQ_CORR: f"{image_name} {Feature.CORRELATION.value} @%d",
120
+ TemplateMeasurementFormat.IQ_THRESHOLD: f"{image_name} %s",
121
+ }
122
+ def add_measurement(
123
+ feature_template: str,
124
+ template_val: str,
125
+ feat_val: ImageQualityMesVal,
126
+ stat_template_val: Optional[Any]=None,
127
+ feat_val_template: Optional[str]=None
128
+ ):
129
+ feature = feature_template % template_val
130
+ measurements.add_image_measurement(feature, feat_val)
131
+ if return_visualization_data:
132
+ stat_name = feat_stat_name_map.get(feature_template, None)
133
+ if stat_name is None:
134
+ return # TODO: 5114 - handle this
135
+ if stat_template_val is not None:
136
+ stat_name = stat_name % stat_template_val
137
+ if feat_val_template is not None:
138
+ feat_val = feat_val_template % feat_val
139
+ statistics.append((stat_name, feat_val))
140
+
141
+ # Image Scalings
142
+ if include_image_scalings:
143
+ add_measurement(TemplateMeasurementFormat.IQ_SCALING, image_name, image_scale_value)
144
+
145
+ # Blur Measurements
146
+ if check_blur and blur_scales is not None:
147
+ # Focus Score
148
+ focus_score, scale, local_focus_score = get_focus_score_for_scale_group(
149
+ blur_scales,
150
+ image,
151
+ dimensions,
152
+ image_mask,
153
+ )
154
+ # Correlation
155
+ scale_measurements = get_correlation_for_scale_group(image, blur_scales, image_mask)
156
+
157
+ # Focus Score
158
+ add_measurement(
159
+ TemplateMeasurementFormat.IQ_FOCUS_SCORE,
160
+ image_name,
161
+ focus_score,
162
+ stat_template_val=blur_scales[-1]
163
+ )
164
+
165
+ for idx, scale in enumerate(blur_scales):
166
+ # Focus Score
167
+ add_measurement(
168
+ TemplateMeasurementFormat.IQ_LOCAL_FOCUS_SCORE,
169
+ f"{image_name}_{scale}",
170
+ local_focus_score[idx],
171
+ stat_template_val=scale,
172
+ )
173
+ # Correlation
174
+ add_measurement(
175
+ TemplateMeasurementFormat.IQ_CORR,
176
+ f"{image_name}_{scale}",
177
+ scale_measurements[scale],
178
+ stat_template_val=scale,
179
+ feat_val_template="%.2f",
180
+ )
181
+
182
+ # Power Spectrum
183
+ if dimensions == 2:
184
+ powerslope = get_power_spectrum_measurement_values(image, image_mask, dimensions)
185
+ add_measurement(
186
+ TemplateMeasurementFormat.IQ_POWER_SPECTRUM_SLOPE,
187
+ image_name,
188
+ powerslope,
189
+ feat_val_template="%.1f",
190
+ )
191
+
192
+ # Saturation Measurements
193
+ if check_saturation:
194
+ percent_minimal, percent_maximal = get_saturation_value(image, image_mask)
195
+
196
+ add_measurement(
197
+ TemplateMeasurementFormat.IQ_PERCENT_MAXIMAL,
198
+ image_name,
199
+ percent_maximal,
200
+ feat_val_template="%.1f",
201
+ )
202
+ add_measurement(
203
+ TemplateMeasurementFormat.IQ_PERCENT_MINIMAL,
204
+ image_name,
205
+ percent_minimal,
206
+ feat_val_template="%.1f",
207
+ )
208
+
209
+ # Intensity Measurements
210
+ if check_intensity:
211
+ (
212
+ pixel_count,
213
+ pixel_sum,
214
+ pixel_mean,
215
+ pixel_std,
216
+ pixel_mad,
217
+ pixel_median,
218
+ pixel_min,
219
+ pixel_max,
220
+ ) = get_intensity_measurement_values(image, image_mask)
221
+
222
+ add_measurement(
223
+ TemplateMeasurementFormat.IQ_TOTAL_VOLUME if volumetric else TemplateMeasurementFormat.IQ_TOTAL_AREA,
224
+ image_name,
225
+ pixel_count,
226
+ feat_val_template="%.2f",
227
+ )
228
+ add_measurement(
229
+ TemplateMeasurementFormat.IQ_TOTAL_INTENSITY,
230
+ image_name,
231
+ pixel_sum,
232
+ feat_val_template="%.2f",
233
+ )
234
+ add_measurement(
235
+ TemplateMeasurementFormat.IQ_MEAN_INTENSITY,
236
+ image_name,
237
+ pixel_mean,
238
+ feat_val_template="%.2f",
239
+ )
240
+ add_measurement(
241
+ TemplateMeasurementFormat.IQ_MEDIAN_INTENSITY,
242
+ image_name,
243
+ pixel_median,
244
+ feat_val_template="%.2f",
245
+ )
246
+ add_measurement(
247
+ TemplateMeasurementFormat.IQ_STD_INTENSITY,
248
+ image_name,
249
+ pixel_std,
250
+ feat_val_template="%.2f",
251
+ )
252
+ add_measurement(
253
+ TemplateMeasurementFormat.IQ_MAD_INTENSITY,
254
+ image_name,
255
+ pixel_mad,
256
+ feat_val_template="%.2f",
257
+ )
258
+ add_measurement(
259
+ TemplateMeasurementFormat.IQ_MAX_INTENSITY,
260
+ image_name,
261
+ pixel_max,
262
+ feat_val_template="%.2f",
263
+ )
264
+ add_measurement(
265
+ TemplateMeasurementFormat.IQ_MIN_INTENSITY,
266
+ image_name,
267
+ pixel_min,
268
+ feat_val_template="%.2f",
269
+ )
270
+
271
+ # Threshold Measurements
272
+ if calculate_threshold and threshold_groups is not None:
273
+ # We need to cast pixel data to float32 for threshold calculations as in original code
274
+ # "pixel_data = image.pixel_data.astype(numpy.float32)"
275
+ pixel_data_float = image.astype(numpy.float32)
276
+
277
+ for config in threshold_groups:
278
+ global_threshold = calculate_threshold_for_threshold_group(
279
+ image_pixel_data=pixel_data_float,
280
+ mask=image_mask,
281
+ algorithm=config.algorithm,
282
+ object_fraction=config.object_fraction,
283
+ two_class_otsu=config.two_class_otsu,
284
+ use_weighted_variance=config.use_weighted_variance,
285
+ assign_middle_to_foreground=config.assign_middle_to_foreground,
286
+ )
287
+
288
+ scale = config.get_scale_string()
289
+ algo = config.algorithm
290
+
291
+ add_measurement(
292
+ TemplateMeasurementFormat.IQ_THRESHOLD,
293
+ f"{algo}_{image_name}_{scale}" if scale else f"{algo}_{image_name}",
294
+ global_threshold,
295
+ stat_template_val=f"{algo}" + (f" {scale}" if scale else "")
296
+ )
297
+
298
+ if return_visualization_data:
299
+ return measurements, ImageQualityDisplayData(
300
+ statistics=statistics,
301
+ )
302
+ return measurements
@@ -15,6 +15,8 @@ from ..opts.threshold import (
15
15
  )
16
16
  from ..types import ImageGrayscale, ImageGrayscaleMask
17
17
 
18
+ # TODO: library cleanup - needs standardizing
19
+ # frontend still uses centrosome
18
20
  @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
19
21
  def threshold(
20
22
  image: Annotated[ImageGrayscale, Field(description="Image to threshold")],
@@ -0,0 +1,89 @@
1
+ from enum import Enum
2
+ from centrosome.threshold import (
3
+ TM_OTSU,
4
+ TM_MOG,
5
+ TM_METHODS,
6
+ )
7
+ from .threshold import OtsuMethod as ThreshOtsuMethod
8
+
9
+ """Root module measurement name"""
10
+ C_IMAGE_QUALITY = "ImageQuality"
11
+
12
+ C_SCALING = "Scaling"
13
+
14
+ class Feature(str, Enum):
15
+ FOCUS_SCORE = "FocusScore"
16
+ LOCAL_FOCUS_SCORE = "LocalFocusScore"
17
+ CORRELATION = "Correlation"
18
+ POWER_SPECTRUM_SLOPE = "PowerLogLogSlope"
19
+ TOTAL_AREA = "TotalArea"
20
+ TOTAL_VOLUME = "TotalVolume"
21
+ TOTAL_INTENSITY = "TotalIntensity"
22
+ MEAN_INTENSITY = "MeanIntensity"
23
+ MEDIAN_INTENSITY = "MedianIntensity"
24
+ STD_INTENSITY = "StdIntensity"
25
+ MAD_INTENSITY = "MADIntensity"
26
+ MAX_INTENSITY = "MaxIntensity"
27
+ MIN_INTENSITY = "MinIntensity"
28
+ PERCENT_MAXIMAL = "PercentMaximal"
29
+ PERCENT_MINIMAL = "PercentMinimal"
30
+ THRESHOLD = "Threshold"
31
+
32
+ class TemplateMeasurementFormat(str):
33
+ """A string subclass for measurement formatting."""
34
+ # IQ = Image Quality
35
+ IQ_SCALING = f"{C_IMAGE_QUALITY}_{C_SCALING}_%s"
36
+ IQ_FOCUS_SCORE = f"{C_IMAGE_QUALITY}_{Feature.FOCUS_SCORE.value}_%s"
37
+ IQ_LOCAL_FOCUS_SCORE = f"{C_IMAGE_QUALITY}_{Feature.LOCAL_FOCUS_SCORE.value}_%s"
38
+ IQ_CORR = f"{C_IMAGE_QUALITY}_{Feature.CORRELATION.value}_%s"
39
+ IQ_POWER_SPECTRUM_SLOPE = f"{C_IMAGE_QUALITY}_{Feature.POWER_SPECTRUM_SLOPE.value}_%s"
40
+ IQ_PERCENT_MAXIMAL = f"{C_IMAGE_QUALITY}_{Feature.PERCENT_MAXIMAL.value}_%s"
41
+ IQ_PERCENT_MINIMAL = f"{C_IMAGE_QUALITY}_{Feature.PERCENT_MINIMAL.value}_%s"
42
+ IQ_TOTAL_AREA = f"{C_IMAGE_QUALITY}_{Feature.TOTAL_AREA.value}_%s"
43
+ IQ_TOTAL_VOLUME = f"{C_IMAGE_QUALITY}_{Feature.TOTAL_VOLUME.value}_%s"
44
+ IQ_TOTAL_INTENSITY = f"{C_IMAGE_QUALITY}_{Feature.TOTAL_INTENSITY.value}_%s"
45
+ IQ_MEAN_INTENSITY = f"{C_IMAGE_QUALITY}_{Feature.MEAN_INTENSITY.value}_%s"
46
+ IQ_MEDIAN_INTENSITY = f"{C_IMAGE_QUALITY}_{Feature.MEDIAN_INTENSITY.value}_%s"
47
+ IQ_STD_INTENSITY = f"{C_IMAGE_QUALITY}_{Feature.STD_INTENSITY.value}_%s"
48
+ IQ_MAD_INTENSITY = f"{C_IMAGE_QUALITY}_{Feature.MAD_INTENSITY.value}_%s"
49
+ IQ_MAX_INTENSITY = f"{C_IMAGE_QUALITY}_{Feature.MAX_INTENSITY.value}_%s"
50
+ IQ_MIN_INTENSITY = f"{C_IMAGE_QUALITY}_{Feature.MIN_INTENSITY.value}_%s"
51
+ IQ_THRESHOLD = f"{C_IMAGE_QUALITY}_{Feature.THRESHOLD.value}%s"
52
+
53
+ class Aggregate(str, Enum):
54
+ MEAN = "Mean"
55
+ MEDIAN = "Median"
56
+ STD = "Std"
57
+ INTENSITY_FEATURES = [
58
+ Feature.TOTAL_INTENSITY,
59
+ Feature.MEAN_INTENSITY,
60
+ Feature.MEDIAN_INTENSITY,
61
+ Feature.STD_INTENSITY,
62
+ Feature.MAD_INTENSITY,
63
+ Feature.MAX_INTENSITY,
64
+ Feature.MIN_INTENSITY,
65
+ ]
66
+ INTENSITY_TEMPLATES = [
67
+ TemplateMeasurementFormat.IQ_TOTAL_INTENSITY,
68
+ TemplateMeasurementFormat.IQ_MEAN_INTENSITY,
69
+ TemplateMeasurementFormat.IQ_MEDIAN_INTENSITY,
70
+ TemplateMeasurementFormat.IQ_STD_INTENSITY,
71
+ TemplateMeasurementFormat.IQ_MAD_INTENSITY,
72
+ TemplateMeasurementFormat.IQ_MAX_INTENSITY,
73
+ TemplateMeasurementFormat.IQ_MIN_INTENSITY,
74
+ ]
75
+ SATURATION_FEATURES = [Feature.PERCENT_MAXIMAL, Feature.PERCENT_MINIMAL]
76
+ SATURATION_TEMPLATES = [TemplateMeasurementFormat.IQ_PERCENT_MAXIMAL, TemplateMeasurementFormat.IQ_PERCENT_MINIMAL]
77
+ AGGREGATES = [Aggregate.MEAN.value, Aggregate.MEDIAN.value, Aggregate.STD.value]
78
+ MEAN_THRESH_ALL_IMAGES = "MeanThresh_AllImages"
79
+ MEDIAN_THRESH_ALL_IMAGES = "MedianThresh_AllImages"
80
+ STD_THRESH_ALL_IMAGES = "StdThresh_AllImages"
81
+
82
+ class ScaledThresholdMethod(str, Enum):
83
+ OTSU = TM_OTSU
84
+ MOG = TM_MOG
85
+ # could just do `from .threshold import OtsuMethod` at the top
86
+ # but we make it explicit here to silence static analysis warnings
87
+ OtsuMethod = ThreshOtsuMethod
88
+ # similar to above
89
+ THRESHOLD_METHODS = TM_METHODS
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellprofiler-library-nightly
3
- Version: 5.0.0.dev592
3
+ Version: 5.0.0.dev610
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>
@@ -41,6 +41,7 @@ cellprofiler_library/modules/_measuregranularity.py
41
41
  cellprofiler_library/modules/_measureimageareaoccupied.py
42
42
  cellprofiler_library/modules/_measureimageintensity.py
43
43
  cellprofiler_library/modules/_measureimageoverlap.py
44
+ cellprofiler_library/modules/_measureimagequality.py
44
45
  cellprofiler_library/modules/_measureimageskeleton.py
45
46
  cellprofiler_library/modules/_measureobjectintensity.py
46
47
  cellprofiler_library/modules/_measureobjectneighbors.py
@@ -85,6 +86,7 @@ cellprofiler_library/opts/measuregranularity.py
85
86
  cellprofiler_library/opts/measureimageareaoccupied.py
86
87
  cellprofiler_library/opts/measureimageintensity.py
87
88
  cellprofiler_library/opts/measureimageoverlap.py
89
+ cellprofiler_library/opts/measureimagequality.py
88
90
  cellprofiler_library/opts/measureimageskeleton.py
89
91
  cellprofiler_library/opts/measureobjectintensity.py
90
92
  cellprofiler_library/opts/measureobjectneighbors.py