cellprofiler-library-nightly 5.0.0.dev462__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.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/PKG-INFO +1 -1
  2. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/_version.py +3 -3
  3. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/image_processing.py +235 -21
  4. {cellprofiler_library_nightly-5.0.0.dev462 → 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/modules/_graytocolor.py +58 -0
  7. cellprofiler_library_nightly-5.0.0.dev475/cellprofiler_library/opts/enhanceedges.py +14 -0
  8. cellprofiler_library_nightly-5.0.0.dev475/cellprofiler_library/opts/flipandrotate.py +29 -0
  9. cellprofiler_library_nightly-5.0.0.dev475/cellprofiler_library/opts/graytocolor.py +20 -0
  10. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/PKG-INFO +1 -1
  11. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/SOURCES.txt +5 -0
  12. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/LICENSE +0 -0
  13. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/README.md +0 -0
  14. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/__init__.py +0 -0
  15. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/__init__.py +0 -0
  16. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/file_processing.py +0 -0
  17. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/measurement.py +0 -0
  18. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/object_processing.py +0 -0
  19. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/functions/segmentation.py +0 -0
  20. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/__init__.py +0 -0
  21. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_closing.py +0 -0
  22. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_colortogray.py +0 -0
  23. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_combineobjects.py +0 -0
  24. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_convertimagetoobjects.py +0 -0
  25. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_convertobjectstoimage.py +0 -0
  26. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_correctilluminationapply.py +0 -0
  27. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_crop.py +0 -0
  28. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_dilateimage.py +0 -0
  29. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_dilateobjects.py +0 -0
  30. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_enhanceorsuppressfeatures.py +0 -0
  31. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_erodeimage.py +0 -0
  32. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_erodeobjects.py +0 -0
  33. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_expandorshrinkobjects.py +0 -0
  34. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_fillobjects.py +0 -0
  35. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_gaussianfilter.py +0 -0
  36. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_identifyprimaryobjects.py +0 -0
  37. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_identifysecondaryobjects.py +0 -0
  38. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_identifytertiaryobjects.py +0 -0
  39. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_imagemath.py +0 -0
  40. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_measureimageoverlap.py +0 -0
  41. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_measureobjectsizeshape.py +0 -0
  42. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_medialaxis.py +0 -0
  43. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_medianfilter.py +0 -0
  44. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_morph.py +0 -0
  45. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_morphologicalskeleton.py +0 -0
  46. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_opening.py +0 -0
  47. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_overlayobjects.py +0 -0
  48. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_overlayoutlines.py +0 -0
  49. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_reducenoise.py +0 -0
  50. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_removeholes.py +0 -0
  51. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_resize.py +0 -0
  52. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_savecroppedobjects.py +0 -0
  53. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_shrinktoobjectcenters.py +0 -0
  54. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_threshold.py +0 -0
  55. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/modules/_watershed.py +0 -0
  56. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/__init__.py +0 -0
  57. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/colortogray.py +0 -0
  58. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/convertimagetoobjects.py +0 -0
  59. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/convertobjectstoimage.py +0 -0
  60. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/correctilluminationapply.py +0 -0
  61. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/crop.py +0 -0
  62. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/dilateimage.py +0 -0
  63. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/dilateobjects.py +0 -0
  64. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/enhanceorsuppressfeatures.py +0 -0
  65. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/erodeimage.py +0 -0
  66. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/erodeobjects.py +0 -0
  67. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/identifyprimaryobjects.py +0 -0
  68. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/identifysecondaryobjects.py +0 -0
  69. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/identifytertiaryobjects.py +0 -0
  70. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/imagemath.py +0 -0
  71. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/measureimageoverlap.py +0 -0
  72. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/morph.py +0 -0
  73. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/objectsizeshapefeatures.py +0 -0
  74. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/overlayoutlines.py +0 -0
  75. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/removeholes.py +0 -0
  76. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/resize.py +0 -0
  77. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/shrinktoobjectcenters.py +0 -0
  78. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/structuring_elements.py +0 -0
  79. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/opts/threshold.py +0 -0
  80. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/py.typed +0 -0
  81. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library/types.py +0 -0
  82. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/dependency_links.txt +0 -0
  83. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/requires.txt +0 -0
  84. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/cellprofiler_library_nightly.egg-info/top_level.txt +0 -0
  85. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/environment.yml +0 -0
  86. {cellprofiler_library_nightly-5.0.0.dev462 → cellprofiler_library_nightly-5.0.0.dev475}/pyproject.toml +0 -0
  87. {cellprofiler_library_nightly-5.0.0.dev462 → 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.dev462
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.dev462'
32
- __version_tuple__ = version_tuple = (5, 0, 0, 'dev462')
31
+ __version__ = version = '5.0.0.dev475'
32
+ __version_tuple__ = version_tuple = (5, 0, 0, 'dev475')
33
33
 
34
- __commit_id__ = commit_id = 'g8dcb1b2d8'
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:
@@ -1854,3 +1890,181 @@ def imagemath_apply_unary_operation(
1854
1890
  "The operation %s has not been implemented" % opval
1855
1891
  )
1856
1892
  return output_pixel_data, output_mask
1893
+
1894
+
1895
+ ###############################################################################
1896
+ # GrayToColor
1897
+ ###############################################################################
1898
+
1899
+ def gray_to_rgb(
1900
+ pixel_data_arr: List[Optional[Image2DGrayscale]],
1901
+ adjustment_factor_array: List[float],
1902
+ intensities: List[Tuple[float, ...]]=[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)],
1903
+ wants_rescale: bool=True,
1904
+ ) -> Image2DColor:
1905
+ assert(len(pixel_data_arr) == len(adjustment_factor_array)), f"pixel_data_arr and adjustment_factor_array must be the same length. pixel_data_arr has {len(pixel_data_arr)} elements, adjustment_factor_array has {len(adjustment_factor_array)} elements."
1906
+ assert(len(pixel_data_arr) == len(intensities)), f"pixel_data_arr and intensities must be the same length. pixel_data_arr has {len(pixel_data_arr)} elements, intensities has {len(intensities)} elements."
1907
+
1908
+ parent_image = None
1909
+ rgb_pixel_data = None
1910
+ for pixel_data, adjustment_factor, intensity_triplet in zip(pixel_data_arr, adjustment_factor_array, intensities):
1911
+ if pixel_data is None:
1912
+ continue
1913
+ multiplier = numpy.array(intensity_triplet) * adjustment_factor
1914
+ if wants_rescale:
1915
+ pixel_data = pixel_data /numpy.max(pixel_data)
1916
+ if parent_image is not None:
1917
+ if parent_image.shape != pixel_data.shape:
1918
+ raise ValueError(
1919
+ "The input images have different sizes (%s vs %s)"
1920
+ % (
1921
+ parent_image.shape,
1922
+ pixel_data.shape,
1923
+ )
1924
+ )
1925
+ rgb_pixel_data += numpy.dstack([pixel_data] * 3) * multiplier
1926
+ else:
1927
+ parent_image = pixel_data
1928
+ rgb_pixel_data = numpy.dstack([pixel_data] * 3) * multiplier
1929
+ return rgb_pixel_data
1930
+
1931
+ def gray_to_cmyk(*args, **kwargs):
1932
+ # gray to cmyk has the same implementation as gray to rgb but with different intensities
1933
+ return gray_to_rgb(*args, **kwargs)
1934
+
1935
+
1936
+ def gray_to_composite_color(
1937
+ pixel_data_arr: List[Optional[Image2DGrayscale]],
1938
+ color_array: List[Tuple[int, int, int]],
1939
+ weight_array: List[float],
1940
+ wants_rescale: bool,
1941
+ ) -> Image2DColor:
1942
+ source_channels = pixel_data_arr
1943
+ parent_image = pixel_data_arr[0]
1944
+ for idx, pd in enumerate(source_channels):
1945
+ if pd is None:
1946
+ continue
1947
+ if pd.shape != source_channels[0].shape:
1948
+ raise ValueError(
1949
+ "The input images have different sizes (%s vs %s)"
1950
+ % (
1951
+ source_channels[0].shape,
1952
+ pd.shape,
1953
+ )
1954
+ )
1955
+
1956
+ colors: List[NDArray[numpy.float32]] = []
1957
+ pixel_data = parent_image
1958
+ if wants_rescale:
1959
+ pixel_data = pixel_data / numpy.max(pixel_data)
1960
+ for color_tuple, weight in zip(color_array, weight_array):
1961
+ color = (weight * numpy.array(color_tuple).astype(pixel_data.dtype) / 255)
1962
+ colors += [color[numpy.newaxis, numpy.newaxis, :]]
1963
+ rgb_pixel_data = pixel_data[:, :, numpy.newaxis] * colors[0]
1964
+ for image, color in zip(source_channels[1:], colors[1:]):
1965
+ if wants_rescale:
1966
+ image = image / numpy.max(image)
1967
+ rgb_pixel_data = rgb_pixel_data + image[:, :, numpy.newaxis] * color
1968
+
1969
+ return rgb_pixel_data
1970
+
1971
+
1972
+ def gray_to_stacked_color(
1973
+ pixel_data_arr: List[Optional[Image2DGrayscale]]
1974
+ ) -> Image2DColor:
1975
+ source_channels = pixel_data_arr
1976
+ rgb_pixel_data = numpy.dstack(source_channels)
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,58 @@
1
+ import numpy
2
+ from numpy.typing import NDArray
3
+ from typing import List, Tuple, Optional
4
+ from pydantic import validate_call, ConfigDict
5
+ from cellprofiler_library.opts.graytocolor import Scheme
6
+ from cellprofiler_library.types import Image2DGrayscale, Image2DColor
7
+ from cellprofiler_library.functions.image_processing import gray_to_rgb, gray_to_cmyk, gray_to_composite_color, gray_to_stacked_color
8
+
9
+ @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
10
+ def gray_to_color(
11
+ pixel_data_arr: List[Optional[Image2DGrayscale]],
12
+ scheme: Scheme,
13
+ color_array: Optional[List[Tuple[int, int, int]]] = None,
14
+ weight_array: Optional[List[float]] = None,
15
+ adjustment_factor_array: Optional[List[float]] = None,
16
+ intensities: List[Tuple[float, ...]]=[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)],
17
+ wants_rescale: bool=True,
18
+ ) -> Image2DColor:
19
+ rgb_pixel_data = None
20
+ if scheme == Scheme.RGB:
21
+ assert adjustment_factor_array is not None, "adjustment_factor_array must be provided for RGB mode"
22
+ assert intensities is not None, "intensities must be provided for RGB mode"
23
+ rgb_pixel_data = gray_to_rgb(
24
+ pixel_data_arr = pixel_data_arr,
25
+ adjustment_factor_array = adjustment_factor_array,
26
+ intensities = intensities,
27
+ wants_rescale = wants_rescale,
28
+ )
29
+ elif scheme == Scheme.CMYK:
30
+ assert adjustment_factor_array is not None, "adjustment_factor_array must be provided for CMYK mode"
31
+ assert intensities is not None, "intensities must be provided for CMYK mode"
32
+ rgb_pixel_data = gray_to_cmyk(
33
+ pixel_data_arr = pixel_data_arr,
34
+ adjustment_factor_array = adjustment_factor_array,
35
+ intensities = intensities,
36
+ wants_rescale = wants_rescale,
37
+ )
38
+ elif scheme == Scheme.COMPOSITE:
39
+ assert color_array is not None, "color_array must be provided for composite mode"
40
+ assert weight_array is not None, "weight_array must be provided for composite mode"
41
+ rgb_pixel_data = gray_to_composite_color(
42
+ pixel_data_arr = pixel_data_arr,
43
+ color_array = color_array,
44
+ weight_array = weight_array,
45
+ wants_rescale = wants_rescale,
46
+ )
47
+ elif scheme == Scheme.STACK:
48
+ assert pixel_data_arr is not None, "pixel_data_arr must be provided for stack mode"
49
+ rgb_pixel_data = gray_to_stacked_color(
50
+ pixel_data_arr = pixel_data_arr,
51
+ )
52
+ else:
53
+ raise ValueError(f"Unimplemented scheme: {scheme}")
54
+ if scheme.value != Scheme.STACK and wants_rescale:
55
+ # If we rescaled, clip values that went out of range after multiplication
56
+ rgb_pixel_data[rgb_pixel_data > 1] = 1
57
+ return rgb_pixel_data
58
+
@@ -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]
@@ -0,0 +1,20 @@
1
+ from enum import Enum
2
+
3
+ class Scheme(str, Enum):
4
+ RGB = "RGB"
5
+ CMYK = "CMYK"
6
+ STACK = "Stack"
7
+ COMPOSITE = "Composite"
8
+ LEAVE_THIS_BLACK = "Leave this black"
9
+
10
+ DEFAULT_COLORS = [
11
+ "#%02x%02x%02x" % color
12
+ for color in (
13
+ (255, 0, 0),
14
+ (0, 255, 0),
15
+ (0, 0, 255),
16
+ (128, 128, 0),
17
+ (128, 0, 128),
18
+ (0, 128, 128),
19
+ )
20
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellprofiler-library-nightly
3
- Version: 5.0.0.dev462
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,9 @@ 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
33
+ cellprofiler_library/modules/_graytocolor.py
32
34
  cellprofiler_library/modules/_identifyprimaryobjects.py
33
35
  cellprofiler_library/modules/_identifysecondaryobjects.py
34
36
  cellprofiler_library/modules/_identifytertiaryobjects.py
@@ -57,9 +59,12 @@ cellprofiler_library/opts/correctilluminationapply.py
57
59
  cellprofiler_library/opts/crop.py
58
60
  cellprofiler_library/opts/dilateimage.py
59
61
  cellprofiler_library/opts/dilateobjects.py
62
+ cellprofiler_library/opts/enhanceedges.py
60
63
  cellprofiler_library/opts/enhanceorsuppressfeatures.py
61
64
  cellprofiler_library/opts/erodeimage.py
62
65
  cellprofiler_library/opts/erodeobjects.py
66
+ cellprofiler_library/opts/flipandrotate.py
67
+ cellprofiler_library/opts/graytocolor.py
63
68
  cellprofiler_library/opts/identifyprimaryobjects.py
64
69
  cellprofiler_library/opts/identifysecondaryobjects.py
65
70
  cellprofiler_library/opts/identifytertiaryobjects.py