cellprofiler-library-nightly 5.0.0.dev466__tar.gz → 5.0.0.dev475__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 (87) hide show
  1. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/PKG-INFO +1 -1
  2. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/_version.py +3 -3
  3. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/image_processing.py +150 -21
  4. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_enhanceedges.py +22 -20
  5. cellprofiler_library_nightly-5.0.0.dev475/cellprofiler_library/modules/_flipandrotate.py +89 -0
  6. cellprofiler_library_nightly-5.0.0.dev475/cellprofiler_library/opts/enhanceedges.py +14 -0
  7. cellprofiler_library_nightly-5.0.0.dev475/cellprofiler_library/opts/flipandrotate.py +29 -0
  8. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/PKG-INFO +1 -1
  9. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/SOURCES.txt +3 -0
  10. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/LICENSE +0 -0
  11. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/README.md +0 -0
  12. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/__init__.py +0 -0
  13. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/__init__.py +0 -0
  14. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/file_processing.py +0 -0
  15. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/measurement.py +0 -0
  16. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/object_processing.py +0 -0
  17. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/segmentation.py +0 -0
  18. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/__init__.py +0 -0
  19. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_closing.py +0 -0
  20. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_colortogray.py +0 -0
  21. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_combineobjects.py +0 -0
  22. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_convertimagetoobjects.py +0 -0
  23. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_convertobjectstoimage.py +0 -0
  24. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_correctilluminationapply.py +0 -0
  25. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_crop.py +0 -0
  26. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_dilateimage.py +0 -0
  27. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_dilateobjects.py +0 -0
  28. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_enhanceorsuppressfeatures.py +0 -0
  29. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_erodeimage.py +0 -0
  30. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_erodeobjects.py +0 -0
  31. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_expandorshrinkobjects.py +0 -0
  32. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_fillobjects.py +0 -0
  33. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_gaussianfilter.py +0 -0
  34. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_graytocolor.py +0 -0
  35. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_identifyprimaryobjects.py +0 -0
  36. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_identifysecondaryobjects.py +0 -0
  37. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_identifytertiaryobjects.py +0 -0
  38. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_imagemath.py +0 -0
  39. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_measureimageoverlap.py +0 -0
  40. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_measureobjectsizeshape.py +0 -0
  41. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_medialaxis.py +0 -0
  42. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_medianfilter.py +0 -0
  43. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_morph.py +0 -0
  44. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_morphologicalskeleton.py +0 -0
  45. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_opening.py +0 -0
  46. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_overlayobjects.py +0 -0
  47. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_overlayoutlines.py +0 -0
  48. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_reducenoise.py +0 -0
  49. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_removeholes.py +0 -0
  50. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_resize.py +0 -0
  51. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_savecroppedobjects.py +0 -0
  52. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_shrinktoobjectcenters.py +0 -0
  53. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_threshold.py +0 -0
  54. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_watershed.py +0 -0
  55. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/__init__.py +0 -0
  56. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/colortogray.py +0 -0
  57. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/convertimagetoobjects.py +0 -0
  58. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/convertobjectstoimage.py +0 -0
  59. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/correctilluminationapply.py +0 -0
  60. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/crop.py +0 -0
  61. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/dilateimage.py +0 -0
  62. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/dilateobjects.py +0 -0
  63. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/enhanceorsuppressfeatures.py +0 -0
  64. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/erodeimage.py +0 -0
  65. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/erodeobjects.py +0 -0
  66. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/graytocolor.py +0 -0
  67. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/identifyprimaryobjects.py +0 -0
  68. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/identifysecondaryobjects.py +0 -0
  69. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/identifytertiaryobjects.py +0 -0
  70. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/imagemath.py +0 -0
  71. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/measureimageoverlap.py +0 -0
  72. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/morph.py +0 -0
  73. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/objectsizeshapefeatures.py +0 -0
  74. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/overlayoutlines.py +0 -0
  75. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/removeholes.py +0 -0
  76. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/resize.py +0 -0
  77. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/shrinktoobjectcenters.py +0 -0
  78. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/structuring_elements.py +0 -0
  79. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/threshold.py +0 -0
  80. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/py.typed +0 -0
  81. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/types.py +0 -0
  82. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/dependency_links.txt +0 -0
  83. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/requires.txt +0 -0
  84. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/top_level.txt +0 -0
  85. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/environment.yml +0 -0
  86. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/pyproject.toml +0 -0
  87. {cellprofiler_library_nightly-5.0.0.dev466 → cellprofiler_library_nightly-5.0.0.dev475}/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.dev466
3
+ Version: 5.0.0.dev475
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.dev466'
32
- __version_tuple__ = version_tuple = (5, 0, 0, 'dev466')
31
+ __version__ = version = '5.0.0.dev475'
32
+ __version_tuple__ = version_tuple = (5, 0, 0, 'dev475')
33
33
 
34
- __commit_id__ = commit_id = 'ge958a4dc2'
34
+ __commit_id__ = commit_id = 'gc4686c345'
@@ -17,7 +17,7 @@ import matplotlib
17
17
  import math
18
18
  from typing import Any, Optional, Tuple, Callable, Union, List, cast, Dict, TypeVar
19
19
  from numpy.typing import NDArray
20
- from cellprofiler_library.types import ImageGrayscale, ImageGrayscaleMask, Image2DColor, Image2DGrayscale, ImageAny, ImageAnyMask, ObjectSegmentation, Image2D, Image2DMask, StructuringElement, ObjectLabelSet, ImageColor, ImageBinaryMask
20
+ from cellprofiler_library.types import ImageGrayscale, ImageGrayscaleMask, Image2DColor, Image2DGrayscale, Image2DGrayscaleMask, ImageAny, ImageAnyMask, ObjectSegmentation, Image2D, Image2DMask, StructuringElement, ObjectLabelSet, ImageColor, ImageBinaryMask
21
21
  from cellprofiler_library.opts import threshold as Threshold
22
22
  from cellprofiler_library.opts.enhanceorsuppressfeatures import SpeckleAccuracy, NeuriteMethod
23
23
  from cellprofiler_library.opts.overlayoutlines import BrightnessMode
@@ -25,8 +25,8 @@ from cellprofiler_library.opts.crop import RemovalMethod
25
25
  from cellprofiler_library.opts.structuring_elements import StructuringElementShape2D, StructuringElementShape3D
26
26
  from cellprofiler_library.opts.resize import ResizingMethod, DimensionMethod, InterpolationMethod
27
27
  from cellprofiler_library.opts.imagemath import Operator
28
-
29
- # TODO: python_latest - remove this if later skimage versions update types
28
+ from cellprofiler_library.opts.flipandrotate import RotationCoordinateAlignmnet
29
+ from cellprofiler_library.opts.enhanceedges import EdgeDirection
30
30
  invert = cast(Callable[[ImageAny], ImageAny], _invert)
31
31
  isscalar = cast(Callable[[Optional[ImageAny]], bool], _isscalar)
32
32
 
@@ -49,30 +49,46 @@ def medial_axis(image):
49
49
  return skimage.morphology.medial_axis(image)
50
50
 
51
51
 
52
- def enhance_edges_sobel(image, mask=None, direction="all"):
53
- if direction.casefold() == "all":
52
+ ###############################################################################
53
+ # EnhanceEdges
54
+ ###############################################################################
55
+
56
+ def enhance_edges_sobel(
57
+ image: Image2DGrayscale,
58
+ mask: Optional[Image2DGrayscaleMask]=None,
59
+ direction: EdgeDirection=EdgeDirection.ALL
60
+ ):
61
+ if direction == EdgeDirection.ALL:
54
62
  output_pixels = centrosome.filter.sobel(image, mask)
55
- elif direction.casefold() == "horizontal":
63
+ elif direction == EdgeDirection.HORIZONTAL:
56
64
  output_pixels = centrosome.filter.hsobel(image, mask)
57
- elif direction.casefold() == "vertical":
65
+ elif direction == EdgeDirection.VERTICAL:
58
66
  output_pixels = centrosome.filter.vsobel(image, mask)
59
67
  else:
60
68
  raise NotImplementedError(f"Unimplemented direction for Sobel: {direction}")
61
69
  return output_pixels
62
70
 
63
71
 
64
- def enhance_edges_log(image, mask=None, sigma=2.0):
72
+ def enhance_edges_log(
73
+ image: Image2DGrayscale,
74
+ mask: Optional[Image2DGrayscaleMask]=None,
75
+ sigma: float=2.0
76
+ ) -> Image2DGrayscale:
65
77
  size = int(sigma * 4) + 1
66
78
  output_pixels = centrosome.filter.laplacian_of_gaussian(image, mask, size, sigma)
67
79
  return output_pixels
68
80
 
69
81
 
70
- def enhance_edges_prewitt(image, mask=None, direction="all"):
71
- if direction.casefold() == "all":
82
+ def enhance_edges_prewitt(
83
+ image: Image2DGrayscale,
84
+ mask: Optional[Image2DGrayscaleMask]=None,
85
+ direction: EdgeDirection=EdgeDirection.ALL
86
+ ) -> Image2DGrayscale:
87
+ if direction == EdgeDirection.ALL:
72
88
  output_pixels = centrosome.filter.prewitt(image, mask)
73
- elif direction.casefold() == "horizontal":
89
+ elif direction == EdgeDirection.HORIZONTAL:
74
90
  output_pixels = centrosome.filter.hprewitt(image, mask)
75
- elif direction.casefold() == "vertical":
91
+ elif direction == EdgeDirection.VERTICAL:
76
92
  output_pixels = centrosome.filter.vprewitt(image, mask)
77
93
  else:
78
94
  raise NotImplementedError(f"Unimplemented direction for Prewitt: {direction}")
@@ -80,15 +96,15 @@ def enhance_edges_prewitt(image, mask=None, direction="all"):
80
96
 
81
97
 
82
98
  def enhance_edges_canny(
83
- image,
84
- mask=None,
85
- auto_threshold=True,
86
- auto_low_threshold=True,
87
- sigma=1.0,
88
- low_threshold=0.1,
89
- manual_threshold=0.2,
90
- threshold_adjustment_factor=1.0,
91
- ):
99
+ image: Image2DGrayscale,
100
+ mask: Optional[Image2DGrayscaleMask] = None,
101
+ auto_threshold: bool = True,
102
+ auto_low_threshold: bool = True,
103
+ sigma: float = 1.0,
104
+ low_threshold: float = 0.1,
105
+ manual_threshold: float = 0.2,
106
+ threshold_adjustment_factor: float = 1.0,
107
+ ) -> Image2DGrayscale:
92
108
 
93
109
  if auto_threshold or auto_low_threshold:
94
110
  sobel_image = centrosome.filter.sobel(image)
@@ -104,6 +120,26 @@ def enhance_edges_canny(
104
120
  output_pixels = centrosome.filter.canny(image, mask, sigma, low_th, high_th)
105
121
  return output_pixels
106
122
 
123
+ def stretched_rgb_from_components(
124
+ r: Image2DGrayscale,
125
+ g: Optional[Image2DGrayscale]=None,
126
+ b: Optional[Image2DGrayscale]=None
127
+ ):
128
+ if g:
129
+ assert r.shape == g.shape
130
+ if b:
131
+ assert r.shape == b.shape
132
+
133
+ color_image = numpy.zeros((r.shape[0], r.shape[1], 3))
134
+ color_image[:, :, 0] = centrosome.filter.stretch(r)
135
+
136
+ if g:
137
+ color_image[:, :, 1] = centrosome.filter.stretch(g)
138
+ if b:
139
+ color_image[:, :, 2] = centrosome.filter.stretch(b)
140
+
141
+ return color_image
142
+
107
143
 
108
144
  def morphology_closing(image, structuring_element=skimage.morphology.disk(1)):
109
145
  if structuring_element.ndim == 3 and image.ndim == 2:
@@ -1939,3 +1975,96 @@ def gray_to_stacked_color(
1939
1975
  source_channels = pixel_data_arr
1940
1976
  rgb_pixel_data = numpy.dstack(source_channels)
1941
1977
  return rgb_pixel_data
1978
+
1979
+
1980
+ ################################################################################
1981
+ # FlipAndRotate
1982
+ ################################################################################
1983
+
1984
+ def flip_image_left_to_right(pixel_data: Image2D) -> NDArray[numpy.int_]:
1985
+ i, j = numpy.mgrid[
1986
+ 0 : pixel_data.shape[0], pixel_data.shape[1] - 1 : -1 : -1
1987
+ ]
1988
+ return i, j
1989
+
1990
+ def flip_image_top_to_bottom(pixel_data: Image2D) -> NDArray[numpy.int_]:
1991
+ i, j = numpy.mgrid[
1992
+ pixel_data.shape[0] - 1 : -1 : -1, 0 : pixel_data.shape[1]
1993
+ ]
1994
+ return i, j
1995
+
1996
+ def flip_image_both(pixel_data: Image2D) -> NDArray[numpy.int_]:
1997
+ i, j = numpy.mgrid[
1998
+ pixel_data.shape[0] - 1 : -1 : -1, pixel_data.shape[1] - 1 : -1 : -1
1999
+ ]
2000
+ return i, j
2001
+
2002
+
2003
+ def rotate_image_angle(pixel_data: Image2D, mask: Image2DMask, rotate_angle: float, wants_crop: bool) -> Tuple[Image2D, Image2DMask, Optional[Image2DMask]]:
2004
+ angle = rotate_angle
2005
+ mask = scipy.ndimage.rotate(mask.astype(float), angle, reshape=True) > 0.50
2006
+ crop = (
2007
+ scipy.ndimage.rotate(
2008
+ numpy.ones(pixel_data.shape[:2]), angle, reshape=True
2009
+ )
2010
+ > 0.50
2011
+ )
2012
+ mask = mask & crop
2013
+ pixel_data = scipy.ndimage.rotate(pixel_data, angle, reshape=True)
2014
+ if wants_crop:
2015
+ #
2016
+ # We want to find the largest rectangle that fits inside
2017
+ # the crop. The cumulative sum in the i and j direction gives
2018
+ # the length of the rectangle in each direction and
2019
+ # multiplying them gives you the area.
2020
+ #
2021
+ # The left and right halves are symmetric, so we compute
2022
+ # on just two of the quadrants.
2023
+ #
2024
+ half = (numpy.array(crop.shape) / 2).astype(int)
2025
+ #
2026
+ # Operate on the lower right
2027
+ #
2028
+ quartercrop = crop[half[0] :, half[1] :]
2029
+ ci = numpy.cumsum(quartercrop, 0)
2030
+ cj = numpy.cumsum(quartercrop, 1)
2031
+ carea_d = ci * cj
2032
+ carea_d[quartercrop == 0] = 0
2033
+ #
2034
+ # Operate on the upper right by flipping I
2035
+ #
2036
+ quartercrop = crop[crop.shape[0] - half[0] - 1 :: -1, half[1] :]
2037
+ ci = numpy.cumsum(quartercrop, 0)
2038
+ cj = numpy.cumsum(quartercrop, 1)
2039
+ carea_u = ci * cj
2040
+ carea_u[quartercrop == 0] = 0
2041
+ carea = carea_d + carea_u
2042
+ max_carea = numpy.max(carea)
2043
+ max_area = numpy.argwhere(carea == max_carea)[0] + half
2044
+ min_i = max(crop.shape[0] - max_area[0] - 1, 0)
2045
+ max_i = max_area[0] + 1
2046
+ min_j = max(crop.shape[1] - max_area[1] - 1, 0)
2047
+ max_j = max_area[1] + 1
2048
+ ii = numpy.index_exp[min_i:max_i, min_j:max_j]
2049
+ crop = numpy.zeros(pixel_data.shape, bool)
2050
+ crop[ii] = True
2051
+ mask = mask[ii]
2052
+ pixel_data = pixel_data[ii]
2053
+ else:
2054
+ crop = None
2055
+ return pixel_data, mask, crop
2056
+
2057
+
2058
+ def rotate_image_coordinates(pixel_data: Image2D, mask: Image2DMask, rotate_point_1: Tuple[float, float], rotate_point_2: Tuple[float, float], rotate_coordinate_alignment: RotationCoordinateAlignmnet) -> float:
2059
+ xdiff = rotate_point_2[0] - rotate_point_1[0]
2060
+ ydiff = rotate_point_2[1] - rotate_point_1[1]
2061
+
2062
+ if rotate_coordinate_alignment == RotationCoordinateAlignmnet.VERTICALLY:
2063
+ angle = -numpy.arctan2(ydiff, xdiff) * 180.0 / numpy.pi
2064
+ elif rotate_coordinate_alignment == RotationCoordinateAlignmnet.HORIZONTALLY:
2065
+ angle = numpy.arctan2(xdiff, ydiff) * 180.0 / numpy.pi
2066
+ else:
2067
+ raise NotImplementedError(
2068
+ "Unknown axis: %s" % rotate_coordinate_alignment.value
2069
+ )
2070
+ return angle
@@ -2,28 +2,30 @@ import warnings
2
2
 
3
3
  import numpy
4
4
  import centrosome
5
-
5
+ from pydantic import Field, validate_call, ConfigDict
6
+ from typing import Annotated, Optional
6
7
  from ..functions.image_processing import (
7
8
  enhance_edges_sobel,
8
9
  enhance_edges_log,
9
10
  enhance_edges_prewitt,
10
11
  enhance_edges_canny,
11
12
  )
13
+ from ..opts.enhanceedges import EdgeFindingMethod, EdgeDirection
14
+ from ..types import Image2DGrayscale, Image2DGrayscaleMask
12
15
 
13
-
16
+ @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
14
17
  def enhanceedges(
15
- image,
16
- mask=None,
17
- method="sobel",
18
- automatic_threshold=True,
19
- direction="all",
20
- automatic_gaussian=True,
21
- sigma=10,
22
- manual_threshold=0.2,
23
- threshold_adjustment_factor=1.0,
24
- automatic_low_threshold=True,
25
- low_threshold=0.1,
26
- ):
18
+ image: Annotated[Image2DGrayscale, Field(description="Input image")],
19
+ mask: Annotated[Optional[Image2DGrayscaleMask], Field(description="Mask of the input image")] = None,
20
+ method: Annotated[EdgeFindingMethod, Field(description="Edge finding method")] = EdgeFindingMethod.SOBEL,
21
+ automatic_threshold: Annotated[bool, Field(description="Automatically calculate the threshold?")] = True,
22
+ direction: Annotated[EdgeDirection, Field(description="Select edge direction to enhance")] = EdgeDirection.ALL,
23
+ sigma: Annotated[int, Field(description="Gaussian's sigma value")] = 10,
24
+ manual_threshold: Annotated[float, Field(description="Absolute threshold")] = 0.2,
25
+ threshold_adjustment_factor: Annotated[float, Field(description="Threshold adjustment factor")] = 1.0,
26
+ automatic_low_threshold: Annotated[bool, Field(description="Automatically calculate the low / soft threshold cutoff for the Canny method?")] = True,
27
+ low_threshold: Annotated[float, Field(description="Low threshold value")] = 0.1,
28
+ ) -> Image2DGrayscale:
27
29
  """EnhanceEdges module
28
30
 
29
31
  Parameters
@@ -64,13 +66,13 @@ def enhanceedges(
64
66
  if mask is None:
65
67
  mask = numpy.ones(image.shape, bool)
66
68
 
67
- if method.casefold() == "sobel":
69
+ if method == EdgeFindingMethod.SOBEL:
68
70
  output_pixels = enhance_edges_sobel(image, mask, direction)
69
- elif method.casefold() == "log":
71
+ elif method == EdgeFindingMethod.LOG:
70
72
  output_pixels = enhance_edges_log(image, mask, sigma)
71
- elif method.casefold() == "prewitt":
73
+ elif method == EdgeFindingMethod.PREWITT:
72
74
  output_pixels = enhance_edges_prewitt(image, mask, direction)
73
- elif method.casefold() == "canny":
75
+ elif method == EdgeFindingMethod.CANNY:
74
76
  output_pixels = enhance_edges_canny(
75
77
  image,
76
78
  mask,
@@ -81,9 +83,9 @@ def enhanceedges(
81
83
  manual_threshold=manual_threshold,
82
84
  threshold_adjustment_factor=threshold_adjustment_factor,
83
85
  )
84
- elif method.casefold() == "roberts":
86
+ elif method == EdgeFindingMethod.ROBERTS:
85
87
  output_pixels = centrosome.filter.roberts(image, mask)
86
- elif method.casefold() == "kirsch":
88
+ elif method == EdgeFindingMethod.KIRSCH:
87
89
  output_pixels = centrosome.kirsch.kirsch(image)
88
90
  else:
89
91
  raise NotImplementedError(f"{method} edge detection method is not implemented.")
@@ -0,0 +1,89 @@
1
+ import numpy
2
+ from pydantic import Field, validate_call, ConfigDict
3
+ from typing import Annotated, Optional, Tuple, Dict, Callable
4
+ from numpy.typing import NDArray
5
+ from cellprofiler_library.functions.image_processing import flip_image_both, flip_image_left_to_right, flip_image_top_to_bottom, rotate_image_angle, rotate_image_coordinates
6
+ from cellprofiler_library.types import Image2D, Image2DMask
7
+ from cellprofiler_library.opts.flipandrotate import FlipDirection, RotateMethod, RotationCoordinateAlignmnet
8
+
9
+ @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
10
+ def flip_and_rotate(
11
+ pixel_data: Annotated[Image2D, Field(description="Pixel data of image to be flipped and/or rotated")],
12
+ mask: Annotated[Image2DMask, Field(description="Mask of the image to be flipped and/or rotated")],
13
+ flip_choice: Annotated[FlipDirection, Field(description="Direction to flip the image")],
14
+ rotate_choice: Annotated[RotateMethod, Field(description="Rotation method")],
15
+ rotate_angle: Annotated[Optional[float], Field(description="Angle to rotate the image")],
16
+ rotate_point_1: Annotated[Optional[Tuple[float, float]], Field(description="Point to rotate the image around")],
17
+ rotate_point_2: Annotated[Optional[Tuple[float, float]], Field(description="Second point to rotate the image around")],
18
+ rotate_coordinate_alignment: Annotated[Optional[RotationCoordinateAlignmnet], Field(description="Alignment of the rotated points. The points you select will be aligned horizontally or vertically after the rotation is complete.")],
19
+ wants_crop: Annotated[bool, Field(description="Whether to crop the image")],
20
+ ) -> Tuple[Image2D, Image2DMask, Optional[Image2DMask], float]:
21
+ #
22
+ # Perform flip
23
+ #
24
+ pixel_data, mask = flip_image(pixel_data, mask, flip_choice)
25
+
26
+ #
27
+ # Perform rotation
28
+ #
29
+ pixel_data, mask, crop, angle = rotate_image(pixel_data, mask, rotate_choice, rotate_angle, rotate_point_1, rotate_point_2, rotate_coordinate_alignment, wants_crop)
30
+
31
+ return pixel_data, mask, crop, angle
32
+
33
+
34
+ def flip_image(
35
+ pixel_data: Image2D,
36
+ mask: Image2DMask,
37
+ flip_choice: FlipDirection
38
+ ) -> Tuple[Image2D, Image2DMask]:
39
+ flip_dispatch: Dict[FlipDirection, Callable[[Image2D], NDArray[numpy.int_]]] = {
40
+ FlipDirection.LEFT_TO_RIGHT: flip_image_left_to_right,
41
+ FlipDirection.TOP_TO_BOTTOM: flip_image_top_to_bottom,
42
+ FlipDirection.BOTH: flip_image_both,
43
+ }
44
+ if flip_choice != FlipDirection.NONE:
45
+ if flip_choice in flip_dispatch.keys():
46
+ i, j = flip_dispatch[flip_choice](pixel_data)
47
+ else:
48
+ raise NotImplementedError(
49
+ "Unknown flipping operation: %s" % flip_choice.value
50
+ )
51
+ mask = mask[i, j]
52
+ if pixel_data.ndim == 2:
53
+ pixel_data = pixel_data[i, j]
54
+ else:
55
+ pixel_data = pixel_data[i, j, :]
56
+ return pixel_data, mask
57
+
58
+
59
+ def rotate_image(
60
+ pixel_data: Image2D,
61
+ mask: Image2DMask,
62
+ rotate_choice: RotateMethod,
63
+ rotate_angle: Optional[float],
64
+ rotate_point_1: Optional[Tuple[float, float]],
65
+ rotate_point_2: Optional[Tuple[float, float]],
66
+ rotate_coordinate_alignment: Optional[RotationCoordinateAlignmnet],
67
+ wants_crop: bool,
68
+ ) -> Tuple[Image2D, Image2DMask, Optional[Image2DMask], float]:
69
+ if rotate_choice != RotateMethod.NONE:
70
+ if rotate_choice == RotateMethod.ANGLE:
71
+ assert rotate_angle is not None, "rotate_angle must be provided for rotate_choice == RotateMethod.ANGLE"
72
+ angle = rotate_angle
73
+ elif rotate_choice == RotateMethod.COORDINATES:
74
+ assert rotate_point_1 is not None, "rotate_point_1 must be provided for rotate_choice == RotateMethod.COORDINATES"
75
+ assert rotate_point_2 is not None, "rotate_point_2 must be provided for rotate_choice == RotateMethod.COORDINATES"
76
+ assert rotate_coordinate_alignment is not None, "rotate_coordinate_alignment must be provided for rotate_choice == RotateMethod.COORDINATES"
77
+ angle = rotate_image_coordinates(pixel_data, mask, rotate_point_1, rotate_point_2, rotate_coordinate_alignment)
78
+
79
+ else:
80
+ raise NotImplementedError(
81
+ "Unknown rotation method: %s" % rotate_choice.value
82
+ )
83
+ # rangle = angle * numpy.pi / 180.0
84
+ pixel_data, mask, crop = rotate_image_angle(pixel_data, mask, angle, wants_crop)
85
+
86
+ else:
87
+ crop = None
88
+ angle = 0.0
89
+ return pixel_data, mask, crop, angle
@@ -0,0 +1,14 @@
1
+ from enum import Enum
2
+
3
+ class EdgeFindingMethod(str, Enum):
4
+ SOBEL = "Sobel"
5
+ PREWITT = "Prewitt"
6
+ ROBERTS = "Roberts"
7
+ LOG = "Log"
8
+ CANNY = "Canny"
9
+ KIRSCH = "Kirsch"
10
+
11
+ class EdgeDirection(str, Enum):
12
+ ALL = "All"
13
+ HORIZONTAL = "Horizontal"
14
+ VERTICAL = "Vertical"
@@ -0,0 +1,29 @@
1
+ from enum import Enum
2
+
3
+ class FlipDirection(str, Enum):
4
+ NONE = "Do not flip"
5
+ LEFT_TO_RIGHT = "Left to right"
6
+ TOP_TO_BOTTOM = "Top to bottom"
7
+ BOTH = "Left to right and top to bottom"
8
+
9
+ class RotateMethod(str, Enum):
10
+ NONE = "Do not rotate"
11
+ ANGLE = "Enter angle"
12
+ COORDINATES = "Enter coordinates"
13
+
14
+ class RotationCoordinateAlignmnet(str, Enum):
15
+ HORIZONTALLY = "Horizontally"
16
+ VERTICALLY = "Vertically"
17
+
18
+ D_ANGLE = "angle"
19
+
20
+ """Rotation measurement category"""
21
+ M_ROTATION_CATEGORY = "Rotation"
22
+ """Rotation measurement format (+ image name)"""
23
+ M_ROTATION_F = "%s_%%s" % M_ROTATION_CATEGORY
24
+
25
+ FLIP_ALL = [FlipDirection.NONE, FlipDirection.LEFT_TO_RIGHT, FlipDirection.TOP_TO_BOTTOM, FlipDirection.BOTH]
26
+
27
+ ROTATE_ALL = [RotateMethod.NONE, RotateMethod.ANGLE, RotateMethod.COORDINATES]
28
+
29
+ C_ALL = [RotationCoordinateAlignmnet.HORIZONTALLY, RotationCoordinateAlignmnet.VERTICALLY]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellprofiler-library-nightly
3
- Version: 5.0.0.dev466
3
+ Version: 5.0.0.dev475
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,6 +28,7 @@ cellprofiler_library/modules/_erodeimage.py
28
28
  cellprofiler_library/modules/_erodeobjects.py
29
29
  cellprofiler_library/modules/_expandorshrinkobjects.py
30
30
  cellprofiler_library/modules/_fillobjects.py
31
+ cellprofiler_library/modules/_flipandrotate.py
31
32
  cellprofiler_library/modules/_gaussianfilter.py
32
33
  cellprofiler_library/modules/_graytocolor.py
33
34
  cellprofiler_library/modules/_identifyprimaryobjects.py
@@ -58,9 +59,11 @@ cellprofiler_library/opts/correctilluminationapply.py
58
59
  cellprofiler_library/opts/crop.py
59
60
  cellprofiler_library/opts/dilateimage.py
60
61
  cellprofiler_library/opts/dilateobjects.py
62
+ cellprofiler_library/opts/enhanceedges.py
61
63
  cellprofiler_library/opts/enhanceorsuppressfeatures.py
62
64
  cellprofiler_library/opts/erodeimage.py
63
65
  cellprofiler_library/opts/erodeobjects.py
66
+ cellprofiler_library/opts/flipandrotate.py
64
67
  cellprofiler_library/opts/graytocolor.py
65
68
  cellprofiler_library/opts/identifyprimaryobjects.py
66
69
  cellprofiler_library/opts/identifysecondaryobjects.py