CellProfiler-nightly 5.0.0.dev318__py3-none-any.whl → 5.0.0.dev324__py3-none-any.whl

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.
cellprofiler/_version.py CHANGED
@@ -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.dev318'
32
- __version_tuple__ = version_tuple = (5, 0, 0, 'dev318')
31
+ __version__ = version = '5.0.0.dev324'
32
+ __version_tuple__ = version_tuple = (5, 0, 0, 'dev324')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -38,14 +38,13 @@ help for more information on saving cropping shapes.
38
38
  """
39
39
 
40
40
  import logging
41
- import math
42
-
43
41
  import centrosome.filter
44
42
  import matplotlib.axes
45
43
  import matplotlib.cm
46
44
  import matplotlib.figure
47
45
  import matplotlib.patches
48
46
  import numpy
47
+ from cellprofiler_core.constants.measurement import GROUP_INDEX
49
48
  from cellprofiler_core.image import Image
50
49
  from cellprofiler_core.module import Module
51
50
  from cellprofiler_core.preferences import get_primary_outline_color
@@ -57,39 +56,11 @@ from cellprofiler_core.setting.subscriber import ImageSubscriber
57
56
  from cellprofiler_core.setting.subscriber import LabelSubscriber
58
57
  from cellprofiler_core.setting.text import CropImageName
59
58
  from cellprofiler_core.setting.text import Integer
60
- from cellprofiler_core.utilities.image import crop_image
61
-
59
+ from cellprofiler_library.functions.image_processing import get_ellipse_cropping, get_rectangle_cropping
60
+ from cellprofiler_library.modules._crop import crop, get_measurements
61
+ from cellprofiler_library.opts.crop import RemovalMethod, Measurement, Shape, CroppingMethod, CroppingPattern, Limits, Ellipse, Rectangle
62
62
  LOGGER = logging.getLogger(__name__)
63
63
 
64
- SH_RECTANGLE = "Rectangle"
65
- SH_ELLIPSE = "Ellipse"
66
- SH_IMAGE = "Image"
67
- SH_OBJECTS = "Objects"
68
- SH_CROPPING = "Previous cropping"
69
- CM_COORDINATES = "Coordinates"
70
- CM_MOUSE = "Mouse"
71
- IO_INDIVIDUALLY = "Every"
72
- IO_FIRST = "First"
73
- RM_NO = "No"
74
- RM_EDGES = "Edges"
75
- RM_ALL = "All"
76
-
77
- # Doesn't seem to like importing defs from cellprofiler.gui.moduleview so define here
78
- ABSOLUTE = "Absolute"
79
- FROM_EDGE = "From edge"
80
-
81
- EL_XCENTER = "xcenter"
82
- EL_YCENTER = "ycenter"
83
- EL_XRADIUS = "xradius"
84
- EL_YRADIUS = "yradius"
85
-
86
- RE_LEFT = "left"
87
- RE_TOP = "top"
88
- RE_RIGHT = "right"
89
- RE_BOTTOM = "bottom"
90
-
91
- FF_AREA_RETAINED = "Crop_AreaRetainedAfterCropping_%s"
92
- FF_ORIGINAL_AREA = "Crop_OriginalImageArea_%s"
93
64
 
94
65
  OFF_IMAGE_NAME = 0
95
66
  OFF_CROPPED_IMAGE_NAME = 1
@@ -130,8 +101,8 @@ class Crop(Module):
130
101
 
131
102
  self.shape = Choice(
132
103
  text="Select the cropping shape",
133
- choices=[SH_RECTANGLE, SH_ELLIPSE, SH_IMAGE, SH_OBJECTS, SH_CROPPING],
134
- value=SH_RECTANGLE,
104
+ choices=[Shape.RECTANGLE.value, Shape.ELLIPSE.value, Shape.IMAGE.value, Shape.OBJECTS.value, Shape.CROPPING.value],
105
+ value=Shape.RECTANGLE.value,
135
106
  doc="""\
136
107
  Choose the shape into which you would like to crop:
137
108
 
@@ -161,19 +132,19 @@ Choose the shape into which you would like to crop:
161
132
  cropping that was used to generate whichever image you choose.
162
133
  """.format(
163
134
  **{
164
- "SH_RECTANGLE": SH_RECTANGLE,
165
- "SH_ELLIPSE": SH_ELLIPSE,
166
- "SH_IMAGE": SH_IMAGE,
167
- "SH_OBJECTS": SH_OBJECTS,
168
- "SH_CROPPING": SH_CROPPING,
135
+ "SH_RECTANGLE": Shape.RECTANGLE.value,
136
+ "SH_ELLIPSE": Shape.ELLIPSE.value,
137
+ "SH_IMAGE": Shape.IMAGE.value,
138
+ "SH_OBJECTS": Shape.OBJECTS.value,
139
+ "SH_CROPPING": Shape.CROPPING.value,
169
140
  }
170
141
  ),
171
142
  )
172
143
 
173
144
  self.crop_method = Choice(
174
145
  text="Select the cropping method",
175
- choices=[CM_COORDINATES, CM_MOUSE],
176
- value=CM_COORDINATES,
146
+ choices=[CroppingMethod.COORDINATES.value, CroppingMethod.MOUSE.value],
147
+ value=CroppingMethod.COORDINATES.value,
177
148
  doc="""\
178
149
  Choose whether you would like to crop by typing in pixel coordinates or
179
150
  clicking with the mouse.
@@ -190,18 +161,18 @@ clicking with the mouse.
190
161
  are in the interior of the region you wish to retain.
191
162
  """.format(
192
163
  **{
193
- "CM_COORDINATES": CM_COORDINATES,
194
- "SH_ELLIPSE": SH_ELLIPSE,
195
- "SH_RECTANGLE": SH_RECTANGLE,
196
- "CM_MOUSE": CM_MOUSE,
164
+ "CM_COORDINATES": CroppingMethod.COORDINATES.value,
165
+ "SH_ELLIPSE": Shape.ELLIPSE.value,
166
+ "SH_RECTANGLE": Shape.RECTANGLE.value,
167
+ "CM_MOUSE": CroppingMethod.MOUSE.value,
197
168
  }
198
169
  ),
199
170
  )
200
171
 
201
172
  self.individual_or_once = Choice(
202
173
  text="Apply which cycle's cropping pattern?",
203
- choices=[IO_INDIVIDUALLY, IO_FIRST],
204
- value=IO_INDIVIDUALLY,
174
+ choices=[CroppingPattern.INDIVIDUALLY.value, CroppingPattern.FIRST.value],
175
+ value=CroppingPattern.INDIVIDUALLY.value,
205
176
  doc="""\
206
177
  Specify how a given cropping pattern should be applied to other image cycles:
207
178
 
@@ -210,7 +181,7 @@ Specify how a given cropping pattern should be applied to other image cycles:
210
181
  intended to function as a template in some fashion.
211
182
  - *{IO_INDIVIDUALLY}:* Every image cycle is cropped individually.
212
183
  """.format(
213
- **{"IO_FIRST": IO_FIRST, "IO_INDIVIDUALLY": IO_INDIVIDUALLY}
184
+ **{"IO_FIRST": CroppingPattern.FIRST.value, "IO_INDIVIDUALLY": CroppingPattern.INDIVIDUALLY.value}
214
185
  ),
215
186
  )
216
187
 
@@ -232,9 +203,9 @@ Specify the left and right positions for the bounding rectangle by selecting one
232
203
  of the image’s original size.
233
204
  """.format(
234
205
  **{
235
- "SH_RECTANGLE": SH_RECTANGLE,
236
- "ABSOLUTE": ABSOLUTE,
237
- "FROM_EDGE": FROM_EDGE,
206
+ "SH_RECTANGLE": Shape.RECTANGLE.value,
207
+ "ABSOLUTE": Limits.ABSOLUTE.value,
208
+ "FROM_EDGE": Limits.FROM_EDGE.value,
238
209
  }
239
210
  ),
240
211
  )
@@ -255,9 +226,9 @@ Specify the top and bottom positions for the bounding rectangle by selecting one
255
226
  from the edges of your images irrespective of their size.
256
227
  """.format(
257
228
  **{
258
- "SH_RECTANGLE": SH_RECTANGLE,
259
- "ABSOLUTE": ABSOLUTE,
260
- "FROM_EDGE": FROM_EDGE,
229
+ "SH_RECTANGLE": Shape.RECTANGLE.value,
230
+ "ABSOLUTE": Limits.ABSOLUTE.value,
231
+ "FROM_EDGE": Limits.FROM_EDGE.value,
261
232
  }
262
233
  ),
263
234
  )
@@ -270,7 +241,7 @@ Specify the top and bottom positions for the bounding rectangle by selecting one
270
241
 
271
242
  Specify the center pixel position of the ellipse.
272
243
  """.format(
273
- **{"SH_ELLIPSE": SH_ELLIPSE}
244
+ **{"SH_ELLIPSE": Shape.ELLIPSE.value}
274
245
  ),
275
246
  )
276
247
 
@@ -282,7 +253,7 @@ Specify the center pixel position of the ellipse.
282
253
 
283
254
  Specify the radius of the ellipse in the X direction.
284
255
  """.format(
285
- **{"SH_ELLIPSE": SH_ELLIPSE}
256
+ **{"SH_ELLIPSE": Shape.ELLIPSE.value}
286
257
  ),
287
258
  )
288
259
 
@@ -294,7 +265,7 @@ Specify the radius of the ellipse in the X direction.
294
265
 
295
266
  Specify the radius of the ellipse in the Y direction.
296
267
  """.format(
297
- **{"SH_ELLIPSE": SH_ELLIPSE}
268
+ **{"SH_ELLIPSE": Shape.ELLIPSE.value}
298
269
  ),
299
270
  )
300
271
 
@@ -306,7 +277,7 @@ Specify the radius of the ellipse in the Y direction.
306
277
 
307
278
  Select the image to be use as a cropping mask.
308
279
  """.format(
309
- **{"SH_IMAGE": SH_IMAGE}
280
+ **{"SH_IMAGE": Shape.IMAGE.value}
310
281
  ),
311
282
  )
312
283
 
@@ -318,7 +289,7 @@ Select the image to be use as a cropping mask.
318
289
 
319
290
  Select the image associated with the cropping mask that you want to use.
320
291
  """.format(
321
- **{"SH_CROPPING": SH_CROPPING}
292
+ **{"SH_CROPPING": Shape.CROPPING.value}
322
293
  ),
323
294
  )
324
295
 
@@ -330,14 +301,14 @@ Select the image associated with the cropping mask that you want to use.
330
301
 
331
302
  Select the objects that are to be used as a cropping mask.
332
303
  """.format(
333
- **{"SH_OBJECTS": SH_OBJECTS}
304
+ **{"SH_OBJECTS": Shape.OBJECTS.value}
334
305
  ),
335
306
  )
336
307
 
337
308
  self.remove_rows_and_columns = Choice(
338
309
  text="Remove empty rows and columns?",
339
- choices=[RM_NO, RM_EDGES, RM_ALL],
340
- value=RM_ALL,
310
+ choices=[RemovalMethod.NO.value, RemovalMethod.EDGES.value, RemovalMethod.ALL.value],
311
+ value=RemovalMethod.ALL.value,
341
312
  doc="""\
342
313
  Use this option to choose whether to remove rows and columns that lack
343
314
  objects:
@@ -349,7 +320,7 @@ objects:
349
320
  - *{RM_ALL}:* Remove any row or column of all-blank pixels, even
350
321
  from the internal portion of the image.
351
322
  """.format(
352
- **{"RM_NO": RM_NO, "RM_EDGES": RM_EDGES, "RM_ALL": RM_ALL}
323
+ **{"RM_NO": RemovalMethod.NO.value, "RM_EDGES": RemovalMethod.EDGES.value, "RM_ALL": RemovalMethod.ALL.value}
353
324
  ),
354
325
  )
355
326
 
@@ -373,22 +344,22 @@ objects:
373
344
 
374
345
  def visible_settings(self):
375
346
  result = [self.image_name, self.cropped_image_name, self.shape]
376
- if self.shape.value in (SH_RECTANGLE, SH_ELLIPSE):
347
+ if self.shape.value in (Shape.RECTANGLE, Shape.ELLIPSE):
377
348
  result += [self.crop_method, self.individual_or_once]
378
- if self.crop_method == CM_COORDINATES:
379
- if self.shape == SH_RECTANGLE:
349
+ if self.crop_method.value == CroppingMethod.COORDINATES:
350
+ if self.shape.value == Shape.RECTANGLE:
380
351
  result += [self.horizontal_limits, self.vertical_limits]
381
- elif self.shape == SH_ELLIPSE:
352
+ elif self.shape.value == Shape.ELLIPSE:
382
353
  result += [
383
354
  self.ellipse_center,
384
355
  self.ellipse_x_radius,
385
356
  self.ellipse_y_radius,
386
357
  ]
387
- elif self.shape == SH_IMAGE:
358
+ elif self.shape.value == Shape.IMAGE:
388
359
  result += [self.image_mask_source]
389
- elif self.shape == SH_CROPPING:
360
+ elif self.shape.value == Shape.CROPPING:
390
361
  result.append(self.cropping_mask_source)
391
- elif self.shape == SH_OBJECTS:
362
+ elif self.shape.value == Shape.OBJECTS:
392
363
  result.append(self.objects_source)
393
364
  else:
394
365
  raise NotImplementedError("Unimplemented shape type: %s" % self.shape.value)
@@ -397,25 +368,25 @@ objects:
397
368
 
398
369
  def run(self, workspace):
399
370
  first_image_set = (
400
- workspace.measurements.get_current_image_measurement("Group_Index") == 1
371
+ workspace.measurements.get_current_image_measurement(GROUP_INDEX) == 1
401
372
  )
402
373
  image_set_list = workspace.image_set_list
403
- d = self.get_dictionary(image_set_list)
374
+ cache_dict = self.get_dictionary(image_set_list)
404
375
  orig_image = workspace.image_set.get_image(self.image_name.value)
405
376
  recalculate_flag = (
406
- self.shape not in (SH_ELLIPSE, SH_RECTANGLE)
407
- or self.individual_or_once == IO_INDIVIDUALLY
377
+ self.shape.value not in (Shape.ELLIPSE, Shape.RECTANGLE)
378
+ or self.individual_or_once.value == CroppingPattern.INDIVIDUALLY
408
379
  or first_image_set
409
380
  or workspace.pipeline.test_mode
410
381
  )
411
- save_flag = self.individual_or_once == IO_FIRST and first_image_set
382
+ save_flag = self.individual_or_once.value == CroppingPattern.FIRST and first_image_set
412
383
  if not recalculate_flag:
413
- if d[D_FIRST_CROPPING].shape != orig_image.pixel_data.shape[:2]:
384
+ if cache_dict[D_FIRST_CROPPING].shape != orig_image.pixel_data.shape[:2]:
414
385
  recalculate_flag = True
415
386
  LOGGER.warning(
416
387
  """Image, "%s", size changed from %s to %s during cycle %d, recalculating""",
417
388
  self.image_name.value,
418
- str(d[D_FIRST_CROPPING].shape),
389
+ str(cache_dict[D_FIRST_CROPPING].shape),
419
390
  str(orig_image.pixel_data.shape[:2]),
420
391
  workspace.image_set.image_number,
421
392
  )
@@ -423,59 +394,54 @@ objects:
423
394
  cropping = None
424
395
  masking_objects = None
425
396
  if not recalculate_flag:
426
- cropping = d[D_FIRST_CROPPING]
427
- mask = d[D_FIRST_CROPPING_MASK]
428
- elif self.shape == SH_CROPPING:
397
+ cropping = cache_dict[D_FIRST_CROPPING]
398
+ mask = cache_dict[D_FIRST_CROPPING_MASK]
399
+ elif self.shape.value == Shape.CROPPING:
429
400
  cropping_image = workspace.image_set.get_image(
430
401
  self.cropping_mask_source.value
431
402
  )
432
403
  cropping = cropping_image.crop_mask
433
- elif self.shape == SH_IMAGE:
404
+ elif self.shape.value == Shape.IMAGE:
434
405
  source_image = workspace.image_set.get_image(
435
406
  self.image_mask_source.value
436
407
  ).pixel_data
437
408
 
438
409
  cropping = source_image > 0
439
- elif self.shape == SH_OBJECTS:
410
+ elif self.shape.value == Shape.OBJECTS:
440
411
  masking_objects = workspace.get_objects(self.objects_source.value)
441
412
  cropping = masking_objects.segmented > 0
442
- elif self.crop_method == CM_MOUSE:
413
+ elif self.crop_method.value == CroppingMethod.MOUSE:
443
414
  cropping = self.ui_crop(workspace, orig_image)
444
- elif self.shape == SH_ELLIPSE:
445
- cropping = self.get_ellipse_cropping(workspace, orig_image)
446
- elif self.shape == SH_RECTANGLE:
447
- cropping = self.get_rectangle_cropping(workspace, orig_image)
448
- if self.remove_rows_and_columns == RM_NO:
449
- cropped_pixel_data = orig_image.pixel_data.copy()
450
- if cropped_pixel_data.ndim == 3:
451
- cropped_pixel_data[~cropping, :] = 0
452
- else:
453
- cropped_pixel_data[numpy.logical_not(cropping)] = 0
454
- if mask is None:
455
- mask = cropping
456
- if orig_image.has_mask:
457
- image_mask = mask & orig_image.mask
458
- else:
459
- image_mask = mask
460
- else:
461
- internal_cropping = self.remove_rows_and_columns == RM_ALL
462
- cropped_pixel_data = crop_image(
463
- orig_image.pixel_data, cropping, internal_cropping
415
+ elif self.shape.value == Shape.ELLIPSE:
416
+ cache_dict[Shape.ELLIPSE] = {
417
+ Ellipse.XCENTER: self.ellipse_center.x,
418
+ Ellipse.YCENTER: self.ellipse_center.y,
419
+ Ellipse.XRADIUS: self.ellipse_x_radius.value,
420
+ Ellipse.YRADIUS: self.ellipse_y_radius.value,
421
+ }
422
+
423
+ cropping = get_ellipse_cropping(
424
+ orig_image.pixel_data,
425
+ (self.ellipse_center.x, self.ellipse_center.y),
426
+ (self.ellipse_x_radius.value, self.ellipse_y_radius.value)
464
427
  )
465
- if mask is None:
466
- mask = crop_image(cropping, cropping, internal_cropping)
467
- if orig_image.has_mask:
468
- image_mask = (
469
- crop_image(orig_image.mask, cropping, internal_cropping) & mask
470
- )
471
- else:
472
- image_mask = mask
473
-
474
- if cropped_pixel_data.ndim == 3:
475
- cropped_pixel_data[~mask, :] = 0
476
- else:
477
- cropped_pixel_data[~mask] = 0
478
- if self.shape == SH_OBJECTS:
428
+
429
+ elif self.shape.value == Shape.RECTANGLE:
430
+ h_min = self.horizontal_limits.min if not self.horizontal_limits.unbounded_min else None
431
+ h_max = self.horizontal_limits.max if not self.horizontal_limits.unbounded_max else None
432
+ v_min = self.vertical_limits.min if not self.vertical_limits.unbounded_min else None
433
+ v_max = self.vertical_limits.max if not self.vertical_limits.unbounded_max else None
434
+
435
+ cropping = get_rectangle_cropping(orig_image.pixel_data, (h_min, h_max, v_min, v_max), validate_boundaries=True)
436
+ else:
437
+ raise NotImplementedError(f"Cropping shape {self.shape.value} or crop method {self.crop_method} not supported.")
438
+
439
+ assert(cropping is not None)
440
+ assert(cropping.dtype == bool)
441
+
442
+ cropped_pixel_data, mask, image_mask = crop(orig_image.pixel_data, cropping, mask, orig_image.mask, self.remove_rows_and_columns.value)
443
+
444
+ if self.shape.value == Shape.OBJECTS:
479
445
  # Special handling for objects - masked objects instead of
480
446
  # mask and crop mask
481
447
  output_image = Image(
@@ -501,8 +467,8 @@ objects:
501
467
  )
502
468
 
503
469
  if save_flag:
504
- d[D_FIRST_CROPPING_MASK] = mask
505
- d[D_FIRST_CROPPING] = cropping
470
+ cache_dict[D_FIRST_CROPPING_MASK] = mask
471
+ cache_dict[D_FIRST_CROPPING] = cropping
506
472
  #
507
473
  # Save the image / cropping / mask
508
474
  #
@@ -510,13 +476,10 @@ objects:
510
476
  #
511
477
  # Save the old and new image sizes
512
478
  #
513
- original_image_area = numpy.product(orig_image.pixel_data.shape[:2])
514
- area_retained_after_cropping = numpy.sum(cropping)
515
- feature = FF_AREA_RETAINED % self.cropped_image_name.value
516
479
  m = workspace.measurements
517
- m.add_measurement("Image", feature, numpy.array([area_retained_after_cropping]))
518
- feature = FF_ORIGINAL_AREA % self.cropped_image_name.value
519
- m.add_measurement("Image", feature, numpy.array([original_image_area]))
480
+ for measurement in get_measurements(cropping, orig_image.pixel_data, self.cropped_image_name.value):
481
+ m.add_measurement("Image", measurement[1], numpy.array([measurement[2]]))
482
+
520
483
 
521
484
  def display(self, workspace, figure):
522
485
  orig_image_pixel_data = workspace.display_data.orig_image_pixel_data
@@ -536,20 +499,28 @@ objects:
536
499
  """Return information on the measurements made during cropping"""
537
500
  return [
538
501
  ("Image", x % self.cropped_image_name.value, "integer",)
539
- for x in (FF_AREA_RETAINED, FF_ORIGINAL_AREA)
502
+ for x in (Measurement.AREA_RETAINED, Measurement.ORIGINAL_AREA)
540
503
  ]
541
504
 
542
505
  def ui_crop(self, workspace, orig_image):
543
506
  """Crop into a rectangle or ellipse, guided by UI"""
544
- d = self.get_dictionary(workspace.image_set_list)
545
- if (self.shape.value not in d) or self.individual_or_once == IO_INDIVIDUALLY:
546
- d[self.shape.value] = workspace.interaction_request(
547
- self, d.get(self.shape.value, None), orig_image.pixel_data
507
+ cache_dict = self.get_dictionary(workspace.image_set_list)
508
+ if (self.shape.value not in cache_dict) or self.individual_or_once.value == CroppingPattern.INDIVIDUALLY:
509
+ cache_dict[self.shape.value] = workspace.interaction_request(
510
+ self, cache_dict.get(self.shape.value, None), orig_image.pixel_data
548
511
  )
549
- if self.shape == SH_ELLIPSE:
550
- return self.apply_ellipse_cropping(workspace, orig_image)
512
+ if self.shape.value == Shape.ELLIPSE:
513
+ center = cache_dict[Shape.ELLIPSE][Ellipse.XCENTER], cache_dict[Shape.ELLIPSE][Ellipse.YCENTER]
514
+ radius = cache_dict[Shape.ELLIPSE][Ellipse.XRADIUS], cache_dict[Shape.ELLIPSE][Ellipse.YRADIUS]
515
+ return get_ellipse_cropping(orig_image.pixel_data, center, radius)
551
516
  else:
552
- return self.apply_rectangle_cropping(workspace, orig_image)
517
+ bounding_box = (
518
+ int(numpy.round(cache_dict[Shape.RECTANGLE][Rectangle.LEFT])),
519
+ int(numpy.round(cache_dict[Shape.RECTANGLE][Rectangle.RIGHT])),
520
+ int(numpy.round(cache_dict[Shape.RECTANGLE][Rectangle.TOP])),
521
+ int(numpy.round(cache_dict[Shape.RECTANGLE][Rectangle.BOTTOM])),
522
+ )
523
+ return get_rectangle_cropping(orig_image.pixel_data, bounding_box, validate_boundaries=True)
553
524
 
554
525
  def handle_interaction(self, current_shape, orig_image):
555
526
  from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
@@ -788,31 +759,31 @@ objects:
788
759
  def handles(self):
789
760
  return [self.center_handle, self.radius_handle]
790
761
 
791
- if self.shape == SH_ELLIPSE:
762
+ if self.shape.value == Shape.ELLIPSE:
792
763
  if current_shape is None:
793
764
  current_shape = {
794
- EL_XCENTER: pixel_data.shape[1] / 2,
795
- EL_YCENTER: pixel_data.shape[0] / 2,
796
- EL_XRADIUS: pixel_data.shape[1] / 2,
797
- EL_YRADIUS: pixel_data.shape[0] / 2,
765
+ Ellipse.XCENTER: pixel_data.shape[1] / 2,
766
+ Ellipse.YCENTER: pixel_data.shape[0] / 2,
767
+ Ellipse.XRADIUS: pixel_data.shape[1] / 2,
768
+ Ellipse.YRADIUS: pixel_data.shape[0] / 2,
798
769
  }
799
770
  ellipse = current_shape
800
771
  shape = CropEllipse(
801
- (ellipse[EL_XCENTER], ellipse[EL_YCENTER]),
802
- (ellipse[EL_XRADIUS], ellipse[EL_YRADIUS]),
772
+ (ellipse[Ellipse.XCENTER], ellipse[Ellipse.YCENTER]),
773
+ (ellipse[Ellipse.XRADIUS], ellipse[Ellipse.YRADIUS]),
803
774
  )
804
775
  else:
805
776
  if current_shape is None:
806
777
  current_shape = {
807
- RE_LEFT: pixel_data.shape[1] / 4,
808
- RE_TOP: pixel_data.shape[0] / 4,
809
- RE_RIGHT: pixel_data.shape[1] * 3 / 4,
810
- RE_BOTTOM: pixel_data.shape[0] * 3 / 4,
778
+ Rectangle.LEFT: pixel_data.shape[1] / 4,
779
+ Rectangle.TOP: pixel_data.shape[0] / 4,
780
+ Rectangle.RIGHT: pixel_data.shape[1] * 3 / 4,
781
+ Rectangle.BOTTOM: pixel_data.shape[0] * 3 / 4,
811
782
  }
812
783
  rectangle = current_shape
813
784
  shape = CropRectangle(
814
- (rectangle[RE_LEFT], rectangle[RE_TOP]),
815
- (rectangle[RE_RIGHT], rectangle[RE_BOTTOM]),
785
+ (rectangle[Rectangle.LEFT], rectangle[Rectangle.TOP]),
786
+ (rectangle[Rectangle.RIGHT], rectangle[Rectangle.BOTTOM]),
816
787
  )
817
788
  for patch in shape.patches:
818
789
  axes.add_artist(patch)
@@ -843,91 +814,21 @@ objects:
843
814
  raise ValueError("Cancelled by user")
844
815
  finally:
845
816
  dialog_box.Destroy()
846
- if self.shape == SH_RECTANGLE:
817
+ if self.shape.value == Shape.RECTANGLE:
847
818
  return {
848
- RE_LEFT: shape.left,
849
- RE_TOP: shape.top,
850
- RE_RIGHT: shape.right,
851
- RE_BOTTOM: shape.bottom,
819
+ Rectangle.LEFT: shape.left,
820
+ Rectangle.TOP: shape.top,
821
+ Rectangle.RIGHT: shape.right,
822
+ Rectangle.BOTTOM: shape.bottom,
852
823
  }
853
824
  else:
854
825
  return {
855
- EL_XCENTER: shape.center_x,
856
- EL_YCENTER: shape.center_y,
857
- EL_XRADIUS: shape.width / 2,
858
- EL_YRADIUS: shape.height / 2,
826
+ Ellipse.XCENTER: shape.center_x,
827
+ Ellipse.YCENTER: shape.center_y,
828
+ Ellipse.XRADIUS: shape.width / 2,
829
+ Ellipse.YRADIUS: shape.height / 2,
859
830
  }
860
831
 
861
- def get_ellipse_cropping(self, workspace, orig_image):
862
- """Crop into an ellipse using user-specified coordinates"""
863
- x_center = self.ellipse_center.x
864
- y_center = self.ellipse_center.y
865
- x_radius = self.ellipse_x_radius.value
866
- y_radius = self.ellipse_y_radius.value
867
- d = self.get_dictionary(workspace.image_set_list)
868
- d[SH_ELLIPSE] = {
869
- EL_XCENTER: x_center,
870
- EL_YCENTER: y_center,
871
- EL_XRADIUS: x_radius,
872
- EL_YRADIUS: y_radius,
873
- }
874
- return self.apply_ellipse_cropping(workspace, orig_image)
875
-
876
- def apply_ellipse_cropping(self, workspace, orig_image):
877
- d = self.get_dictionary(workspace.image_set_list)
878
- ellipse = d[SH_ELLIPSE]
879
- x_center, y_center, x_radius, y_radius = [
880
- ellipse[x] for x in (EL_XCENTER, EL_YCENTER, EL_XRADIUS, EL_YRADIUS)
881
- ]
882
- pixel_data = orig_image.pixel_data
883
- x_max = pixel_data.shape[1]
884
- y_max = pixel_data.shape[0]
885
- if x_radius > y_radius:
886
- dist_x = math.sqrt(x_radius ** 2 - y_radius ** 2)
887
- dist_y = 0
888
- major_radius = x_radius
889
- else:
890
- dist_x = 0
891
- dist_y = math.sqrt(y_radius ** 2 - x_radius ** 2)
892
- major_radius = y_radius
893
-
894
- focus_1_x, focus_1_y = (x_center - dist_x, y_center - dist_y)
895
- focus_2_x, focus_2_y = (x_center + dist_x, y_center + dist_y)
896
- y, x = numpy.mgrid[0:y_max, 0:x_max]
897
- d1 = numpy.sqrt((x - focus_1_x) ** 2 + (y - focus_1_y) ** 2)
898
- d2 = numpy.sqrt((x - focus_2_x) ** 2 + (y - focus_2_y) ** 2)
899
- cropping = d1 + d2 <= major_radius * 2
900
- return cropping
901
-
902
- def get_rectangle_cropping(self, workspace, orig_image):
903
- """Crop into a rectangle using user-specified coordinates"""
904
- cropping = numpy.ones(orig_image.pixel_data.shape[:2], bool)
905
- if not self.horizontal_limits.unbounded_min:
906
- cropping[:, : self.horizontal_limits.min] = False
907
- if not self.horizontal_limits.unbounded_max:
908
- cropping[:, self.horizontal_limits.max :] = False
909
- if not self.vertical_limits.unbounded_min:
910
- cropping[: self.vertical_limits.min, :] = False
911
- if not self.vertical_limits.unbounded_max:
912
- cropping[self.vertical_limits.max :, :] = False
913
- return cropping
914
-
915
- def apply_rectangle_cropping(self, workspace, orig_image):
916
- cropping = numpy.ones(orig_image.pixel_data.shape[:2], bool)
917
- d = self.get_dictionary(workspace.image_set_list)
918
- r = d[SH_RECTANGLE]
919
- left, top, right, bottom = [
920
- int(numpy.round(r[x])) for x in (RE_LEFT, RE_TOP, RE_RIGHT, RE_BOTTOM)
921
- ]
922
- if left > 0:
923
- cropping[:, :left] = False
924
- if right < cropping.shape[1]:
925
- cropping[:, right:] = False
926
- if top > 0:
927
- cropping[:top, :] = False
928
- if bottom < cropping.shape[0]:
929
- cropping[bottom:, :] = False
930
- return cropping
931
832
 
932
833
  def upgrade_settings(self, setting_values, variable_revision_number, module_name):
933
834
  if variable_revision_number == 1:
@@ -940,12 +841,12 @@ objects:
940
841
  # minor - "Cropping" changed to "Previous cropping"
941
842
  setting_values = list(setting_values)
942
843
  if setting_values[OFF_SHAPE] == "Cropping":
943
- setting_values[OFF_SHAPE] = SH_CROPPING
844
+ setting_values[OFF_SHAPE] = Shape.CROPPING
944
845
  #
945
846
  # Individually changed to "every"
946
847
  #
947
848
  if setting_values[OFF_INDIVIDUAL_OR_ONCE] == "Individually":
948
- setting_values[OFF_INDIVIDUAL_OR_ONCE] = IO_INDIVIDUALLY
849
+ setting_values[OFF_INDIVIDUAL_OR_ONCE] = CroppingPattern.INDIVIDUALLY
949
850
 
950
851
  setting_values = setting_values[:10] + setting_values[11:]
951
852
 
@@ -19,9 +19,8 @@ YES YES NO
19
19
  from cellprofiler_core.module import ImageProcessing
20
20
  from cellprofiler_core.setting import StructuringElement
21
21
 
22
- import cellprofiler.utilities.morphology
23
22
  from cellprofiler.modules._help import HELP_FOR_STREL
24
-
23
+ from cellprofiler_library.modules._erodeimage import erode_image
25
24
 
26
25
  class ErodeImage(ImageProcessing):
27
26
  category = "Advanced"
@@ -48,6 +47,5 @@ class ErodeImage(ImageProcessing):
48
47
  return __settings__ + [self.structuring_element]
49
48
 
50
49
  def run(self, workspace):
51
- self.function = cellprofiler.utilities.morphology.erosion
52
-
50
+ self.function = erode_image
53
51
  super(ErodeImage, self).run(workspace)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CellProfiler-nightly
3
- Version: 5.0.0.dev318
3
+ Version: 5.0.0.dev324
4
4
  Summary: CellProfiler is a free open-source software designed to enable biologists without training in computer vision or programming to quantitatively measure phenotypes from thousands of images automatically.
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>
@@ -1,6 +1,6 @@
1
1
  cellprofiler/__init__.py,sha256=AL2XeOBhIeYkBRyDd0QRgJan7j0DKjT1GD-RdzKvMUY,46
2
2
  cellprofiler/__main__.py,sha256=uy78oz5c6NBGRwDZkZ2Gl4HfhbJZQH6K1n54Qfl2OFc,38075
3
- cellprofiler/_version.py,sha256=VKwI68zHVxr7qKLpGyfYE5ws8C3HO1sHftyVZcFWLQk,721
3
+ cellprofiler/_version.py,sha256=X_dsIS438JBC3vSFB9YEnaGPIPrvCqTB7mibbwXlkv0,721
4
4
  cellprofiler/knime_bridge.py,sha256=T6Op-KO79oULx92nGXRQ6lHsEcTutx1Uep1L4ZOKJgc,27767
5
5
  cellprofiler/misc.py,sha256=yqv873lP_mquxxkKcLgE_ZU4Hrc1trtuQ-NXLK2qQVc,553
6
6
  cellprofiler/data/examples/ExampleFly/ExampleFly.cppipe,sha256=JGZK9IZuYlOHOI4hi6a3DK36IahY69cfeLEd7eJ_rO0,15409
@@ -290,7 +290,7 @@ cellprofiler/modules/convertobjectstoimage.py,sha256=zvn2nlnF3-i6g16F0um1yNT-Y03
290
290
  cellprofiler/modules/correctilluminationapply.py,sha256=eEcXliF2xNkT36Bo7xkNNh7l2YGbSqkqpss4O7RbwaM,15862
291
291
  cellprofiler/modules/correctilluminationcalculate.py,sha256=wJMCy3W9zK-xPI8PUvh25MLtE_JSI3QuVVzdLjuTwD4,54200
292
292
  cellprofiler/modules/createbatchfiles.py,sha256=a8R5PpbaQYqF8OIvWBuC0uh-yhjzBaU4Uni4m3MRLok,19512
293
- cellprofiler/modules/crop.py,sha256=Lg1cQCIzO7o8wcwEgRlsccdt8mgiiugowcNEe44vT0k,36039
293
+ cellprofiler/modules/crop.py,sha256=gnAHZNjPCNr-RLc7xQjZYViRpmKCTfJjuZ8MwHRiT1Y,34177
294
294
  cellprofiler/modules/definegrid.py,sha256=tjYcrzHu6TV7rkh1l2T0pNqcjBLwCfz9BCqTPWhQr_A,47160
295
295
  cellprofiler/modules/dilateimage.py,sha256=xcdsDdgvuplD69pcyJTOmVTxXFlwDWRNxapoQZHTiVc,1382
296
296
  cellprofiler/modules/dilateobjects.py,sha256=lnipjKkd6A3hhY3G1ttU9ZlhsTZp3oVU-QnU7_ayWbE,1828
@@ -302,7 +302,7 @@ cellprofiler/modules/displayscatterplot.py,sha256=sgB5Uf03mtUFMy3X6GqNNImhlKBWfZ
302
302
  cellprofiler/modules/editobjectsmanually.py,sha256=fkTFMTlrTfIiHNhhPzYsfFvZBSBDEIJgM7pZ7gDrMNA,21527
303
303
  cellprofiler/modules/enhanceedges.py,sha256=bivBs2OMNYvNnJ7tYrs9yheJP9JGIkgJDQfB2u837HE,11398
304
304
  cellprofiler/modules/enhanceorsuppressfeatures.py,sha256=vc_LLANt2gEsntqog9JwbzCVaaBQEM3ayvvY7CSJCF0,24062
305
- cellprofiler/modules/erodeimage.py,sha256=vdE2BjYq_wN5pKqNKdgs5xAINAK6vbQjB6rP_uLTwaY,1410
305
+ cellprofiler/modules/erodeimage.py,sha256=GGO6EjgA_6A0pjrsATxcfs1a_QmZ1rS5Lec7Kkb21hw,1402
306
306
  cellprofiler/modules/erodeobjects.py,sha256=cDQR8y7XqSt-ssp1nAQp3wXdQk5OE1uT7GrhTgjfdlI,4381
307
307
  cellprofiler/modules/expandorshrinkobjects.py,sha256=fiFf4q2BplR4u6Cym-jdlOOdOKc6oZVtEkZE-O-Ansg,13911
308
308
  cellprofiler/modules/exporttodatabase.py,sha256=Tb5Hf329m96zUNaxPStQoTkr_MV62HGNBetZL_Y1iyk,217927
@@ -374,9 +374,9 @@ cellprofiler/modules/plugins/segmentationtemplatewithdependencies.py,sha256=Sh76
374
374
  cellprofiler/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
375
375
  cellprofiler/utilities/morphology.py,sha256=8-81TrP8AmE3ETXIvQUKFD1vmKNBy2lfbc1QnM1eGIM,2685
376
376
  cellprofiler/utilities/rules.py,sha256=NoIHwFTA37zGvIP7vcB-aYeys0MDYVYxspfhLJe00OU,8790
377
- cellprofiler_nightly-5.0.0.dev318.dist-info/licenses/LICENSE,sha256=QLWaBS7kAioYx7PmJNXAMJaY8NODcFAag60YlUWuyz0,2276
378
- cellprofiler_nightly-5.0.0.dev318.dist-info/METADATA,sha256=x_cH5kn90YFPhDW1njHHwH4IHwMxcUKR5bfXgxSIKvQ,6063
379
- cellprofiler_nightly-5.0.0.dev318.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
380
- cellprofiler_nightly-5.0.0.dev318.dist-info/entry_points.txt,sha256=MNDCjguFW3dKiS5Pcdu1NfWo4I0HHI3DekJLUJ4AKkY,60
381
- cellprofiler_nightly-5.0.0.dev318.dist-info/top_level.txt,sha256=bK7AacDeSj9qAmW8MGlO5wA79hDj6-ACt_mENUNKSIk,13
382
- cellprofiler_nightly-5.0.0.dev318.dist-info/RECORD,,
377
+ cellprofiler_nightly-5.0.0.dev324.dist-info/licenses/LICENSE,sha256=QLWaBS7kAioYx7PmJNXAMJaY8NODcFAag60YlUWuyz0,2276
378
+ cellprofiler_nightly-5.0.0.dev324.dist-info/METADATA,sha256=rcJmOQxLnbrpJc0xxW9H88YMgZrJgDMvTA-W-YDrcPE,6063
379
+ cellprofiler_nightly-5.0.0.dev324.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
380
+ cellprofiler_nightly-5.0.0.dev324.dist-info/entry_points.txt,sha256=MNDCjguFW3dKiS5Pcdu1NfWo4I0HHI3DekJLUJ4AKkY,60
381
+ cellprofiler_nightly-5.0.0.dev324.dist-info/top_level.txt,sha256=bK7AacDeSj9qAmW8MGlO5wA79hDj6-ACt_mENUNKSIk,13
382
+ cellprofiler_nightly-5.0.0.dev324.dist-info/RECORD,,