def measure_objects(self, operand, workspace): '''Performs the measurements on the requested objects''' objects = workspace.get_objects(operand.operand_objects.value) if objects.has_parent_image: area_occupied = np.sum(objects.segmented[objects.parent_image.mask]>0) perimeter = np.sum(outline(np.logical_and(objects.segmented != 0,objects.parent_image.mask))) total_area = np.sum(objects.parent_image.mask) else: area_occupied = np.sum(objects.segmented > 0) perimeter = np.sum(outline(objects.segmented) > 0) total_area = np.product(objects.segmented.shape) m = workspace.measurements m.add_image_measurement(F_AREA_OCCUPIED%(operand.operand_objects.value), np.array([area_occupied], dtype=float )) m.add_image_measurement(F_PERIMETER%(operand.operand_objects.value), np.array([perimeter], dtype=float )) m.add_image_measurement(F_TOTAL_AREA%(operand.operand_objects.value), np.array([total_area], dtype=float)) if operand.should_save_image.value: binary_pixels = objects.segmented > 0 output_image = cpi.Image(binary_pixels, parent_image = objects.parent_image) workspace.image_set.add(operand.image_name.value, output_image) return[[operand.operand_objects.value, str(area_occupied),str(perimeter),str(total_area)]]
def measure_objects(self, operand, workspace): '''Performs the measurements on the requested objects''' objects = workspace.get_objects(operand.operand_objects.value) if objects.has_parent_image: area_occupied = np.sum( objects.segmented[objects.parent_image.mask] > 0) perimeter = np.sum( outline( np.logical_and(objects.segmented != 0, objects.parent_image.mask))) total_area = np.sum(objects.parent_image.mask) else: area_occupied = np.sum(objects.segmented > 0) perimeter = np.sum(outline(objects.segmented) > 0) total_area = np.product(objects.segmented.shape) m = workspace.measurements m.add_image_measurement( F_AREA_OCCUPIED % (operand.operand_objects.value), np.array([area_occupied], dtype=float)) m.add_image_measurement(F_PERIMETER % (operand.operand_objects.value), np.array([perimeter], dtype=float)) m.add_image_measurement(F_TOTAL_AREA % (operand.operand_objects.value), np.array([total_area], dtype=float)) if operand.should_save_image.value: binary_pixels = objects.segmented > 0 output_image = cpi.Image(binary_pixels, parent_image=objects.parent_image) workspace.image_set.add(operand.image_name.value, output_image) return [[ operand.operand_objects.value, str(area_occupied), str(perimeter), str(total_area) ]]
def test_02_04_edge(self): x = numpy.array([[0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0]]) e = numpy.array([[0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0]]) result = OL.outline(x) self.assertTrue(numpy.all(result == e))
def test_04_02_masked_edge(self): # Regression test of issue #1115 labels = np.zeros((20,50), int) labels[15:25, 15:25] = 1 image = np.random.uniform(size=labels.shape).astype(np.float32) # # Mask the edge of the object # mask = ~ cpmo.outline(labels).astype(bool) m = cpmeas.Measurements() m.add(IMAGE_NAME, cpi.Image(image, mask=mask)) object_set = cpo.ObjectSet() o = cpo.Objects() o.segmented = labels object_set.add_objects(o, OBJECT_NAME) pipeline = P.Pipeline() def callback(caller, event): self.assertFalse(isinstance(event, P.RunExceptionEvent)) pipeline.add_listener(callback) module = MOI.MeasureObjectIntensity() module.module_num = 1 module.images[0].name.value = IMAGE_NAME module.objects[0].name.value = OBJECT_NAME pipeline.add_module(module) workspace = cpw.Workspace(pipeline, module, m, object_set, m, None) module.run(workspace)
def test_04_02_masked_edge(self): # Regression test of issue #1115 labels = np.zeros((20, 50), int) labels[15:25, 15:25] = 1 image = np.random.uniform(size=labels.shape).astype(np.float32) # # Mask the edge of the object # mask = ~cpmo.outline(labels).astype(bool) m = cpmeas.Measurements() m.add(IMAGE_NAME, cpi.Image(image, mask=mask)) object_set = cpo.ObjectSet() o = cpo.Objects() o.segmented = labels object_set.add_objects(o, OBJECT_NAME) pipeline = P.Pipeline() def callback(caller, event): self.assertFalse(isinstance(event, P.RunExceptionEvent)) pipeline.add_listener(callback) module = MOI.MeasureObjectIntensity() module.module_num = 1 module.images[0].name.value = IMAGE_NAME module.objects[0].name.value = OBJECT_NAME pipeline.add_module(module) workspace = cpw.Workspace(pipeline, module, m, object_set, m, None) module.run(workspace)
def run(self, workspace): '''Find the outlines on the current image set workspace - The workspace contains pipeline - instance of cpp for this run image_set - the images in the image set being processed object_set - the objects (labeled masks) in this image set measurements - the measurements for this run frame - the parent frame to whatever frame is created. None means don't draw. ''' gridding = workspace.get_grid(self.grid_name.value) if self.shape_choice == SHAPE_RECTANGLE: labels = self.run_rectangle(workspace, gridding) elif self.shape_choice == SHAPE_CIRCLE_FORCED: labels = self.run_forced_circle(workspace, gridding) elif self.shape_choice == SHAPE_CIRCLE_NATURAL: labels = self.run_natural_circle(workspace, gridding) elif self.shape_choice == SHAPE_NATURAL: labels = self.run_natural(workspace, gridding) objects = cpo.Objects() objects.segmented = labels object_count = gridding.rows * gridding.columns workspace.object_set.add_objects(objects, self.output_objects_name.value) add_object_location_measurements(workspace.measurements, self.output_objects_name.value, labels, object_count) add_object_count_measurements(workspace.measurements, self.output_objects_name.value, object_count) if self.wants_outlines: outlines = outline(labels!=0) outline_image = cpi.Image(outlines) workspace.image_set.add(self.outlines_name.value, outline_image)
def outlines(self): '''Get a mask of all the points on the border of objects''' if self._outlines is None: for i, labels in enumerate(self.labels): if i == 0: self._outlines = outline(labels) != 0 else: self._outlines = self._outlines | (outline(labels) != 0) if self.line_width > 1: hw = float(self.line_width) / 2 d = distance_transform_edt(~ self._outlines) dti, dtj = np.where((d < hw+.5) & ~self._outlines) self._outlines = self._outlines.astype(np.float32) self._outlines[dti, dtj] = np.minimum(1, hw + .5 - d[dti, dtj]) return self._outlines.astype(np.float32)
def run(self, workspace): input_objects = workspace.object_set.get_objects(self.object_name.value) output_objects = cpo.Objects() output_objects.segmented = self.do_labels(input_objects.segmented) if (input_objects.has_small_removed_segmented and self.operation not in (O_EXPAND, O_EXPAND_INF, O_DIVIDE)): output_objects.small_removed_segmented = \ self.do_labels(input_objects.small_removed_segmented) if (input_objects.has_unedited_segmented and self.operation not in (O_EXPAND, O_EXPAND_INF, O_DIVIDE)): output_objects.unedited_segmented = \ self.do_labels(input_objects.unedited_segmented) workspace.object_set.add_objects(output_objects, self.output_object_name.value) add_object_count_measurements(workspace.measurements, self.output_object_name.value, np.max(output_objects.segmented)) add_object_location_measurements(workspace.measurements, self.output_object_name.value, output_objects.segmented) if self.wants_outlines.value: outline_image = cpi.Image(outline(output_objects.segmented) > 0, parent_image = input_objects.parent_image) workspace.image_set.add(self.outlines_name.value, outline_image) if workspace.frame is not None: figure = workspace.create_or_find_figure(title="ExpandOrShrinkObjects, image cycle #%d"%( workspace.measurements.image_set_number),subplots=(2,1)) figure.subplot_imshow_labels(0,0,input_objects.segmented, self.object_name.value) figure.subplot_imshow_labels(1,0,output_objects.segmented, self.output_object_name.value, sharex = figure.subplot(0,0), sharey = figure.subplot(0,0))
def test_07_01_make_ijv_outlines(self): np.random.seed(70) x = cpo.Objects() ii,jj = np.mgrid[0:10,0:20] masks = [(ii-ic)**2 + (jj - jc) **2 < r **2 for ic, jc, r in ((4,5,5), (4,12,5), (6, 8, 5))] i = np.hstack([ii[mask] for mask in masks]) j = np.hstack([jj[mask] for mask in masks]) v = np.hstack([[k+1] * np.sum(mask) for k, mask in enumerate(masks)]) x.ijv = np.column_stack((i,j,v)) x.parent_image = cpi.Image(np.zeros((10,20))) colors = np.random.uniform(size=(3, 3)).astype(np.float32) image = x.make_ijv_outlines(colors) i1 = [i for i, color in enumerate(colors) if np.all(color == image[0,5,:])] self.assertEqual(len(i1), 1) i2 = [i for i, color in enumerate(colors) if np.all(color == image[0,12,:])] self.assertEqual(len(i2), 1) i3 = [i for i, color in enumerate(colors) if np.all(color == image[-1,8,:])] self.assertEqual(len(i3), 1) self.assertNotEqual(i1[0], i2[0]) self.assertNotEqual(i2[0], i3[0]) colors = colors[np.array([i1[0], i2[0], i3[0]])] outlines = np.zeros((10,20,3), np.float32) alpha = np.zeros((10,20)) for i, (color, mask) in enumerate(zip(colors, masks)): my_outline = outline(mask) outlines[my_outline] += color alpha[my_outline] += 1 alpha[alpha == 0] = 1 outlines /= alpha[:,:,np.newaxis] np.testing.assert_almost_equal(outlines, image)
def run(self, workspace): input_objects = workspace.object_set.get_objects(self.object_name.value) output_objects = cpo.Objects() output_objects.segmented = self.do_labels(input_objects.segmented) if (input_objects.has_small_removed_segmented and self.operation not in (O_EXPAND, O_EXPAND_INF, O_DIVIDE)): output_objects.small_removed_segmented = \ self.do_labels(input_objects.small_removed_segmented) if (input_objects.has_unedited_segmented and self.operation not in (O_EXPAND, O_EXPAND_INF, O_DIVIDE)): output_objects.unedited_segmented = \ self.do_labels(input_objects.unedited_segmented) workspace.object_set.add_objects(output_objects, self.output_object_name.value) add_object_count_measurements(workspace.measurements, self.output_object_name.value, np.max(output_objects.segmented)) add_object_location_measurements(workspace.measurements, self.output_object_name.value, output_objects.segmented) if self.wants_outlines.value: outline_image = cpi.Image(outline(output_objects.segmented) > 0, parent_image = input_objects.parent_image) workspace.image_set.add(self.outlines_name.value, outline_image) if self.show_window: workspace.display_data.input_objects_segmented = input_objects.segmented workspace.display_data.output_objects_segmented = output_objects.segmented
def run(self, workspace): '''Find the outlines on the current image set workspace - The workspace contains pipeline - instance of cpp for this run image_set - the images in the image set being processed object_set - the objects (labeled masks) in this image set measurements - the measurements for this run frame - the parent frame to whatever frame is created. None means don't draw. ''' gridding = workspace.get_grid(self.grid_name.value) if self.shape_choice == SHAPE_RECTANGLE: labels = self.run_rectangle(workspace, gridding) elif self.shape_choice == SHAPE_CIRCLE_FORCED: labels = self.run_forced_circle(workspace, gridding) elif self.shape_choice == SHAPE_CIRCLE_NATURAL: labels = self.run_natural_circle(workspace, gridding) elif self.shape_choice == SHAPE_NATURAL: labels = self.run_natural(workspace, gridding) objects = cpo.Objects() objects.segmented = labels object_count = gridding.rows * gridding.columns workspace.object_set.add_objects(objects, self.output_objects_name.value) add_object_location_measurements(workspace.measurements, self.output_objects_name.value, labels, object_count) add_object_count_measurements(workspace.measurements, self.output_objects_name.value, object_count) if self.wants_outlines: outlines = outline(labels != 0) outline_image = cpi.Image(outlines) workspace.image_set.add(self.outlines_name.value, outline_image)
def test_01_02_object_with_cropping(self): labels = np.zeros((10, 10), int) labels[0:7, 3:8] = 1 mask = np.zeros((10, 10), bool) mask[1:9, 1:9] = True image = cpi.Image(np.zeros((10, 10)), mask=mask) area_occupied = np.sum(labels[mask]) perimeter = np.sum(outline(np.logical_and(labels, mask))) total_area = np.sum(mask) workspace = self.make_workspace(labels, image) module = workspace.module module.operands[0].operand_choice.value = "Objects" module.run(workspace) m = workspace.measurements def mn(x): return "AreaOccupied_%s_%s" % ( x, module.operands[0].operand_objects.value) self.assertEqual( m.get_current_measurement("Image", mn("AreaOccupied")), area_occupied) self.assertEqual(m.get_current_measurement("Image", mn("Perimeter")), perimeter) self.assertEqual(m.get_current_measurement("Image", mn("TotalArea")), total_area)
def outlines(self): '''Get a mask of all the points on the border of objects''' if self._outlines == None: for i, labels in enumerate(self.labels): if i == 0: self._outlines = outline(labels) != 0 else: self._outlines = self._outlines | (outline(labels) != 0) if self.line_width > 1: hw = float(self.line_width) / 2 d = distance_transform_edt(~ self._outlines) dti, dtj = np.where((d < hw+.5) & ~self._outlines) self._outlines = self._outlines.astype(np.float32) self._outlines[dti, dtj] = np.minimum(1, hw + .5 - d[dti, dtj]) return self._outlines.astype(np.float32)
def display(self, workspace, figure): '''Create an informative display for the module''' import matplotlib from cellprofiler.gui.cpfigure import renumber_labels_for_display original_labels = workspace.display_data.original_labels final_labels = workspace.display_data.final_labels mask = workspace.display_data.mask # # Create a composition of the final labels and mask # final_labels = renumber_labels_for_display(final_labels) outlines = outline(original_labels) > 0 cm = matplotlib.cm.get_cmap(cpprefs.get_default_colormap()) sm = matplotlib.cm.ScalarMappable(cmap=cm) # # Paint the labels in color # image = sm.to_rgba(final_labels)[:, :, :3] image[final_labels == 0, :] = 0 # # Make the mask a dark gray # image[(final_labels == 0) & mask, :] = .25 # # Make the outlines of the kept objects the primary color # and the outlines of removed objects red. # final_outlines = outline(final_labels) > 0 original_color = np.array(cpprefs.get_secondary_outline_color(), float) / 255 final_color = np.array(cpprefs.get_primary_outline_color(), float) / 255 image[outlines, :] = original_color[np.newaxis, :] image[final_outlines, :] = final_color[np.newaxis, :] figure.set_subplots((2, 1)) figure.subplot_imshow_labels(0, 0, original_labels, title=self.object_name.value) figure.subplot_imshow_color(1, 0, image, title=self.remaining_objects.value, sharexy=figure.subplot(0, 0))
def display(self, workspace): '''Display what was filtered''' src_name = self.object_name.value src_objects = workspace.get_objects(src_name) target_name = self.target_name.value target_objects = workspace.get_objects(target_name) image = None image_names = [image for image in [m.measurement.get_image_name(workspace.pipeline) for m in self.measurements] if image is not None and image in workspace.image_set.get_names()] if len(image_names) == 0: # Measurement isn't image-based if src_objects.has_parent_image: image = src_objects.parent_image else: image = workspace.image_set.get_image(image_names[0]) if image is None: # Oh so sad - no image, just display the old and new labels figure = workspace.create_or_find_figure(title="FilterObjects, image cycle #%d"%( workspace.measurements.image_set_number),subplots=(1,2)) figure.subplot_imshow_labels(0,0,src_objects.segmented, title="Original: %s"%src_name) figure.subplot_imshow_labels(0,1,target_objects.segmented, title="Filtered: %s"% target_name, sharex = figure.subplot(0,0), sharey = figure.subplot(0,0)) else: figure = workspace.create_or_find_figure(title="FilterObjects, image cycle #%d"%( workspace.measurements.image_set_number),subplots=(2,2)) figure.subplot_imshow_labels(0,0,src_objects.segmented, title="Original: %s"%src_name) figure.subplot_imshow_labels(0,1,target_objects.segmented, title="Filtered: %s"% target_name, sharex = figure.subplot(0,0), sharey = figure.subplot(0,0)) outs = outline(target_objects.segmented) > 0 pixel_data = image.pixel_data maxpix = np.max(pixel_data) if maxpix == 0: maxpix = 1.0 if len(pixel_data.shape) == 3: picture = pixel_data.copy() else: picture = np.dstack((pixel_data,pixel_data,pixel_data)) red_channel = picture[:,:,0] red_channel[outs] = maxpix figure.subplot_imshow(1, 0, picture, "Filtered Outlines", sharex = figure.subplot(0,0), sharey = figure.subplot(0,0)) if workspace.frame != None: statistics = [ ["Number of objects pre-filtering", np.max(src_objects.segmented)], ["Number of objects post-filtering", np.max(target_objects.segmented)]] figure.subplot_table(1, 1, statistics, ratio=[.8,.2])
def display(self, workspace, figure): '''Display what was filtered''' src_name = self.object_name.value src_objects_segmented = workspace.display_data.src_objects_segmented image = workspace.display_data.image image_names = workspace.display_data.image_names target_objects_segmented = workspace.display_data.target_objects_segmented target_name = self.target_name.value if image is None: # Oh so sad - no image, just display the old and new labels figure.set_subplots((1, 2)) figure.subplot_imshow_labels(0, 0, src_objects_segmented, title="Original: %s" % src_name) figure.subplot_imshow_labels(0, 1, target_objects_segmented, title="Filtered: %s" % target_name, sharexy=figure.subplot(0, 0)) else: figure.set_subplots((2, 2)) figure.subplot_imshow_labels(0, 0, src_objects_segmented, title="Original: %s" % src_name) figure.subplot_imshow_labels(0, 1, target_objects_segmented, title="Filtered: %s" % target_name, sharexy=figure.subplot(0, 0)) outs = outline(target_objects_segmented) > 0 maxpix = np.max(image) if maxpix == 0: maxpix = 1.0 if len(image.shape) == 3: picture = image.copy() else: picture = np.dstack((image, image, image)) red_channel = picture[:, :, 0] red_channel[outs] = maxpix figure.subplot_imshow(1, 0, picture, "Filtered Outlines", sharexy=figure.subplot(0, 0)) statistics = [[np.max(src_objects_segmented)], [np.max(target_objects_segmented)]] figure.subplot_table( 1, 1, statistics, row_labels=("Number of objects pre-filtering", "Number of objects post-filtering"))
def display(self, workspace): '''Create an informative display for the module''' import matplotlib from cellprofiler.gui.cpfigure import renumber_labels_for_display original_labels = workspace.display_data.original_labels final_labels = workspace.display_data.final_labels mask = workspace.display_data.mask # # Create a composition of the final labels and mask # final_labels = renumber_labels_for_display(final_labels) outlines = outline(original_labels) > 0 cm = matplotlib.cm.get_cmap(cpprefs.get_default_colormap()) sm = matplotlib.cm.ScalarMappable(cmap = cm) # # Paint the labels in color # image = sm.to_rgba(final_labels)[:,:,:3] image[final_labels == 0,:] = 0 # # Make the mask a dark gray # image[(final_labels == 0) & mask,:] = .25 # # Make the outlines of the kept objects the primary color # and the outlines of removed objects red. # final_outlines = outline(final_labels) > 0 original_color = np.array(cpprefs.get_secondary_outline_color(), float) / 255 final_color = np.array(cpprefs.get_primary_outline_color(), float) / 255 image[outlines, :] = original_color[np.newaxis, :] image[final_outlines, :] = final_color[np.newaxis, :] figure = workspace.create_or_find_figure(title="MaskObjects, image cycle #%d"%( workspace.measurements.image_set_number),subplots=(2,1)) figure.subplot_imshow_labels(0, 0, original_labels, title = self.object_name.value) figure.subplot_imshow_color(1, 0, image, title = self.remaining_objects.value, sharex = figure.subplot(0,0), sharey = figure.subplot(0,0))
def test_01_03_touching(self): x = numpy.array([[0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0]]) e = numpy.array([[0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 0, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0]]) result = OL.outline(x) self.assertTrue(numpy.all(result == e))
def test_02_04_edge(self): x = numpy.array([[ 0,0,1,1,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,0,0,0,0,0]]) e = numpy.array([[ 0,0,1,1,1,0,0], [ 0,0,1,0,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,0,0,0,0,0]]) result = OL.outline(x) self.assertTrue(numpy.all(result==e))
def test_01_02_two_disjoint(self): x = numpy.array([[0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0]]) e = numpy.array([[0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 0, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0]]) result = OL.outline(x) self.assertTrue(numpy.all(result == e))
def test_07_01_outlines(self): """Create an outline of the resulting objects""" labels = np.zeros((10, 10), int) labels[4, 4] = 1 i, j = np.mgrid[0:10, 0:10] - 4 expected = (i ** 2 + j ** 2 <= 4).astype(int) expected_outlines = outline(expected) workspace, module = self.make_workspace(labels, E.O_EXPAND, 2, wants_outlines=True) module.run(workspace) objects = workspace.object_set.get_objects(OUTPUT_NAME) self.assertTrue(np.all(objects.segmented == expected)) self.assertTrue(OUTLINES_NAME in workspace.image_set.get_names()) outlines = workspace.image_set.get_image(OUTLINES_NAME).pixel_data self.assertTrue(np.all(outlines == expected_outlines))
def measure_images(self,operand,workspace): '''Performs measurements on the requested images''' image = workspace.image_set.get_image(operand.binary_name.value, must_be_binary = True) area_occupied = np.sum(image.pixel_data > 0) perimeter = np.sum(outline(image.pixel_data) > 0) total_area = np.prod(np.shape(image.pixel_data)) m = workspace.measurements m.add_image_measurement(F_AREA_OCCUPIED%(operand.binary_name.value), np.array([area_occupied], dtype=float)) m.add_image_measurement(F_PERIMETER%(operand.binary_name.value), np.array([perimeter], dtype=float)) m.add_image_measurement(F_TOTAL_AREA%(operand.binary_name.value), np.array([total_area], dtype=float)) return [[operand.binary_name.value, str(area_occupied), str(perimeter), str(total_area)]]
def display(): if len(orig_axes.images) > 0: # Save zoom and scale if coming through here a second time x0, x1 = orig_axes.get_xlim() y0, y1 = orig_axes.get_ylim() set_lim = True else: set_lim = False for axes, labels, title in ((orig_axes, orig_labels, "Original: %s" % orig_objects_name), (keep_axes, orig_labels * mask, "Objects to keep"), (remove_axes, orig_labels * (~mask), "Objects to remove")): assert isinstance(axes, matplotlib.axes.Axes) labels = renumber_labels_for_display(labels) axes.clear() if np.all(labels == 0): use_cm = matplotlib.cm.gray is_blank = True else: use_cm = cm is_blank = False if wants_image_display[0]: outlines = outline(labels) image = workspace.image_set.get_image( self.image_name.value) image = image.pixel_data.astype(np.float) image, _ = cpo.size_similarly(labels, image) if image.ndim == 2: image = np.dstack((image, image, image)) if not is_blank: mappable = matplotlib.cm.ScalarMappable(cmap=use_cm) mappable.set_clim(1, labels.max()) limage = mappable.to_rgba(labels)[:, :, :3] image[outlines != 0, :] = limage[outlines != 0, :] axes.imshow(image) else: axes.imshow(labels, cmap=use_cm) axes.set_title(title, fontname=cpprefs.get_title_font_name(), fontsize=cpprefs.get_title_font_size()) if set_lim: orig_axes.set_xlim((x0, x1)) orig_axes.set_ylim((y0, y1)) figure.canvas.draw() panel.Refresh()
def test_07_01_outlines(self): '''Create an outline of the resulting objects''' labels = np.zeros((10,10), int) labels[4,4] = 1 i,j = np.mgrid[0:10,0:10]-4 expected = (i**2 + j**2 <=4).astype(int) expected_outlines = outline(expected) workspace, module = self.make_workspace(labels, E.O_EXPAND, 2, wants_outlines = True) module.run(workspace) objects = workspace.object_set.get_objects(OUTPUT_NAME) self.assertTrue(np.all(objects.segmented == expected)) self.assertTrue(OUTLINES_NAME in workspace.image_set.get_names()) outlines = workspace.image_set.get_image(OUTLINES_NAME).pixel_data self.assertTrue(np.all(outlines == expected_outlines))
def make_ijv_outlines(self, colors): '''Make ijv-style color outlines Make outlines, coloring each object differently to distinguish between objects that might overlap. colors: a N x 3 color map to be used to color the outlines ''' # # Get planes of non-overlapping objects. The idea here is to use # the most similar colors in the color space for objects that # don't overlap. # all_labels = [(outline(label), indexes) for label, indexes in self.get_labels()] image = np.zeros(list(all_labels[0][0].shape) + [3], np.float32) # # Find out how many unique labels in each # counts = [np.sum(np.unique(l) != 0) for l, _ in all_labels] if len(counts) == 1 and counts[0] == 0: return image if len(colors) < len(all_labels): # Have to color 2 planes using the same color! # There's some chance that overlapping objects will get # the same color. Give me more colors to work with please. colors = np.vstack([colors] * (1 + len(all_labels) / len(colors))) r = np.random.mtrand.RandomState() alpha = np.zeros(all_labels[0][0].shape, np.float32) order = np.lexsort([counts]) label_colors = [] for idx, i in enumerate(order): max_available = len(colors) / (len(all_labels) - idx) ncolors = min(counts[i], max_available) my_colors = colors[:ncolors] colors = colors[ncolors:] my_colors = my_colors[r.permutation(np.arange(ncolors))] my_labels, indexes = all_labels[i] color_idx = np.zeros(np.max(indexes) + 1, int) color_idx[indexes] = np.arange(len(indexes)) % ncolors image[my_labels != 0,:] += \ my_colors[color_idx[my_labels[my_labels != 0]],:] alpha[my_labels != 0] += 1 image[alpha > 0, :] /= alpha[alpha > 0][:, np.newaxis] return image
def display(): if len(orig_axes.images) > 0: # Save zoom and scale if coming through here a second time x0, x1 = orig_axes.get_xlim() y0, y1 = orig_axes.get_ylim() set_lim = True else: set_lim = False for axes, labels, title in ( (orig_axes, orig_labels, "Original: %s"%orig_objects_name), (keep_axes, orig_labels * mask,"Objects to keep"), (remove_axes, orig_labels * (~ mask), "Objects to remove")): assert isinstance(axes, matplotlib.axes.Axes) labels = renumber_labels_for_display(labels) axes.clear() if np.all(labels == 0): use_cm = matplotlib.cm.gray is_blank = True else: use_cm = cm is_blank = False if wants_image_display[0]: outlines = outline(labels) image = workspace.image_set.get_image(self.image_name.value) image = image.pixel_data.astype(np.float) image, _ = cpo.size_similarly(labels, image) if image.ndim == 2: image = np.dstack((image, image, image)) if not is_blank: mappable = matplotlib.cm.ScalarMappable(cmap=use_cm) mappable.set_clim(1,labels.max()) limage = mappable.to_rgba(labels)[:,:,:3] image[outlines != 0,:] = limage[outlines != 0, :] axes.imshow(image) else: axes.imshow(labels, cmap = use_cm) axes.set_title(title, fontname=cpprefs.get_title_font_name(), fontsize=cpprefs.get_title_font_size()) if set_lim: orig_axes.set_xlim((x0, x1)) orig_axes.set_ylim((y0, y1)) figure.canvas.draw() panel.Refresh()
def display(self, workspace, figure): '''Display what was filtered''' src_name = self.object_name.value src_objects_segmented = workspace.display_data.src_objects_segmented image = workspace.display_data.image image_names = workspace.display_data.image_names target_objects_segmented = workspace.display_data.target_objects_segmented target_name = self.target_name.value if image is None: # Oh so sad - no image, just display the old and new labels figure.set_subplots((1, 2)) figure.subplot_imshow_labels(0,0,src_objects_segmented, title="Original: %s"%src_name) figure.subplot_imshow_labels(0,1,target_objects_segmented, title="Filtered: %s"% target_name, sharexy = figure.subplot(0,0)) else: figure.set_subplots((2, 2)) figure.subplot_imshow_labels(0,0,src_objects_segmented, title="Original: %s"%src_name) figure.subplot_imshow_labels(0,1,target_objects_segmented, title="Filtered: %s"% target_name, sharexy = figure.subplot(0,0)) outs = outline(target_objects_segmented) > 0 maxpix = np.max(image) if maxpix == 0: maxpix = 1.0 if len(image.shape) == 3: picture = image.copy() else: picture = np.dstack((image,image,image)) red_channel = picture[:,:,0] red_channel[outs] = maxpix figure.subplot_imshow(1, 0, picture, "Filtered Outlines", sharexy = figure.subplot(0,0)) statistics = [ [np.max(src_objects_segmented)], [np.max(target_objects_segmented)]] figure.subplot_table( 1, 1, statistics, row_labels = ("Number of objects pre-filtering", "Number of objects post-filtering"))
def make_ijv_outlines(self, colors): '''Make ijv-style color outlines Make outlines, coloring each object differently to distinguish between objects that might overlap. colors: a N x 3 color map to be used to color the outlines ''' # # Get planes of non-overlapping objects. The idea here is to use # the most similar colors in the color space for objects that # don't overlap. # all_labels = [(outline(label), indexes) for label, indexes in self.get_labels()] image = np.zeros(list(all_labels[0][0].shape) + [3], np.float32) # # Find out how many unique labels in each # counts = [np.sum(np.unique(l) != 0) for l, _ in all_labels] if len(counts) == 1 and counts[0] == 0: return image if len(colors) < len(all_labels): # Have to color 2 planes using the same color! # There's some chance that overlapping objects will get # the same color. Give me more colors to work with please. colors = np.vstack([colors] * (1 + len(all_labels) / len(colors))) r = np.random.mtrand.RandomState() alpha = np.zeros(all_labels[0][0].shape, np.float32) order = np.lexsort([counts]) label_colors = [] for idx,i in enumerate(order): max_available = len(colors) / (len(all_labels) - idx) ncolors = min(counts[i], max_available) my_colors = colors[:ncolors] colors = colors[ncolors:] my_colors = my_colors[r.permutation(np.arange(ncolors))] my_labels, indexes = all_labels[i] color_idx = np.zeros(np.max(indexes) + 1, int) color_idx[indexes] = np.arange(len(indexes)) % ncolors image[my_labels != 0,:] += \ my_colors[color_idx[my_labels[my_labels != 0]],:] alpha[my_labels != 0] += 1 image[alpha > 0, :] /= alpha[alpha > 0][:, np.newaxis] return image
def run(self, workspace): image_name = self.image_name.value objects_name = self.objects_name.value outlines_name = self.outlines_name.value image = workspace.image_set.get_image(image_name) pixel_data = image.pixel_data labels = np.zeros(pixel_data.shape[:2], int) self.do_ui(workspace, pixel_data, labels) objects = cpo.Objects() objects.segmented = labels workspace.object_set.add_objects(objects, objects_name) ################## # # Add measurements # m = workspace.measurements # # The object count # object_count = np.max(labels) I.add_object_count_measurements(m, objects_name, object_count) # # The object locations # I.add_object_location_measurements(m, objects_name, labels) # # Outlines if we want them # if self.wants_outlines: outlines_name = self.outlines_name.value outlines = outline(labels) outlines_image = cpi.Image(outlines.astype(bool)) workspace.image_set.add(outlines_name, outlines_image) # # Do the drawing here # if workspace.frame is not None: figure = workspace.create_or_find_figure(title="IdentifyObjectsManually, image cycle #%d"%( workspace.measurements.image_set_number),subplots=(2,1)) figure.subplot_imshow_labels(0, 0, labels, objects_name) figure.subplot_imshow(1, 0, self.draw_outlines(pixel_data, labels), sharex = figure.subplot(0,0), sharey = figure.subplot(0,0))
def test_01_03_touching(self): x = numpy.array([[ 0,0,0,0,0,0,0], [ 0,0,1,1,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,2,2,2,0,0], [ 0,0,2,2,2,0,0], [ 0,0,2,2,2,0,0], [ 0,0,0,0,0,0,0]]) e = numpy.array([[ 0,0,0,0,0,0,0], [ 0,0,1,1,1,0,0], [ 0,0,1,0,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,2,2,2,0,0], [ 0,0,2,0,2,0,0], [ 0,0,2,2,2,0,0], [ 0,0,0,0,0,0,0]]) result = OL.outline(x) self.assertTrue(numpy.all(result==e))
def run(self, workspace): image_name = self.image_name.value objects_name = self.objects_name.value outlines_name = self.outlines_name.value image = workspace.image_set.get_image(image_name) pixel_data = image.pixel_data labels = workspace.interaction_request( self, pixel_data, workspace.measurements.image_set_number) if labels is None: # User cancelled. Soldier on as best we can. workspace.cancel_request() labels = np.zeros(pixel_data.shape[:2], int) objects = cpo.Objects() objects.segmented = labels workspace.object_set.add_objects(objects, objects_name) ################## # # Add measurements # m = workspace.measurements # # The object count # object_count = np.max(labels) I.add_object_count_measurements(m, objects_name, object_count) # # The object locations # I.add_object_location_measurements(m, objects_name, labels) # # Outlines if we want them # if self.wants_outlines: outlines_name = self.outlines_name.value outlines = outline(labels) outlines_image = cpi.Image(outlines.astype(bool)) workspace.image_set.add(outlines_name, outlines_image) workspace.display_data.labels = labels workspace.display_data.pixel_data = pixel_data
def measure_images(self, operand, workspace): '''Performs measurements on the requested images''' image = workspace.image_set.get_image(operand.binary_name.value, must_be_binary=True) area_occupied = np.sum(image.pixel_data > 0) perimeter = np.sum(outline(image.pixel_data) > 0) total_area = np.prod(np.shape(image.pixel_data)) m = workspace.measurements m.add_image_measurement(F_AREA_OCCUPIED % (operand.binary_name.value), np.array([area_occupied], dtype=float)) m.add_image_measurement(F_PERIMETER % (operand.binary_name.value), np.array([perimeter], dtype=float)) m.add_image_measurement(F_TOTAL_AREA % (operand.binary_name.value), np.array([total_area], dtype=float)) return [[ operand.binary_name.value, str(area_occupied), str(perimeter), str(total_area) ]]
def test_01_02_object_with_cropping(self): labels = np.zeros((10,10),int) labels[0:7,3:8] = 1 mask = np.zeros((10,10),bool) mask[1:9,1:9] = True image = cpi.Image(np.zeros((10,10)),mask=mask) area_occupied = np.sum(labels[mask]) perimeter = np.sum(outline(np.logical_and(labels,mask))) total_area = np.sum(mask) workspace = self.make_workspace(labels, image) module = workspace.module module.operands[0].operand_choice.value = "Objects" module.run(workspace) m = workspace.measurements def mn(x): return "AreaOccupied_%s_%s"%(x, module.operands[0].operand_objects.value) self.assertEqual(m.get_current_measurement("Image",mn("AreaOccupied")), area_occupied) self.assertEqual(m.get_current_measurement("Image",mn("Perimeter")), perimeter) self.assertEqual(m.get_current_measurement("Image",mn("TotalArea")), total_area)
def test_01_02_two_disjoint(self): x = numpy.array([[ 0,0,0,0,0,0,0], [ 0,0,1,1,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,0,0,0,0,0], [ 0,0,2,2,2,0,0], [ 0,0,2,2,2,0,0], [ 0,0,2,2,2,0,0], [ 0,0,0,0,0,0,0]]) e = numpy.array([[ 0,0,0,0,0,0,0], [ 0,0,1,1,1,0,0], [ 0,0,1,0,1,0,0], [ 0,0,1,1,1,0,0], [ 0,0,0,0,0,0,0], [ 0,0,2,2,2,0,0], [ 0,0,2,0,2,0,0], [ 0,0,2,2,2,0,0], [ 0,0,0,0,0,0,0]]) result = OL.outline(x) self.assertTrue(numpy.all(result==e))
def run(self, workspace): input_objects = workspace.object_set.get_objects( self.object_name.value) output_objects = cpo.Objects() output_objects.segmented = self.do_labels(input_objects.segmented) if (input_objects.has_small_removed_segmented and self.operation not in (O_EXPAND, O_EXPAND_INF, O_DIVIDE)): output_objects.small_removed_segmented = \ self.do_labels(input_objects.small_removed_segmented) if (input_objects.has_unedited_segmented and self.operation not in (O_EXPAND, O_EXPAND_INF, O_DIVIDE)): output_objects.unedited_segmented = \ self.do_labels(input_objects.unedited_segmented) workspace.object_set.add_objects(output_objects, self.output_object_name.value) add_object_count_measurements(workspace.measurements, self.output_object_name.value, np.max(output_objects.segmented)) add_object_location_measurements(workspace.measurements, self.output_object_name.value, output_objects.segmented) if self.wants_outlines.value: outline_image = cpi.Image(outline(output_objects.segmented) > 0, parent_image=input_objects.parent_image) workspace.image_set.add(self.outlines_name.value, outline_image) if workspace.frame is not None: figure = workspace.create_or_find_figure( title="ExpandOrShrinkObjects, image cycle #%d" % (workspace.measurements.image_set_number), subplots=(2, 1)) figure.subplot_imshow_labels(0, 0, input_objects.segmented, self.object_name.value) figure.subplot_imshow_labels(1, 0, output_objects.segmented, self.output_object_name.value, sharex=figure.subplot(0, 0), sharey=figure.subplot(0, 0))
def run(self, workspace): image_name = self.image_name.value objects_name = self.objects_name.value outlines_name = self.outlines_name.value image = workspace.image_set.get_image(image_name) pixel_data = image.pixel_data labels = workspace.interaction_request(self, pixel_data) objects = cpo.Objects() objects.segmented = labels workspace.object_set.add_objects(objects, objects_name) ################## # # Add measurements # m = workspace.measurements # # The object count # object_count = np.max(labels) I.add_object_count_measurements(m, objects_name, object_count) # # The object locations # I.add_object_location_measurements(m, objects_name, labels) # # Outlines if we want them # if self.wants_outlines: outlines_name = self.outlines_name.value outlines = outline(labels) outlines_image = cpi.Image(outlines.astype(bool)) workspace.image_set.add(outlines_name, outlines_image) workspace.display_data.labels = labels workspace.display_data.pixel_data = pixel_data
def draw_outlines(self, pixel_data, labels): '''Draw a color image that shows the objects pixel_data - image, either b & w or color labels - labels for image returns - color image of same size as pixel_data ''' from cellprofiler.gui.cpfigure import renumber_labels_for_display import matplotlib labels = renumber_labels_for_display(labels) outlines = outline(labels) if pixel_data.ndim == 3: image = pixel_data.copy() else: image = np.dstack([pixel_data]*3) # # make labeled pixels a grayscale times the label color # cm = matplotlib.cm.get_cmap(cpprefs.get_default_colormap()) sm = matplotlib.cm.ScalarMappable(cmap = cm) labels_image = sm.to_rgba(labels)[:,:,:3] lmask = labels > 0 gray = (image[lmask,0] + image[lmask,1] + image[lmask,2]) / 3 for i in range(3): image[lmask,i] = gray * labels_image[lmask, i] # # Make the outline pixels a solid color # outlines_image = sm.to_rgba(outlines)[:,:,:3] image[outlines > 0,:] = outlines_image[outlines > 0,:] return image
def calculate_minimum_distances(self, workspace, parent_name): '''Calculate the distance from child center to parent perimeter''' meas = workspace.measurements assert isinstance(meas, cpmeas.Measurements) sub_object_name = self.sub_object_name.value parents = workspace.object_set.get_objects(parent_name) children = workspace.object_set.get_objects(sub_object_name) parents_of = self.get_parents_of(workspace, parent_name) if len(parents_of) == 0: dist = np.zeros((0, )) elif np.all(parents_of == 0): dist = np.array([np.NaN] * len(parents_of)) else: mask = parents_of > 0 ccenters = centers_of_labels(children.segmented).transpose() ccenters = ccenters[mask, :] parents_of_masked = parents_of[mask] - 1 pperim = outline(parents.segmented) # # Get a list of all points on the perimeter # perim_loc = np.argwhere(pperim != 0) # # Get the label # for each point # perim_idx = pperim[perim_loc[:, 0], perim_loc[:, 1]] # # Sort the points by label # # idx = np.lexsort((perim_loc[:, 1], perim_loc[:, 0], perim_idx)) perim_loc = perim_loc[idx, :] perim_idx = perim_idx[idx] # # Get counts and indexes to each run of perimeter points # counts = fix( scind.sum(np.ones(len(perim_idx)), perim_idx, np.arange(1, perim_idx[-1] + 1))).astype(np.int32) indexes = np.cumsum(counts) - counts # # For the children, get the index and count of the parent # ccounts = counts[parents_of_masked] cindexes = indexes[parents_of_masked] # # Now make an array that has an element for each of that child's # perimeter points # clabel = np.zeros(np.sum(ccounts), int) # # cfirst is the eventual first index of each child in the # clabel array # cfirst = np.cumsum(ccounts) - ccounts clabel[cfirst[1:]] += 1 clabel = np.cumsum(clabel) # # Make an index that runs from 0 to ccounts for each # child label. # cp_index = np.arange(len(clabel)) - cfirst[clabel] # # then add cindexes to get an index to the perimeter point # cp_index += cindexes[clabel] # # Now, calculate the distance from the centroid of each label # to each perimeter point in the parent. # dist = np.sqrt( np.sum((perim_loc[cp_index, :] - ccenters[clabel, :])**2, 1)) # # Finally, find the minimum distance per child # min_dist = fix(scind.minimum(dist, clabel, np.arange(len(ccounts)))) # # Account for unparented children # dist = np.array([np.NaN] * len(mask)) dist[mask] = min_dist meas.add_measurement(sub_object_name, FF_MINIMUM % parent_name, dist)
def run(self, workspace): '''Run the module on an image set''' object_name = self.object_name.value remaining_object_name = self.remaining_objects.value original_objects = workspace.object_set.get_objects(object_name) if self.mask_choice == MC_IMAGE: mask = workspace.image_set.get_image(self.masking_image.value, must_be_binary = True) mask = mask.pixel_data else: masking_objects = workspace.object_set.get_objects( self.masking_objects.value) mask = masking_objects.segmented > 0 if self.wants_inverted_mask: mask = ~mask # # Load the labels # labels = original_objects.segmented.copy() nobjects = np.max(labels) # # Resize the mask to cover the objects # mask, m1 = cpo.size_similarly(labels, mask) mask[~m1] = False # # Apply the mask according to the overlap choice. # if nobjects == 0: pass elif self.overlap_choice == P_MASK: labels = labels * mask else: pixel_counts = fix(scind.sum(mask, labels, np.arange(1, nobjects+1,dtype=np.int32))) if self.overlap_choice == P_KEEP: keep = pixel_counts > 0 else: total_pixels = fix(scind.sum(np.ones(labels.shape), labels, np.arange(1, nobjects+1,dtype=np.int32))) if self.overlap_choice == P_REMOVE: keep = pixel_counts == total_pixels elif self.overlap_choice == P_REMOVE_PERCENTAGE: fraction = self.overlap_fraction.value keep = pixel_counts / total_pixels >= fraction else: raise NotImplementedError("Unknown overlap-handling choice: %s", self.overlap_choice.value) keep = np.hstack(([False], keep)) labels[~ keep[labels]] = 0 # # Renumber the labels matrix if requested # if self.retain_or_renumber == R_RENUMBER: unique_labels = np.unique(labels[labels!=0]) indexer = np.zeros(nobjects+1, int) indexer[unique_labels] = np.arange(1, len(unique_labels)+1) labels = indexer[labels] parent_objects = unique_labels else: parent_objects = np.arange(1, nobjects+1) # # Add the objects # remaining_objects = cpo.Objects() remaining_objects.segmented = labels remaining_objects.unedited_segmented = original_objects.unedited_segmented workspace.object_set.add_objects(remaining_objects, remaining_object_name) # # Add measurements # m = workspace.measurements m.add_measurement(remaining_object_name, I.FF_PARENT % object_name, parent_objects) if np.max(original_objects.segmented) == 0: child_count = np.array([],int) else: child_count = fix(scind.sum(labels, original_objects.segmented, np.arange(1, nobjects+1,dtype=np.int32))) child_count = (child_count > 0).astype(int) m.add_measurement(object_name, I.FF_CHILDREN_COUNT % remaining_object_name, child_count) if self.retain_or_renumber == R_RETAIN: remaining_object_count = nobjects else: remaining_object_count = len(unique_labels) I.add_object_count_measurements(m, remaining_object_name, remaining_object_count) I.add_object_location_measurements(m, remaining_object_name, labels) # # Add an outline if asked to do so # if self.wants_outlines.value: outline_image = cpi.Image(outline(labels) > 0, parent_image = original_objects.parent_image) workspace.image_set.add(self.outlines_name.value, outline_image) # # Save the input, mask and output images for display # if self.show_window: workspace.display_data.original_labels = original_objects.segmented workspace.display_data.final_labels = labels workspace.display_data.mask = mask
def run(self, workspace): """Run the module on the current data set workspace - has the current image set, object set, measurements and the parent frame for the application if the module is allowed to display. If the module should not display, workspace.frame is None. """ # # The object set holds "objects". Each of these is a container # for holding up to three kinds of image labels. # object_set = workspace.object_set # # Get the primary objects (the centers to be removed). # Get the string value out of primary_object_name. # primary_objects = object_set.get_objects( self.primary_objects_name.value) # # Get the cleaned-up labels image # primary_labels = primary_objects.segmented # # Do the same with the secondary object secondary_objects = object_set.get_objects( self.secondary_objects_name.value) secondary_labels = secondary_objects.segmented # # If one of the two label images is smaller than the other, we # try to find the cropping mask and we apply that mask to the larger # try: if any([ p_size < s_size for p_size, s_size in zip( primary_labels.shape, secondary_labels.shape) ]): # # Look for a cropping mask associated with the primary_labels # and apply that mask to resize the secondary labels # secondary_labels = primary_objects.crop_image_similarly( secondary_labels) tertiary_image = primary_objects.parent_image elif any([ p_size > s_size for p_size, s_size in zip( primary_labels.shape, secondary_labels.shape) ]): primary_labels = secondary_objects.crop_image_similarly( primary_labels) tertiary_image = secondary_objects.parent_image elif secondary_objects.parent_image != None: tertiary_image = secondary_objects.parent_image else: tertiary_image = primary_objects.parent_image except ValueError: # No suitable cropping - resize all to fit the secondary # labels which are the most critical. # primary_labels, _ = cpo.size_similarly(secondary_labels, primary_labels) if secondary_objects.parent_image != None: tertiary_image = secondary_objects.parent_image else: tertiary_image = primary_objects.parent_image if tertiary_image is not None: tertiary_image, _ = cpo.size_similarly( secondary_labels, tertiary_image) # # Find the outlines of the primary image and use this to shrink the # primary image by one. This guarantees that there is something left # of the secondary image after subtraction # primary_outline = outline(primary_labels) tertiary_labels = secondary_labels.copy() if self.shrink_primary: primary_mask = np.logical_or(primary_labels == 0, primary_outline) else: primary_mask = primary_labels == 0 tertiary_labels[primary_mask == False] = 0 # # Get the outlines of the tertiary image # tertiary_outlines = outline(tertiary_labels) != 0 # # Make the tertiary objects container # tertiary_objects = cpo.Objects() tertiary_objects.segmented = tertiary_labels tertiary_objects.parent_image = tertiary_image # # Relate tertiary objects to their parents & record # child_count_of_secondary, secondary_parents = \ secondary_objects.relate_children(tertiary_objects) if self.shrink_primary: child_count_of_primary, primary_parents = \ primary_objects.relate_children(tertiary_objects) else: # Primary and tertiary don't overlap. If tertiary object # disappeared, have primary disavow knowledge of it. child_count_of_primary = np.zeros(primary_objects.count) child_count_of_primary[tertiary_objects.areas > 0] = 1 primary_parents = np.arange(1, tertiary_objects.count + 1) # # Write out the objects # workspace.object_set.add_objects(tertiary_objects, self.subregion_objects_name.value) # # Write out the measurements # m = workspace.measurements # # The parent/child associations # for parent_objects_name, parents_of, child_count\ in ((self.primary_objects_name, primary_parents,child_count_of_primary), (self.secondary_objects_name, secondary_parents, child_count_of_secondary)): m.add_measurement(self.subregion_objects_name.value, cpmi.FF_PARENT % (parent_objects_name.value), parents_of) m.add_measurement( parent_objects_name.value, cpmi.FF_CHILDREN_COUNT % (self.subregion_objects_name.value), child_count) object_count = tertiary_objects.count # # The object count # cpmi.add_object_count_measurements(workspace.measurements, self.subregion_objects_name.value, object_count) # # The object locations # cpmi.add_object_location_measurements( workspace.measurements, self.subregion_objects_name.value, tertiary_labels) # # The outlines # if self.use_outlines.value: out_img = cpi.Image(tertiary_outlines.astype(bool), parent_image=tertiary_image) workspace.image_set.add(self.outlines_name.value, out_img) if self.show_window: workspace.display_data.primary_labels = primary_labels workspace.display_data.secondary_labels = secondary_labels workspace.display_data.tertiary_labels = tertiary_labels workspace.display_data.tertiary_outlines = tertiary_outlines
def test_00_00_zeros(self): x = numpy.zeros((10,10),int) result = OL.outline(x) self.assertTrue(numpy.all(x==result))
def run(self, workspace): assert isinstance(workspace, cpw.Workspace) image_name = self.image_name.value image = workspace.image_set.get_image(image_name, must_be_grayscale=True) workspace.display_data.statistics = [] img = image.pixel_data mask = image.mask objects = workspace.object_set.get_objects(self.primary_objects.value) global_threshold = None if self.method == M_DISTANCE_N: has_threshold = False else: thresholded_image = self.threshold_image(image_name, workspace) has_threshold = True # # Get the following labels: # * all edited labels # * labels touching the edge, including small removed # labels_in = objects.unedited_segmented.copy() labels_touching_edge = np.hstack( (labels_in[0, :], labels_in[-1, :], labels_in[:, 0], labels_in[:, -1])) labels_touching_edge = np.unique(labels_touching_edge) is_touching = np.zeros(np.max(labels_in) + 1, bool) is_touching[labels_touching_edge] = True is_touching = is_touching[labels_in] labels_in[(~is_touching) & (objects.segmented == 0)] = 0 # # Stretch the input labels to match the image size. If there's no # label matrix, then there's no label in that area. # if tuple(labels_in.shape) != tuple(img.shape): tmp = np.zeros(img.shape, labels_in.dtype) i_max = min(img.shape[0], labels_in.shape[0]) j_max = min(img.shape[1], labels_in.shape[1]) tmp[:i_max, :j_max] = labels_in[:i_max, :j_max] labels_in = tmp if self.method in (M_DISTANCE_B, M_DISTANCE_N): if self.method == M_DISTANCE_N: distances, (i, j) = scind.distance_transform_edt( labels_in == 0, return_indices=True) labels_out = np.zeros(labels_in.shape, int) dilate_mask = distances <= self.distance_to_dilate.value labels_out[dilate_mask] =\ labels_in[i[dilate_mask],j[dilate_mask]] else: labels_out, distances = propagate(img, labels_in, thresholded_image, 1.0) labels_out[distances > self.distance_to_dilate.value] = 0 labels_out[labels_in > 0] = labels_in[labels_in > 0] if self.fill_holes: small_removed_segmented_out = fill_labeled_holes(labels_out) else: small_removed_segmented_out = labels_out # # Create the final output labels by removing labels in the # output matrix that are missing from the segmented image # segmented_labels = objects.segmented segmented_out = self.filter_labels(small_removed_segmented_out, objects, workspace) elif self.method == M_PROPAGATION: labels_out, distance = propagate(img, labels_in, thresholded_image, self.regularization_factor.value) if self.fill_holes: small_removed_segmented_out = fill_labeled_holes(labels_out) else: small_removed_segmented_out = labels_out.copy() segmented_out = self.filter_labels(small_removed_segmented_out, objects, workspace) elif self.method == M_WATERSHED_G: # # First, apply the sobel filter to the image (both horizontal # and vertical). The filter measures gradient. # sobel_image = np.abs(scind.sobel(img)) # # Combine the image mask and threshold to mask the watershed # watershed_mask = np.logical_or(thresholded_image, labels_in > 0) watershed_mask = np.logical_and(watershed_mask, mask) # # Perform the first watershed # labels_out = watershed(sobel_image, labels_in, np.ones((3, 3), bool), mask=watershed_mask) if self.fill_holes: small_removed_segmented_out = fill_labeled_holes(labels_out) else: small_removed_segmented_out = labels_out.copy() segmented_out = self.filter_labels(small_removed_segmented_out, objects, workspace) elif self.method == M_WATERSHED_I: # # invert the image so that the maxima are filled first # and the cells compete over what's close to the threshold # inverted_img = 1 - img # # Same as above, but perform the watershed on the original image # watershed_mask = np.logical_or(thresholded_image, labels_in > 0) watershed_mask = np.logical_and(watershed_mask, mask) # # Perform the watershed # labels_out = watershed(inverted_img, labels_in, np.ones((3, 3), bool), mask=watershed_mask) if self.fill_holes: small_removed_segmented_out = fill_labeled_holes(labels_out) else: small_removed_segmented_out = labels_out segmented_out = self.filter_labels(small_removed_segmented_out, objects, workspace) if self.wants_discard_edge and self.wants_discard_primary: # # Make a new primary object # lookup = scind.maximum(segmented_out, objects.segmented, range(np.max(objects.segmented) + 1)) lookup = fix(lookup) lookup[0] = 0 lookup[lookup != 0] = np.arange(np.sum(lookup != 0)) + 1 segmented_labels = lookup[objects.segmented] segmented_out = lookup[segmented_out] new_objects = cpo.Objects() new_objects.segmented = segmented_labels if objects.has_unedited_segmented: new_objects.unedited_segmented = objects.unedited_segmented if objects.has_small_removed_segmented: new_objects.small_removed_segmented = objects.small_removed_segmented new_objects.parent_image = objects.parent_image primary_outline = outline(segmented_labels) if self.wants_primary_outlines: out_img = cpi.Image(primary_outline.astype(bool), parent_image=image) workspace.image_set.add(self.new_primary_outlines_name.value, out_img) else: primary_outline = outline(objects.segmented) secondary_outline = outline(segmented_out) # # Add the objects to the object set # objects_out = cpo.Objects() objects_out.unedited_segmented = small_removed_segmented_out objects_out.small_removed_segmented = small_removed_segmented_out objects_out.segmented = segmented_out objects_out.parent_image = image objname = self.objects_name.value workspace.object_set.add_objects(objects_out, objname) if self.use_outlines.value: out_img = cpi.Image(secondary_outline.astype(bool), parent_image=image) workspace.image_set.add(self.outlines_name.value, out_img) object_count = np.max(segmented_out) # # Add measurements # measurements = workspace.measurements cpmi.add_object_count_measurements(measurements, objname, object_count) cpmi.add_object_location_measurements(measurements, objname, segmented_out) # # Relate the secondary objects to the primary ones and record # the relationship. # children_per_parent, parents_of_children = \ objects.relate_children(objects_out) measurements.add_measurement(self.primary_objects.value, cpmi.FF_CHILDREN_COUNT % objname, children_per_parent) measurements.add_measurement( objname, cpmi.FF_PARENT % self.primary_objects.value, parents_of_children) image_numbers = np.ones(len(parents_of_children), int) *\ measurements.image_set_number mask = parents_of_children > 0 measurements.add_relate_measurement( self.module_num, R_PARENT, self.primary_objects.value, self.objects_name.value, image_numbers[mask], parents_of_children[mask], image_numbers[mask], np.arange(1, len(parents_of_children) + 1)[mask]) # # If primary objects were created, add them # if self.wants_discard_edge and self.wants_discard_primary: workspace.object_set.add_objects( new_objects, self.new_primary_objects_name.value) cpmi.add_object_count_measurements( measurements, self.new_primary_objects_name.value, np.max(new_objects.segmented)) cpmi.add_object_location_measurements( measurements, self.new_primary_objects_name.value, new_objects.segmented) for parent_objects, parent_name, child_objects, child_name in ( (objects, self.primary_objects.value, new_objects, self.new_primary_objects_name.value), (new_objects, self.new_primary_objects_name.value, objects_out, objname)): children_per_parent, parents_of_children = \ parent_objects.relate_children(child_objects) measurements.add_measurement( parent_name, cpmi.FF_CHILDREN_COUNT % child_name, children_per_parent) measurements.add_measurement(child_name, cpmi.FF_PARENT % parent_name, parents_of_children) if self.show_window: object_area = np.sum(segmented_out > 0) workspace.display_data.object_pct = \ 100 * object_area / np.product(segmented_out.shape) workspace.display_data.img = img workspace.display_data.segmented_out = segmented_out workspace.display_data.primary_labels = objects.segmented workspace.display_data.global_threshold = global_threshold workspace.display_data.object_count = object_count
def run(self, workspace): """Run the module workspace - The workspace contains pipeline - instance of cpp for this run image_set - the images in the image set being processed object_set - the objects (labeled masks) in this image set measurements - the measurements for this run frame - the parent frame to whatever frame is created. None means don't draw. """ orig_objects_name = self.object_name.value filtered_objects_name = self.filtered_objects.value orig_objects = workspace.object_set.get_objects(orig_objects_name) assert isinstance(orig_objects, cpo.Objects) orig_labels = [l for l, c in orig_objects.get_labels()] if self.wants_image_display: guide_image = workspace.image_set.get_image(self.image_name.value) guide_image = guide_image.pixel_data if np.any(guide_image != np.min(guide_image)): guide_image = (guide_image - np.min(guide_image)) / (np.max(guide_image) - np.min(guide_image)) else: guide_image = None filtered_labels = workspace.interaction_request( self, orig_labels, guide_image, workspace.measurements.image_set_number) if filtered_labels is None: # Ask whoever is listening to stop doing stuff workspace.cancel_request() # Have to soldier on until the cancel takes effect... filtered_labels = orig_labels # # Renumber objects consecutively if asked to do so # unique_labels = np.unique(np.array(filtered_labels)) unique_labels = unique_labels[unique_labels != 0] object_count = len(unique_labels) if self.renumber_choice == R_RENUMBER: mapping = np.zeros(1 if len(unique_labels) == 0 else np.max(unique_labels)+1, int) mapping[unique_labels] = np.arange(1,object_count + 1) filtered_labels = [mapping[l] for l in filtered_labels] # # Make the objects out of the labels # filtered_objects = cpo.Objects() i, j = np.mgrid[0:filtered_labels[0].shape[0], 0:filtered_labels[0].shape[1]] ijv = np.zeros((0, 3), filtered_labels[0].dtype) for l in filtered_labels: ijv = np.vstack((ijv, np.column_stack((i[l != 0], j[l != 0], l[l != 0])))) filtered_objects.set_ijv(ijv, orig_labels[0].shape) if orig_objects.has_unedited_segmented(): filtered_objects.unedited_segmented = orig_objects.unedited_segmented if orig_objects.parent_image is not None: filtered_objects.parent_image = orig_objects.parent_image workspace.object_set.add_objects(filtered_objects, filtered_objects_name) # # Add parent/child & other measurements # m = workspace.measurements child_count, parents = orig_objects.relate_children(filtered_objects) m.add_measurement(filtered_objects_name, I.FF_PARENT%(orig_objects_name), parents) m.add_measurement(orig_objects_name, I.FF_CHILDREN_COUNT%(filtered_objects_name), child_count) # # The object count # I.add_object_count_measurements(m, filtered_objects_name, object_count) # # The object locations # I.add_object_location_measurements_ijv(m, filtered_objects_name, ijv) # # Outlines if we want them # if self.wants_outlines: outlines_name = self.outlines_name.value outlines = outline(filtered_labels[0]).astype(bool) outlines_image = cpi.Image(outlines) workspace.image_set.add(outlines_name, outlines_image) workspace.display_data.orig_ijv = orig_objects.ijv workspace.display_data.filtered_ijv = filtered_objects.ijv workspace.display_data.shape = orig_labels[0].shape
def run(self, workspace): if self.show_window: workspace.display_data.col_labels = ("Image", "Object", "Feature", "Mean", "Median", "STD") workspace.display_data.statistics = statistics = [] for image_name in [img.name for img in self.images]: image = workspace.image_set.get_image(image_name.value, must_be_grayscale=True) for object_name in [obj.name for obj in self.objects]: # Need to refresh image after each iteration... img = image.pixel_data if image.has_mask: masked_image = img.copy() masked_image[~image.mask] = 0 else: masked_image = img objects = workspace.object_set.get_objects(object_name.value) nobjects = objects.count integrated_intensity = np.zeros((nobjects, )) integrated_intensity_edge = np.zeros((nobjects, )) mean_intensity = np.zeros((nobjects, )) mean_intensity_edge = np.zeros((nobjects, )) std_intensity = np.zeros((nobjects, )) std_intensity_edge = np.zeros((nobjects, )) min_intensity = np.zeros((nobjects, )) min_intensity_edge = np.zeros((nobjects, )) max_intensity = np.zeros((nobjects, )) max_intensity_edge = np.zeros((nobjects, )) mass_displacement = np.zeros((nobjects, )) lower_quartile_intensity = np.zeros((nobjects, )) median_intensity = np.zeros((nobjects, )) mad_intensity = np.zeros((nobjects, )) upper_quartile_intensity = np.zeros((nobjects, )) cmi_x = np.zeros((nobjects, )) cmi_y = np.zeros((nobjects, )) max_x = np.zeros((nobjects, )) max_y = np.zeros((nobjects, )) for labels, lindexes in objects.get_labels(): lindexes = lindexes[lindexes != 0] labels, img = cpo.crop_labels_and_image(labels, img) _, masked_image = cpo.crop_labels_and_image( labels, masked_image) outlines = cpmo.outline(labels) if image.has_mask: _, mask = cpo.crop_labels_and_image(labels, image.mask) masked_labels = labels.copy() masked_labels[~mask] = 0 masked_outlines = outlines.copy() masked_outlines[~mask] = 0 else: masked_labels = labels masked_outlines = outlines lmask = masked_labels > 0 & np.isfinite( img) # Ignore NaNs, Infs has_objects = np.any(lmask) if has_objects: emask = masked_outlines > 0 limg = img[lmask] eimg = img[emask] llabels = labels[lmask] elabels = labels[emask] mesh_y, mesh_x = np.mgrid[0:masked_image.shape[0], 0:masked_image.shape[1]] mesh_x = mesh_x[lmask] mesh_y = mesh_y[lmask] lcount = fix( nd.sum(np.ones(len(limg)), llabels, lindexes)) ecount = fix( nd.sum(np.ones(len(eimg)), elabels, lindexes)) integrated_intensity[lindexes-1] = \ fix(nd.sum(limg, llabels, lindexes)) integrated_intensity_edge[lindexes-1] = \ fix(nd.sum(eimg, elabels, lindexes)) mean_intensity[lindexes-1] = \ integrated_intensity[lindexes-1] / lcount mean_intensity_edge[lindexes-1] = \ integrated_intensity_edge[lindexes-1] / ecount std_intensity[lindexes - 1] = np.sqrt( fix( nd.mean( (limg - mean_intensity[llabels - 1])**2, llabels, lindexes))) std_intensity_edge[lindexes - 1] = np.sqrt( fix( nd.mean((eimg - mean_intensity_edge[elabels - 1])**2, elabels, lindexes))) min_intensity[lindexes - 1] = fix( nd.minimum(limg, llabels, lindexes)) min_intensity_edge[lindexes - 1] = fix( nd.minimum(eimg, elabels, lindexes)) max_intensity[lindexes - 1] = fix( nd.maximum(limg, llabels, lindexes)) max_intensity_edge[lindexes - 1] = fix( nd.maximum(eimg, elabels, lindexes)) # Compute the position of the intensity maximum max_position = np.array(fix( nd.maximum_position(limg, llabels, lindexes)), dtype=int) max_position = np.reshape(max_position, (max_position.shape[0], )) max_x[lindexes - 1] = mesh_x[max_position] max_y[lindexes - 1] = mesh_y[max_position] # The mass displacement is the distance between the center # of mass of the binary image and of the intensity image. The # center of mass is the average X or Y for the binary image # and the sum of X or Y * intensity / integrated intensity cm_x = fix(nd.mean(mesh_x, llabels, lindexes)) cm_y = fix(nd.mean(mesh_y, llabels, lindexes)) i_x = fix(nd.sum(mesh_x * limg, llabels, lindexes)) i_y = fix(nd.sum(mesh_y * limg, llabels, lindexes)) cmi_x[lindexes - 1] = i_x / integrated_intensity[lindexes - 1] cmi_y[lindexes - 1] = i_y / integrated_intensity[lindexes - 1] diff_x = cm_x - cmi_x[lindexes - 1] diff_y = cm_y - cmi_y[lindexes - 1] mass_displacement[lindexes-1] = \ np.sqrt(diff_x * diff_x+diff_y*diff_y) # # Sort the intensities by label, then intensity. # For each label, find the index above and below # the 25%, 50% and 75% mark and take the weighted # average. # order = np.lexsort((limg, llabels)) areas = lcount.astype(int) indices = np.cumsum(areas) - areas for dest, fraction in ((lower_quartile_intensity, 1.0 / 4.0), (median_intensity, 1.0 / 2.0), (upper_quartile_intensity, 3.0 / 4.0)): qindex = indices.astype(float) + areas * fraction qfraction = qindex - np.floor(qindex) qindex = qindex.astype(int) qmask = qindex < indices + areas - 1 qi = qindex[qmask] qf = qfraction[qmask] dest[lindexes[qmask] - 1] = (limg[order[qi]] * (1 - qf) + limg[order[qi + 1]] * qf) # # In some situations (e.g. only 3 points), there may # not be an upper bound. # qmask = (~qmask) & (areas > 0) dest[lindexes[qmask] - 1] = limg[order[qindex[qmask]]] # # Once again, for the MAD # madimg = limg - median_intensity[llabels - 1] order = np.lexsort((limg, llabels)) qindex = indices.astype(float) + areas / 2.0 qfraction = qindex - np.floor(qindex) qindex = qindex.astype(int) qmask = qindex < indices + areas - 1 qi = qindex[qmask] qf = qfraction[qmask] mad_intensity[lindexes[qmask] - 1] = (madimg[order[qi]] * (1 - qf) + madimg[order[qi + 1]] * qf) qmask = (~qmask) & (areas > 0) mad_intensity[lindexes[qmask] - 1] = madimg[order[qindex[qmask]]] m = workspace.measurements for category, feature_name, measurement in \ ((INTENSITY, INTEGRATED_INTENSITY, integrated_intensity), (INTENSITY, MEAN_INTENSITY, mean_intensity), (INTENSITY, STD_INTENSITY, std_intensity), (INTENSITY, MIN_INTENSITY, min_intensity), (INTENSITY, MAX_INTENSITY, max_intensity), (INTENSITY, INTEGRATED_INTENSITY_EDGE, integrated_intensity_edge), (INTENSITY, MEAN_INTENSITY_EDGE, mean_intensity_edge), (INTENSITY, STD_INTENSITY_EDGE, std_intensity_edge), (INTENSITY, MIN_INTENSITY_EDGE, min_intensity_edge), (INTENSITY, MAX_INTENSITY_EDGE, max_intensity_edge), (INTENSITY, MASS_DISPLACEMENT, mass_displacement), (INTENSITY, LOWER_QUARTILE_INTENSITY, lower_quartile_intensity), (INTENSITY, MEDIAN_INTENSITY, median_intensity), (INTENSITY, MAD_INTENSITY, mad_intensity), (INTENSITY, UPPER_QUARTILE_INTENSITY, upper_quartile_intensity), (C_LOCATION, LOC_CMI_X, cmi_x), (C_LOCATION, LOC_CMI_Y, cmi_y), (C_LOCATION, LOC_MAX_X, max_x), (C_LOCATION, LOC_MAX_Y, max_y)): measurement_name = "%s_%s_%s" % (category, feature_name, image_name.value) m.add_measurement(object_name.value, measurement_name, measurement) if self.show_window and len(measurement) > 0: statistics.append( (image_name.value, object_name.value, feature_name, np.round(np.mean(measurement), 3), np.round(np.median(measurement), 3), np.round(np.std(measurement), 3)))
def run(self, workspace): objects = workspace.object_set.get_objects(self.object_name.value) assert isinstance(objects, cpo.Objects) has_pixels = objects.areas > 0 labels = objects.small_removed_segmented kept_labels = objects.segmented neighbor_objects = workspace.object_set.get_objects(self.neighbors_name.value) assert isinstance(neighbor_objects, cpo.Objects) neighbor_labels = neighbor_objects.small_removed_segmented # # Need to add in labels touching border. # unedited_segmented = neighbor_objects.unedited_segmented touching_border = np.zeros(np.max(unedited_segmented) + 1, bool) touching_border[unedited_segmented[0, :]] = True touching_border[unedited_segmented[-1, :]] = True touching_border[unedited_segmented[:, 0]] = True touching_border[unedited_segmented[:, -1]] = True touching_border[0] = False touching_border_mask = touching_border[unedited_segmented] if np.any(touching_border) and \ np.all(~ touching_border_mask[neighbor_labels]): # Add the border labels if any were excluded touching_border_object_number = np.cumsum(touching_border) + \ np.max(neighbor_labels) touching_border_mask = touching_border_mask & neighbor_labels == 0 neighbor_labels[touching_border_mask] = touching_border_object_number[ unedited_segmented[touching_border_mask]] nobjects = np.max(labels) nneighbors = np.max(neighbor_labels) nkept_objects = objects.count _, object_numbers = objects.relate_labels(labels, kept_labels) if self.neighbors_are_objects: neighbor_numbers = object_numbers else: _, neighbor_numbers = neighbor_objects.relate_labels( neighbor_labels, neighbor_objects.segmented) neighbor_count = np.zeros((nobjects,)) pixel_count = np.zeros((nobjects,)) first_object_number = np.zeros((nobjects,),int) second_object_number = np.zeros((nobjects,),int) first_x_vector = np.zeros((nobjects,)) second_x_vector = np.zeros((nobjects,)) first_y_vector = np.zeros((nobjects,)) second_y_vector = np.zeros((nobjects,)) angle = np.zeros((nobjects,)) percent_touching = np.zeros((nobjects,)) expanded_labels = None if self.distance_method == D_EXPAND: # Find the i,j coordinates of the nearest foreground point # to every background point i,j = scind.distance_transform_edt(labels==0, return_distances=False, return_indices=True) # Assign each background pixel to the label of its nearest # foreground pixel. Assign label to label for foreground. labels = labels[i,j] expanded_labels = labels # for display distance = 1 # dilate once to make touching edges overlap scale = S_EXPANDED if self.neighbors_are_objects: neighbor_labels = labels.copy() elif self.distance_method == D_WITHIN: distance = self.distance.value scale = str(distance) elif self.distance_method == D_ADJACENT: distance = 1 scale = S_ADJACENT else: raise ValueError("Unknown distance method: %s" % self.distance_method.value) if nneighbors > (1 if self.neighbors_are_objects else 0): first_objects = [] second_objects = [] object_indexes = np.arange(nobjects, dtype=np.int32)+1 # # First, compute the first and second nearest neighbors, # and the angles between self and the first and second # nearest neighbors # ocenters = centers_of_labels( objects.small_removed_segmented).transpose() ncenters = centers_of_labels( neighbor_objects.small_removed_segmented).transpose() areas = fix(scind.sum(np.ones(labels.shape),labels, object_indexes)) perimeter_outlines = outline(labels) perimeters = fix(scind.sum( np.ones(labels.shape), perimeter_outlines, object_indexes)) i,j = np.mgrid[0:nobjects,0:nneighbors] distance_matrix = np.sqrt((ocenters[i,0] - ncenters[j,0])**2 + (ocenters[i,1] - ncenters[j,1])**2) # # order[:,0] should be arange(nobjects) # order[:,1] should be the nearest neighbor # order[:,2] should be the next nearest neighbor # if distance_matrix.shape[1] == 1: # a little buggy, lexsort assumes that a 2-d array of # second dimension = 1 is a 1-d array order = np.zeros(distance_matrix.shape, int) else: order = np.lexsort([distance_matrix]) first_neighbor = 1 if self.neighbors_are_objects else 0 first_object_index = order[:, first_neighbor] first_x_vector = ncenters[first_object_index,1] - ocenters[:,1] first_y_vector = ncenters[first_object_index,0] - ocenters[:,0] if nneighbors > first_neighbor+1: second_object_index = order[:, first_neighbor + 1] second_x_vector = ncenters[second_object_index,1] - ocenters[:,1] second_y_vector = ncenters[second_object_index,0] - ocenters[:,0] v1 = np.array((first_x_vector,first_y_vector)) v2 = np.array((second_x_vector,second_y_vector)) # # Project the unit vector v1 against the unit vector v2 # dot = (np.sum(v1*v2,0) / np.sqrt(np.sum(v1**2,0)*np.sum(v2**2,0))) angle = np.arccos(dot) * 180. / np.pi # Make the structuring element for dilation strel = strel_disk(distance) # # A little bigger one to enter into the border with a structure # that mimics the one used to create the outline # strel_touching = strel_disk(distance + .5) # # Get the extents for each object and calculate the patch # that excises the part of the image that is "distance" # away i,j = np.mgrid[0:labels.shape[0],0:labels.shape[1]] min_i, max_i, min_i_pos, max_i_pos =\ scind.extrema(i,labels,object_indexes) min_j, max_j, min_j_pos, max_j_pos =\ scind.extrema(j,labels,object_indexes) min_i = np.maximum(fix(min_i)-distance,0).astype(int) max_i = np.minimum(fix(max_i)+distance+1,labels.shape[0]).astype(int) min_j = np.maximum(fix(min_j)-distance,0).astype(int) max_j = np.minimum(fix(max_j)+distance+1,labels.shape[1]).astype(int) # # Loop over all objects # Calculate which ones overlap "index" # Calculate how much overlap there is of others to "index" # for object_number in object_numbers: if object_number == 0: # # No corresponding object in small-removed. This means # that the object has no pixels, e.g. not renumbered. # continue index = object_number - 1 patch = labels[min_i[index]:max_i[index], min_j[index]:max_j[index]] npatch = neighbor_labels[min_i[index]:max_i[index], min_j[index]:max_j[index]] # # Find the neighbors # patch_mask = patch==(index+1) extended = scind.binary_dilation(patch_mask,strel) neighbors = np.unique(npatch[extended]) neighbors = neighbors[neighbors != 0] if self.neighbors_are_objects: neighbors = neighbors[neighbors != object_number] nc = len(neighbors) neighbor_count[index] = nc if nc > 0: first_objects.append(np.ones(nc,int) * object_number) second_objects.append(neighbors) if self.neighbors_are_objects: # # Find the # of overlapping pixels. Dilate the neighbors # and see how many pixels overlap our image. Use a 3x3 # structuring element to expand the overlapping edge # into the perimeter. # outline_patch = perimeter_outlines[ min_i[index]:max_i[index], min_j[index]:max_j[index]] == object_number extended = scind.binary_dilation( (patch != 0) & (patch != object_number), strel_touching) overlap = np.sum(outline_patch & extended) pixel_count[index] = overlap if sum([len(x) for x in first_objects]) > 0: first_objects = np.hstack(first_objects) reverse_object_numbers = np.zeros( max(np.max(object_numbers), np.max(first_objects)) + 1, int) reverse_object_numbers[object_numbers] = np.arange(len(object_numbers)) + 1 first_objects = reverse_object_numbers[first_objects] second_objects = np.hstack(second_objects) reverse_neighbor_numbers = np.zeros( max(np.max(neighbor_numbers), np.max(second_objects)) + 1, int) reverse_neighbor_numbers[neighbor_numbers] = np.arange(len(neighbor_numbers)) + 1 second_objects= reverse_neighbor_numbers[second_objects] to_keep = (first_objects > 0) & (second_objects > 0) first_objects = first_objects[to_keep] second_objects = second_objects[to_keep] else: first_objects = np.zeros(0, int) second_objects = np.zeros(0, int) if self.neighbors_are_objects: percent_touching = pixel_count * 100 / perimeters else: percent_touching = pixel_count * 100.0 / areas object_indexes = object_numbers - 1 neighbor_indexes = neighbor_numbers - 1 # # Have to recompute nearest # first_object_number = np.zeros(nkept_objects, int) second_object_number = np.zeros(nkept_objects, int) if nkept_objects > (1 if self.neighbors_are_objects else 0): di = (ocenters[object_indexes[:, np.newaxis], 0] - ncenters[neighbor_indexes[np.newaxis, :], 0]) dj = (ocenters[object_indexes[:, np.newaxis], 1] - ncenters[neighbor_indexes[np.newaxis, :], 1]) distance_matrix = np.sqrt(di*di + dj*dj) distance_matrix[~ has_pixels, :] = np.inf distance_matrix[:, ~has_pixels] = np.inf # # order[:,0] should be arange(nobjects) # order[:,1] should be the nearest neighbor # order[:,2] should be the next nearest neighbor # order = np.lexsort([distance_matrix]).astype( first_object_number.dtype) if self.neighbors_are_objects: first_object_number[has_pixels] = order[has_pixels,1] + 1 if nkept_objects > 2: second_object_number[has_pixels] = order[has_pixels,2] + 1 else: first_object_number[has_pixels] = order[has_pixels,0] + 1 if nneighbors > 1: second_object_number[has_pixels] = order[has_pixels,1] + 1 else: object_indexes = object_numbers - 1 neighbor_indexes = neighbor_numbers - 1 first_objects = np.zeros(0, int) second_objects = np.zeros(0, int) # # Now convert all measurements from the small-removed to # the final number set. # neighbor_count = neighbor_count[object_indexes] neighbor_count[~ has_pixels] = 0 percent_touching = percent_touching[object_indexes] percent_touching[~ has_pixels] = 0 first_x_vector = first_x_vector[object_indexes] second_x_vector = second_x_vector[object_indexes] first_y_vector = first_y_vector[object_indexes] second_y_vector = second_y_vector[object_indexes] angle = angle[object_indexes] # # Record the measurements # assert(isinstance(workspace, cpw.Workspace)) m = workspace.measurements assert(isinstance(m, cpmeas.Measurements)) image_set = workspace.image_set features_and_data = [ (M_NUMBER_OF_NEIGHBORS, neighbor_count), (M_FIRST_CLOSEST_OBJECT_NUMBER, first_object_number), (M_FIRST_CLOSEST_DISTANCE, np.sqrt(first_x_vector**2+first_y_vector**2)), (M_SECOND_CLOSEST_OBJECT_NUMBER, second_object_number), (M_SECOND_CLOSEST_DISTANCE, np.sqrt(second_x_vector**2+second_y_vector**2)), (M_ANGLE_BETWEEN_NEIGHBORS, angle)] if self.neighbors_are_objects: features_and_data.append((M_PERCENT_TOUCHING, percent_touching)) for feature_name, data in features_and_data: m.add_measurement(self.object_name.value, self.get_measurement_name(feature_name), data) if len(first_objects) > 0: m.add_relate_measurement( self.module_num, cpmeas.NEIGHBORS, self.object_name.value, self.object_name.value if self.neighbors_are_objects else self.neighbors_name.value, m.image_set_number * np.ones(first_objects.shape, int), first_objects, m.image_set_number * np.ones(second_objects.shape, int), second_objects) labels = kept_labels neighbor_count_image = np.zeros(labels.shape,int) object_mask = objects.segmented != 0 object_indexes = objects.segmented[object_mask]-1 neighbor_count_image[object_mask] = neighbor_count[object_indexes] workspace.display_data.neighbor_count_image = neighbor_count_image if self.neighbors_are_objects: percent_touching_image = np.zeros(labels.shape) percent_touching_image[object_mask] = percent_touching[object_indexes] workspace.display_data.percent_touching_image = percent_touching_image image_set = workspace.image_set if self.wants_count_image.value: neighbor_cm_name = self.count_colormap.value neighbor_cm = get_colormap(neighbor_cm_name) sm = matplotlib.cm.ScalarMappable(cmap = neighbor_cm) img = sm.to_rgba(neighbor_count_image)[:,:,:3] img[:,:,0][~ object_mask] = 0 img[:,:,1][~ object_mask] = 0 img[:,:,2][~ object_mask] = 0 count_image = cpi.Image(img, masking_objects = objects) image_set.add(self.count_image_name.value, count_image) else: neighbor_cm_name = cpprefs.get_default_colormap() neighbor_cm = matplotlib.cm.get_cmap(neighbor_cm_name) if self.neighbors_are_objects and self.wants_percent_touching_image: percent_touching_cm_name = self.touching_colormap.value percent_touching_cm = get_colormap(percent_touching_cm_name) sm = matplotlib.cm.ScalarMappable(cmap = percent_touching_cm) img = sm.to_rgba(percent_touching_image)[:,:,:3] img[:,:,0][~ object_mask] = 0 img[:,:,1][~ object_mask] = 0 img[:,:,2][~ object_mask] = 0 touching_image = cpi.Image(img, masking_objects = objects) image_set.add(self.touching_image_name.value, touching_image) else: percent_touching_cm_name = cpprefs.get_default_colormap() percent_touching_cm = matplotlib.cm.get_cmap(percent_touching_cm_name) if self.show_window: workspace.display_data.neighbor_cm_name = neighbor_cm_name workspace.display_data.percent_touching_cm_name = percent_touching_cm_name workspace.display_data.orig_labels = objects.segmented workspace.display_data.expanded_labels = expanded_labels workspace.display_data.object_mask = object_mask
def run(self, workspace): if self.show_window: workspace.display_data.col_labels = ( "Image","Object","Feature","Mean","Median","STD") workspace.display_data.statistics = statistics = [] for image_name in [img.name for img in self.images]: image = workspace.image_set.get_image(image_name.value, must_be_grayscale=True) for object_name in [obj.name for obj in self.objects]: # Need to refresh image after each iteration... img = image.pixel_data if image.has_mask: masked_image = img.copy() masked_image[~image.mask] = 0 else: masked_image = img objects = workspace.object_set.get_objects(object_name.value) nobjects = objects.count integrated_intensity = np.zeros((nobjects,)) integrated_intensity_edge = np.zeros((nobjects,)) mean_intensity = np.zeros((nobjects,)) mean_intensity_edge = np.zeros((nobjects,)) std_intensity = np.zeros((nobjects,)) std_intensity_edge = np.zeros((nobjects,)) min_intensity = np.zeros((nobjects,)) min_intensity_edge = np.zeros((nobjects,)) max_intensity = np.zeros((nobjects,)) max_intensity_edge = np.zeros((nobjects,)) mass_displacement = np.zeros((nobjects,)) lower_quartile_intensity = np.zeros((nobjects,)) median_intensity = np.zeros((nobjects,)) mad_intensity = np.zeros((nobjects,)) upper_quartile_intensity = np.zeros((nobjects,)) cmi_x = np.zeros((nobjects,)) cmi_y = np.zeros((nobjects,)) max_x = np.zeros((nobjects,)) max_y = np.zeros((nobjects,)) for labels, lindexes in objects.get_labels(): lindexes = lindexes[lindexes != 0] labels, img = cpo.crop_labels_and_image(labels, img) _, masked_image = cpo.crop_labels_and_image(labels, masked_image) outlines = cpmo.outline(labels) if image.has_mask: _, mask = cpo.crop_labels_and_image(labels, image.mask) masked_labels = labels.copy() masked_labels[~mask] = 0 masked_outlines = outlines.copy() masked_outlines[~mask] = 0 else: masked_labels = labels masked_outlines = outlines lmask = masked_labels > 0 & np.isfinite(img) # Ignore NaNs, Infs has_objects = np.any(lmask) if has_objects: limg = img[lmask] llabels = labels[lmask] mesh_y, mesh_x = np.mgrid[0:masked_image.shape[0], 0:masked_image.shape[1]] mesh_x = mesh_x[lmask] mesh_y = mesh_y[lmask] lcount = fix(nd.sum(np.ones(len(limg)), llabels, lindexes)) integrated_intensity[lindexes-1] = \ fix(nd.sum(limg, llabels, lindexes)) mean_intensity[lindexes-1] = \ integrated_intensity[lindexes-1] / lcount std_intensity[lindexes-1] = np.sqrt( fix(nd.mean((limg - mean_intensity[llabels-1])**2, llabels, lindexes))) min_intensity[lindexes-1] = fix(nd.minimum(limg, llabels, lindexes)) max_intensity[lindexes-1] = fix( nd.maximum(limg, llabels, lindexes)) # Compute the position of the intensity maximum max_position = np.array( fix(nd.maximum_position(limg, llabels, lindexes)), dtype=int ) max_position = np.reshape( max_position, ( max_position.shape[0], ) ) max_x[lindexes-1] = mesh_x[ max_position ] max_y[lindexes-1] = mesh_y[ max_position ] # The mass displacement is the distance between the center # of mass of the binary image and of the intensity image. The # center of mass is the average X or Y for the binary image # and the sum of X or Y * intensity / integrated intensity cm_x = fix(nd.mean(mesh_x, llabels, lindexes)) cm_y = fix(nd.mean(mesh_y, llabels, lindexes)) i_x = fix(nd.sum(mesh_x * limg, llabels, lindexes)) i_y = fix(nd.sum(mesh_y * limg, llabels, lindexes)) cmi_x[lindexes-1] = i_x / integrated_intensity[lindexes-1] cmi_y[lindexes-1] = i_y / integrated_intensity[lindexes-1] diff_x = cm_x - cmi_x[lindexes-1] diff_y = cm_y - cmi_y[lindexes-1] mass_displacement[lindexes-1] = \ np.sqrt(diff_x * diff_x+diff_y*diff_y) # # Sort the intensities by label, then intensity. # For each label, find the index above and below # the 25%, 50% and 75% mark and take the weighted # average. # order = np.lexsort((limg, llabels)) areas = lcount.astype(int) indices = np.cumsum(areas) - areas for dest, fraction in ( (lower_quartile_intensity, 1.0/4.0), (median_intensity, 1.0/2.0), (upper_quartile_intensity, 3.0/4.0)): qindex = indices.astype(float) + areas * fraction qfraction = qindex - np.floor(qindex) qindex = qindex.astype(int) qmask = qindex < indices + areas-1 qi = qindex[qmask] qf = qfraction[qmask] dest[lindexes[qmask]-1] = ( limg[order[qi]] * (1 - qf) + limg[order[qi + 1]] * qf) # # In some situations (e.g. only 3 points), there may # not be an upper bound. # qmask = (~qmask) & (areas > 0) dest[lindexes[qmask]-1] = limg[order[qindex[qmask]]] # # Once again, for the MAD # madimg = np.abs(limg - median_intensity[llabels-1]) order = np.lexsort((madimg, llabels)) qindex = indices.astype(float) + areas / 2.0 qfraction = qindex - np.floor(qindex) qindex = qindex.astype(int) qmask = qindex < indices + areas-1 qi = qindex[qmask] qf = qfraction[qmask] mad_intensity[lindexes[qmask]-1] = ( madimg[order[qi]] * (1 - qf) + madimg[order[qi + 1]] * qf) qmask = (~qmask) & (areas > 0) mad_intensity[lindexes[qmask]-1] = madimg[order[qindex[qmask]]] emask = masked_outlines > 0 eimg = img[emask] elabels = labels[emask] has_edge = len(eimg) > 0 if has_edge: ecount = fix(nd.sum( np.ones(len(eimg)), elabels, lindexes)) integrated_intensity_edge[lindexes-1] = \ fix(nd.sum(eimg, elabels, lindexes)) mean_intensity_edge[lindexes-1] = \ integrated_intensity_edge[lindexes-1] / ecount std_intensity_edge[lindexes-1] = \ np.sqrt(fix(nd.mean( (eimg - mean_intensity_edge[elabels-1])**2, elabels, lindexes))) min_intensity_edge[lindexes-1] = fix( nd.minimum(eimg, elabels, lindexes)) max_intensity_edge[lindexes-1] = fix( nd.maximum(eimg, elabels, lindexes)) m = workspace.measurements for category, feature_name, measurement in \ ((INTENSITY, INTEGRATED_INTENSITY, integrated_intensity), (INTENSITY, MEAN_INTENSITY, mean_intensity), (INTENSITY, STD_INTENSITY, std_intensity), (INTENSITY, MIN_INTENSITY, min_intensity), (INTENSITY, MAX_INTENSITY, max_intensity), (INTENSITY, INTEGRATED_INTENSITY_EDGE, integrated_intensity_edge), (INTENSITY, MEAN_INTENSITY_EDGE, mean_intensity_edge), (INTENSITY, STD_INTENSITY_EDGE, std_intensity_edge), (INTENSITY, MIN_INTENSITY_EDGE, min_intensity_edge), (INTENSITY, MAX_INTENSITY_EDGE, max_intensity_edge), (INTENSITY, MASS_DISPLACEMENT, mass_displacement), (INTENSITY, LOWER_QUARTILE_INTENSITY, lower_quartile_intensity), (INTENSITY, MEDIAN_INTENSITY, median_intensity), (INTENSITY, MAD_INTENSITY, mad_intensity), (INTENSITY, UPPER_QUARTILE_INTENSITY, upper_quartile_intensity), (C_LOCATION, LOC_CMI_X, cmi_x), (C_LOCATION, LOC_CMI_Y, cmi_y), (C_LOCATION, LOC_MAX_X, max_x), (C_LOCATION, LOC_MAX_Y, max_y)): measurement_name = "%s_%s_%s"%(category,feature_name, image_name.value) m.add_measurement(object_name.value,measurement_name, measurement) if self.show_window and len(measurement) > 0: statistics.append((image_name.value, object_name.value, feature_name, np.round(np.mean(measurement),3), np.round(np.median(measurement),3), np.round(np.std(measurement),3)))
def run(self, workspace): '''Filter objects for this image set, display results''' src_objects = workspace.get_objects(self.object_name.value) if self.mode == MODE_RULES: indexes = self.keep_by_rules(workspace, src_objects) elif self.mode == MODE_MEASUREMENTS: if self.filter_choice in (FI_MINIMAL, FI_MAXIMAL): indexes = self.keep_one(workspace, src_objects) if self.filter_choice in (FI_MINIMAL_PER_OBJECT, FI_MAXIMAL_PER_OBJECT): indexes = self.keep_per_object(workspace, src_objects) if self.filter_choice == FI_LIMITS: indexes = self.keep_within_limits(workspace, src_objects) elif self.mode == MODE_BORDER: indexes = self.discard_border_objects(workspace, src_objects) else: raise ValueError("Unknown filter choice: %s"% self.filter_choice.value) # # Create an array that maps label indexes to their new values # All labels to be deleted have a value in this array of zero # new_object_count = len(indexes) max_label = np.max(src_objects.segmented) label_indexes = np.zeros((max_label+1,),int) label_indexes[indexes] = np.arange(1,new_object_count+1) # # Loop over both the primary and additional objects # object_list = ([(self.object_name.value, self.target_name.value, self.wants_outlines.value, self.outlines_name.value)] + [(x.object_name.value, x.target_name.value, x.wants_outlines.value, x.outlines_name.value) for x in self.additional_objects]) m = workspace.measurements for src_name, target_name, wants_outlines, outlines_name in object_list: src_objects = workspace.get_objects(src_name) target_labels = src_objects.segmented.copy() # # Reindex the labels of the old source image # target_labels[target_labels > max_label] = 0 target_labels = label_indexes[target_labels] # # Make a new set of objects - retain the old set's unedited # segmentation for the new and generally try to copy stuff # from the old to the new. # target_objects = cpo.Objects() target_objects.segmented = target_labels target_objects.unedited_segmented = src_objects.unedited_segmented if src_objects.has_parent_image: target_objects.parent_image = src_objects.parent_image workspace.object_set.add_objects(target_objects, target_name) # # Add measurements for the new objects add_object_count_measurements(m, target_name, new_object_count) add_object_location_measurements(m, target_name, target_labels) # # Relate the old numbering to the new numbering # m.add_measurement(target_name, FF_PARENT%(src_name), np.array(indexes)) # # Count the children (0 / 1) # child_count = (label_indexes[1:] > 0).astype(int) m.add_measurement(src_name, FF_CHILDREN_COUNT % target_name, child_count) # # Add an outline if asked to do so # if wants_outlines: outline_image = cpi.Image(outline(target_labels) > 0, parent_image = target_objects.parent_image) workspace.image_set.add(outlines_name, outline_image) if self.show_window: src_objects = workspace.get_objects(src_name) image_names = \ [image for image in [m.measurement.get_image_name(workspace.pipeline) for m in self.measurements] if image is not None and image in workspace.image_set.get_names()] if len(image_names) == 0: # Measurement isn't image-based if src_objects.has_parent_image: image = src_objects.parent_image.pixel_data else: image = None else: image = workspace.image_set.get_image(image_names[0]).pixel_data workspace.display_data.src_objects_segmented = \ src_objects.segmented workspace.display_data.image_names = image_names workspace.display_data.image = image workspace.display_data.target_objects_segmented = target_objects.segmented
def calculate_minimum_distances(self, workspace, parent_name): '''Calculate the distance from child center to parent perimeter''' meas = workspace.measurements assert isinstance(meas,cpmeas.Measurements) sub_object_name = self.sub_object_name.value parents = workspace.object_set.get_objects(parent_name) children = workspace.object_set.get_objects(sub_object_name) parents_of = self.get_parents_of(workspace, parent_name) if len(parents_of) == 0: dist = np.zeros((0,)) elif np.all(parents_of == 0): dist = np.array([np.NaN] * len(parents_of)) else: mask = parents_of > 0 ccenters = centers_of_labels(children.segmented).transpose() ccenters = ccenters[mask,:] parents_of_masked = parents_of[mask] - 1 pperim = outline(parents.segmented) # # Get a list of all points on the perimeter # perim_loc = np.argwhere(pperim != 0) # # Get the label # for each point # perim_idx = pperim[perim_loc[:,0],perim_loc[:,1]] # # Sort the points by label # # idx = np.lexsort((perim_loc[:,1],perim_loc[:,0],perim_idx)) perim_loc = perim_loc[idx,:] perim_idx = perim_idx[idx] # # Get counts and indexes to each run of perimeter points # counts = fix(scind.sum(np.ones(len(perim_idx)),perim_idx, np.arange(1,perim_idx[-1]+1))).astype(np.int32) indexes = np.cumsum(counts) - counts # # For the children, get the index and count of the parent # ccounts = counts[parents_of_masked] cindexes = indexes[parents_of_masked] # # Now make an array that has an element for each of that child's # perimeter points # clabel = np.zeros(np.sum(ccounts), int) # # cfirst is the eventual first index of each child in the # clabel array # cfirst = np.cumsum(ccounts) - ccounts clabel[cfirst[1:]] += 1 clabel = np.cumsum(clabel) # # Make an index that runs from 0 to ccounts for each # child label. # cp_index = np.arange(len(clabel)) - cfirst[clabel] # # then add cindexes to get an index to the perimeter point # cp_index += cindexes[clabel] # # Now, calculate the distance from the centroid of each label # to each perimeter point in the parent. # dist = np.sqrt(np.sum((perim_loc[cp_index,:] - ccenters[clabel,:])**2,1)) # # Finally, find the minimum distance per child # min_dist = fix(scind.minimum(dist, clabel, np.arange(len(ccounts)))) # # Account for unparented children # dist = np.array([np.NaN] * len(mask)) dist[mask] = min_dist meas.add_measurement(sub_object_name, FF_MINIMUM % parent_name, dist)
def test_02_01_forced_location(self): d = D.DefineGrid() d.ordering.value = D.NUM_BY_COLUMNS # # Grid with x spacing = 10, y spacing = 20 # diameter = 6 gridding =d.build_grid_info(15,25,1,1,25,45,2,2) expected = self.make_rectangular_grid(gridding) i,j = np.mgrid[0:expected.shape[0],0:expected.shape[1]] ispot, jspot = np.mgrid[0:gridding.rows, 0:gridding.columns] y_locations = np.zeros(np.max(gridding.spot_table)+1,int) y_locations[gridding.spot_table.flatten()] = \ gridding.y_locations[ispot.flatten()] x_locations = np.zeros(np.max(gridding.spot_table)+1,int) x_locations[gridding.spot_table.flatten()] =\ gridding.x_locations[jspot.flatten()] idist = (i - y_locations[expected]) jdist = (j - x_locations[expected]) expected[idist**2 + jdist**2 > (float(diameter + 1)/2)**2] = 0 workspace, module = self.make_workspace(gridding) self.assertTrue(isinstance(module, I.IdentifyObjectsInGrid)) module.diameter_choice.value = I.AM_MANUAL module.diameter.value = diameter module.shape_choice.value = I.SHAPE_CIRCLE_FORCED module.wants_outlines.value = True module.run(workspace) labels = workspace.object_set.get_objects(OUTPUT_OBJECTS_NAME).segmented self.assertTrue(np.all(labels == expected[0:labels.shape[0],0:labels.shape[1]])) # # Check measurements # m = workspace.measurements self.assertTrue(isinstance(m, cpmeas.Measurements)) xm = m.get_current_measurement(OUTPUT_OBJECTS_NAME, 'Location_Center_X') self.assertTrue(np.all(xm == x_locations[1:])) ym = m.get_current_measurement(OUTPUT_OBJECTS_NAME, 'Location_Center_Y') self.assertTrue(np.all(ym == y_locations[1:])) count = m.get_current_image_measurement('Count_%s'%OUTPUT_OBJECTS_NAME) self.assertEqual(count, gridding.rows * gridding.columns) columns = module.get_measurement_columns(workspace.pipeline) self.assertEqual(len(columns), 4) count_feature = 'Count_%s'%OUTPUT_OBJECTS_NAME self.assertTrue(all([column[0] == ("Image" if column[1] == count_feature else OUTPUT_OBJECTS_NAME) for column in columns])) self.assertTrue(all([column[1] in ('Location_Center_X','Location_Center_Y', count_feature,'Number_Object_Number') for column in columns])) # # Check the outlines # outlines = workspace.image_set.get_image(OUTLINES_NAME) outlines = outlines.pixel_data expected_outlines = outline(expected) self.assertTrue(np.all(outlines == (expected_outlines[0:outlines.shape[0],0:outlines.shape[1]]>0))) # # Check the measurements # categories = list(module.get_categories(None, OUTPUT_OBJECTS_NAME)) self.assertEqual(len(categories), 2) categories.sort() self.assertEqual(categories[0], "Location") self.assertEqual(categories[1], "Number") categories = module.get_categories(None, cpmeas.IMAGE) self.assertEqual(len(categories), 1) self.assertEqual(categories[0], "Count") measurements = module.get_measurements(None, cpmeas.IMAGE, "Count") self.assertEqual(len(measurements), 1) self.assertEqual(measurements[0], OUTPUT_OBJECTS_NAME) measurements = module.get_measurements(None, OUTPUT_OBJECTS_NAME, "Location") self.assertEqual(len(measurements), 2) self.assertTrue(all(m in ('Center_X','Center_Y') for m in measurements)) self.assertTrue('Center_X' in measurements) self.assertTrue('Center_Y' in measurements) measurements = module.get_measurements(None, OUTPUT_OBJECTS_NAME, "Number") self.assertEqual(len(measurements),1) self.assertEqual(measurements[0], "Object_Number")
def run(self, workspace): """Run the module on the current data set workspace - has the current image set, object set, measurements and the parent frame for the application if the module is allowed to display. If the module should not display, workspace.frame is None. """ # # The object set holds "objects". Each of these is a container # for holding up to three kinds of image labels. # object_set = workspace.object_set # # Get the primary objects (the centers to be removed). # Get the string value out of primary_object_name. # primary_objects = object_set.get_objects(self.primary_objects_name.value) # # Get the cleaned-up labels image # primary_labels = primary_objects.segmented # # Do the same with the secondary object secondary_objects = object_set.get_objects(self.secondary_objects_name.value) secondary_labels = secondary_objects.segmented # # If one of the two label images is smaller than the other, we # try to find the cropping mask and we apply that mask to the larger # try: if any([p_size < s_size for p_size,s_size in zip(primary_labels.shape, secondary_labels.shape)]): # # Look for a cropping mask associated with the primary_labels # and apply that mask to resize the secondary labels # secondary_labels = primary_objects.crop_image_similarly(secondary_labels) tertiary_image = primary_objects.parent_image elif any([p_size > s_size for p_size,s_size in zip(primary_labels.shape, secondary_labels.shape)]): primary_labels = secondary_objects.crop_image_similarly(primary_labels) tertiary_image = secondary_objects.parent_image elif secondary_objects.parent_image is not None: tertiary_image = secondary_objects.parent_image else: tertiary_image = primary_objects.parent_image except ValueError: # No suitable cropping - resize all to fit the secondary # labels which are the most critical. # primary_labels, _ = cpo.size_similarly(secondary_labels, primary_labels) if secondary_objects.parent_image is not None: tertiary_image = secondary_objects.parent_image else: tertiary_image = primary_objects.parent_image if tertiary_image is not None: tertiary_image, _ = cpo.size_similarly(secondary_labels, tertiary_image) # # Find the outlines of the primary image and use this to shrink the # primary image by one. This guarantees that there is something left # of the secondary image after subtraction # primary_outline = outline(primary_labels) tertiary_labels = secondary_labels.copy() if self.shrink_primary: primary_mask = np.logical_or(primary_labels == 0, primary_outline) else: primary_mask = primary_labels == 0 tertiary_labels[primary_mask == False] = 0 # # Get the outlines of the tertiary image # tertiary_outlines = outline(tertiary_labels)!=0 # # Make the tertiary objects container # tertiary_objects = cpo.Objects() tertiary_objects.segmented = tertiary_labels tertiary_objects.parent_image = tertiary_image # # Relate tertiary objects to their parents & record # child_count_of_secondary, secondary_parents = \ secondary_objects.relate_children(tertiary_objects) if self.shrink_primary: child_count_of_primary, primary_parents = \ primary_objects.relate_children(tertiary_objects) else: # Primary and tertiary don't overlap. # Establish overlap between primary and secondary and commute _, secondary_of_primary = \ secondary_objects.relate_children(primary_objects) mask = secondary_of_primary != 0 child_count_of_primary = np.zeros(mask.shape, int) child_count_of_primary[mask] = child_count_of_secondary[ secondary_of_primary[mask] - 1] primary_parents = np.zeros(secondary_parents.shape, secondary_parents.dtype) primary_of_secondary = np.zeros(secondary_objects.count+1, int) primary_of_secondary[secondary_of_primary] = \ np.arange(1, len(secondary_of_primary)+1) primary_of_secondary[0] = 0 primary_parents = primary_of_secondary[secondary_parents] # # Write out the objects # workspace.object_set.add_objects(tertiary_objects, self.subregion_objects_name.value) # # Write out the measurements # m = workspace.measurements # # The parent/child associations # for parent_objects_name, parents_of, child_count, relationship in ( (self.primary_objects_name, primary_parents, child_count_of_primary, R_REMOVED), (self.secondary_objects_name, secondary_parents, child_count_of_secondary, R_PARENT)): m.add_measurement(self.subregion_objects_name.value, cpmi.FF_PARENT%(parent_objects_name.value), parents_of) m.add_measurement(parent_objects_name.value, cpmi.FF_CHILDREN_COUNT%(self.subregion_objects_name.value), child_count) mask = parents_of != 0 image_number = np.ones(np.sum(mask), int) * m.image_set_number child_object_number = np.argwhere(mask).flatten() + 1 parent_object_number = parents_of[mask] m.add_relate_measurement( self.module_num, relationship, parent_objects_name.value, self.subregion_objects_name.value, image_number, parent_object_number, image_number, child_object_number) object_count = tertiary_objects.count # # The object count # cpmi.add_object_count_measurements(workspace.measurements, self.subregion_objects_name.value, object_count) # # The object locations # cpmi.add_object_location_measurements(workspace.measurements, self.subregion_objects_name.value, tertiary_labels) # # The outlines # if self.use_outlines.value: out_img = cpi.Image(tertiary_outlines.astype(bool), parent_image = tertiary_image) workspace.image_set.add(self.outlines_name.value, out_img) if self.show_window: workspace.display_data.primary_labels = primary_labels workspace.display_data.secondary_labels = secondary_labels workspace.display_data.tertiary_labels = tertiary_labels workspace.display_data.tertiary_outlines = tertiary_outlines
def run(self, workspace): objects = workspace.object_set.get_objects(self.object_name.value) assert isinstance(objects, cpo.Objects) has_pixels = objects.areas > 0 labels = objects.small_removed_segmented kept_labels = objects.segmented neighbor_objects = workspace.object_set.get_objects(self.neighbors_name.value) assert isinstance(neighbor_objects, cpo.Objects) neighbor_labels = neighbor_objects.small_removed_segmented # # Need to add in labels touching border. # unedited_segmented = neighbor_objects.unedited_segmented touching_border = np.zeros(np.max(unedited_segmented) + 1, bool) touching_border[unedited_segmented[0, :]] = True touching_border[unedited_segmented[-1, :]] = True touching_border[unedited_segmented[:, 0]] = True touching_border[unedited_segmented[:, -1]] = True touching_border[0] = False touching_border_mask = touching_border[unedited_segmented] nobjects = np.max(labels) nneighbors = np.max(neighbor_labels) nkept_objects = objects.count if np.any(touching_border) and \ np.all(~ touching_border_mask[neighbor_labels!=0]): # Add the border labels if any were excluded touching_border_object_number = np.cumsum(touching_border) + \ np.max(neighbor_labels) touching_border_mask = touching_border_mask & neighbor_labels == 0 neighbor_labels = neighbor_labels.copy().astype(np.int32) neighbor_labels[touching_border_mask] = touching_border_object_number[ unedited_segmented[touching_border_mask]] _, object_numbers = objects.relate_labels(labels, kept_labels) if self.neighbors_are_objects: neighbor_numbers = object_numbers else: _, neighbor_numbers = neighbor_objects.relate_labels( neighbor_labels, neighbor_objects.segmented) neighbor_count = np.zeros((nobjects,)) pixel_count = np.zeros((nobjects,)) first_object_number = np.zeros((nobjects,),int) second_object_number = np.zeros((nobjects,),int) first_x_vector = np.zeros((nobjects,)) second_x_vector = np.zeros((nobjects,)) first_y_vector = np.zeros((nobjects,)) second_y_vector = np.zeros((nobjects,)) angle = np.zeros((nobjects,)) percent_touching = np.zeros((nobjects,)) expanded_labels = None if self.distance_method == D_EXPAND: # Find the i,j coordinates of the nearest foreground point # to every background point i,j = scind.distance_transform_edt(labels==0, return_distances=False, return_indices=True) # Assign each background pixel to the label of its nearest # foreground pixel. Assign label to label for foreground. labels = labels[i,j] expanded_labels = labels # for display distance = 1 # dilate once to make touching edges overlap scale = S_EXPANDED if self.neighbors_are_objects: neighbor_labels = labels.copy() elif self.distance_method == D_WITHIN: distance = self.distance.value scale = str(distance) elif self.distance_method == D_ADJACENT: distance = 1 scale = S_ADJACENT else: raise ValueError("Unknown distance method: %s" % self.distance_method.value) if nneighbors > (1 if self.neighbors_are_objects else 0): first_objects = [] second_objects = [] object_indexes = np.arange(nobjects, dtype=np.int32)+1 # # First, compute the first and second nearest neighbors, # and the angles between self and the first and second # nearest neighbors # ocenters = centers_of_labels( objects.small_removed_segmented).transpose() ncenters = centers_of_labels( neighbor_objects.small_removed_segmented).transpose() areas = fix(scind.sum(np.ones(labels.shape),labels, object_indexes)) perimeter_outlines = outline(labels) perimeters = fix(scind.sum( np.ones(labels.shape), perimeter_outlines, object_indexes)) i,j = np.mgrid[0:nobjects,0:nneighbors] distance_matrix = np.sqrt((ocenters[i,0] - ncenters[j,0])**2 + (ocenters[i,1] - ncenters[j,1])**2) # # order[:,0] should be arange(nobjects) # order[:,1] should be the nearest neighbor # order[:,2] should be the next nearest neighbor # if distance_matrix.shape[1] == 1: # a little buggy, lexsort assumes that a 2-d array of # second dimension = 1 is a 1-d array order = np.zeros(distance_matrix.shape, int) else: order = np.lexsort([distance_matrix]) first_neighbor = 1 if self.neighbors_are_objects else 0 first_object_index = order[:, first_neighbor] first_x_vector = ncenters[first_object_index,1] - ocenters[:,1] first_y_vector = ncenters[first_object_index,0] - ocenters[:,0] if nneighbors > first_neighbor+1: second_object_index = order[:, first_neighbor + 1] second_x_vector = ncenters[second_object_index,1] - ocenters[:,1] second_y_vector = ncenters[second_object_index,0] - ocenters[:,0] v1 = np.array((first_x_vector,first_y_vector)) v2 = np.array((second_x_vector,second_y_vector)) # # Project the unit vector v1 against the unit vector v2 # dot = (np.sum(v1*v2,0) / np.sqrt(np.sum(v1**2,0)*np.sum(v2**2,0))) angle = np.arccos(dot) * 180. / np.pi # Make the structuring element for dilation strel = strel_disk(distance) # # A little bigger one to enter into the border with a structure # that mimics the one used to create the outline # strel_touching = strel_disk(distance + .5) # # Get the extents for each object and calculate the patch # that excises the part of the image that is "distance" # away i,j = np.mgrid[0:labels.shape[0],0:labels.shape[1]] min_i, max_i, min_i_pos, max_i_pos =\ scind.extrema(i,labels,object_indexes) min_j, max_j, min_j_pos, max_j_pos =\ scind.extrema(j,labels,object_indexes) min_i = np.maximum(fix(min_i)-distance,0).astype(int) max_i = np.minimum(fix(max_i)+distance+1,labels.shape[0]).astype(int) min_j = np.maximum(fix(min_j)-distance,0).astype(int) max_j = np.minimum(fix(max_j)+distance+1,labels.shape[1]).astype(int) # # Loop over all objects # Calculate which ones overlap "index" # Calculate how much overlap there is of others to "index" # for object_number in object_numbers: if object_number == 0: # # No corresponding object in small-removed. This means # that the object has no pixels, e.g. not renumbered. # continue index = object_number - 1 patch = labels[min_i[index]:max_i[index], min_j[index]:max_j[index]] npatch = neighbor_labels[min_i[index]:max_i[index], min_j[index]:max_j[index]] # # Find the neighbors # patch_mask = patch==(index+1) extended = scind.binary_dilation(patch_mask,strel) neighbors = np.unique(npatch[extended]) neighbors = neighbors[neighbors != 0] if self.neighbors_are_objects: neighbors = neighbors[neighbors != object_number] nc = len(neighbors) neighbor_count[index] = nc if nc > 0: first_objects.append(np.ones(nc,int) * object_number) second_objects.append(neighbors) if self.neighbors_are_objects: # # Find the # of overlapping pixels. Dilate the neighbors # and see how many pixels overlap our image. Use a 3x3 # structuring element to expand the overlapping edge # into the perimeter. # outline_patch = perimeter_outlines[ min_i[index]:max_i[index], min_j[index]:max_j[index]] == object_number extended = scind.binary_dilation( (patch != 0) & (patch != object_number), strel_touching) overlap = np.sum(outline_patch & extended) pixel_count[index] = overlap if sum([len(x) for x in first_objects]) > 0: first_objects = np.hstack(first_objects) reverse_object_numbers = np.zeros( max(np.max(object_numbers), np.max(first_objects)) + 1, int) reverse_object_numbers[object_numbers] = np.arange(len(object_numbers)) + 1 first_objects = reverse_object_numbers[first_objects] second_objects = np.hstack(second_objects) reverse_neighbor_numbers = np.zeros( max(np.max(neighbor_numbers), np.max(second_objects)) + 1, int) reverse_neighbor_numbers[neighbor_numbers] = np.arange(len(neighbor_numbers)) + 1 second_objects= reverse_neighbor_numbers[second_objects] to_keep = (first_objects > 0) & (second_objects > 0) first_objects = first_objects[to_keep] second_objects = second_objects[to_keep] else: first_objects = np.zeros(0, int) second_objects = np.zeros(0, int) if self.neighbors_are_objects: percent_touching = pixel_count * 100 / perimeters else: percent_touching = pixel_count * 100.0 / areas object_indexes = object_numbers - 1 neighbor_indexes = neighbor_numbers - 1 # # Have to recompute nearest # first_object_number = np.zeros(nkept_objects, int) second_object_number = np.zeros(nkept_objects, int) if nkept_objects > (1 if self.neighbors_are_objects else 0): di = (ocenters[object_indexes[:, np.newaxis], 0] - ncenters[neighbor_indexes[np.newaxis, :], 0]) dj = (ocenters[object_indexes[:, np.newaxis], 1] - ncenters[neighbor_indexes[np.newaxis, :], 1]) distance_matrix = np.sqrt(di*di + dj*dj) distance_matrix[~ has_pixels, :] = np.inf distance_matrix[:, ~has_pixels] = np.inf # # order[:,0] should be arange(nobjects) # order[:,1] should be the nearest neighbor # order[:,2] should be the next nearest neighbor # order = np.lexsort([distance_matrix]).astype( first_object_number.dtype) if self.neighbors_are_objects: first_object_number[has_pixels] = order[has_pixels,1] + 1 if nkept_objects > 2: second_object_number[has_pixels] = order[has_pixels,2] + 1 else: first_object_number[has_pixels] = order[has_pixels,0] + 1 if nneighbors > 1: second_object_number[has_pixels] = order[has_pixels,1] + 1 else: object_indexes = object_numbers - 1 neighbor_indexes = neighbor_numbers - 1 first_objects = np.zeros(0, int) second_objects = np.zeros(0, int) # # Now convert all measurements from the small-removed to # the final number set. # neighbor_count = neighbor_count[object_indexes] neighbor_count[~ has_pixels] = 0 percent_touching = percent_touching[object_indexes] percent_touching[~ has_pixels] = 0 first_x_vector = first_x_vector[object_indexes] second_x_vector = second_x_vector[object_indexes] first_y_vector = first_y_vector[object_indexes] second_y_vector = second_y_vector[object_indexes] angle = angle[object_indexes] # # Record the measurements # assert(isinstance(workspace, cpw.Workspace)) m = workspace.measurements assert(isinstance(m, cpmeas.Measurements)) image_set = workspace.image_set features_and_data = [ (M_NUMBER_OF_NEIGHBORS, neighbor_count), (M_FIRST_CLOSEST_OBJECT_NUMBER, first_object_number), (M_FIRST_CLOSEST_DISTANCE, np.sqrt(first_x_vector**2+first_y_vector**2)), (M_SECOND_CLOSEST_OBJECT_NUMBER, second_object_number), (M_SECOND_CLOSEST_DISTANCE, np.sqrt(second_x_vector**2+second_y_vector**2)), (M_ANGLE_BETWEEN_NEIGHBORS, angle)] if self.neighbors_are_objects: features_and_data.append((M_PERCENT_TOUCHING, percent_touching)) for feature_name, data in features_and_data: m.add_measurement(self.object_name.value, self.get_measurement_name(feature_name), data) if len(first_objects) > 0: m.add_relate_measurement( self.module_num, cpmeas.NEIGHBORS, self.object_name.value, self.object_name.value if self.neighbors_are_objects else self.neighbors_name.value, m.image_set_number * np.ones(first_objects.shape, int), first_objects, m.image_set_number * np.ones(second_objects.shape, int), second_objects) labels = kept_labels neighbor_count_image = np.zeros(labels.shape,int) object_mask = objects.segmented != 0 object_indexes = objects.segmented[object_mask]-1 neighbor_count_image[object_mask] = neighbor_count[object_indexes] workspace.display_data.neighbor_count_image = neighbor_count_image if self.neighbors_are_objects: percent_touching_image = np.zeros(labels.shape) percent_touching_image[object_mask] = percent_touching[object_indexes] workspace.display_data.percent_touching_image = percent_touching_image image_set = workspace.image_set if self.wants_count_image.value: neighbor_cm_name = self.count_colormap.value neighbor_cm = get_colormap(neighbor_cm_name) sm = matplotlib.cm.ScalarMappable(cmap = neighbor_cm) img = sm.to_rgba(neighbor_count_image)[:,:,:3] img[:,:,0][~ object_mask] = 0 img[:,:,1][~ object_mask] = 0 img[:,:,2][~ object_mask] = 0 count_image = cpi.Image(img, masking_objects = objects) image_set.add(self.count_image_name.value, count_image) else: neighbor_cm_name = cpprefs.get_default_colormap() neighbor_cm = matplotlib.cm.get_cmap(neighbor_cm_name) if self.neighbors_are_objects and self.wants_percent_touching_image: percent_touching_cm_name = self.touching_colormap.value percent_touching_cm = get_colormap(percent_touching_cm_name) sm = matplotlib.cm.ScalarMappable(cmap = percent_touching_cm) img = sm.to_rgba(percent_touching_image)[:,:,:3] img[:,:,0][~ object_mask] = 0 img[:,:,1][~ object_mask] = 0 img[:,:,2][~ object_mask] = 0 touching_image = cpi.Image(img, masking_objects = objects) image_set.add(self.touching_image_name.value, touching_image) else: percent_touching_cm_name = cpprefs.get_default_colormap() percent_touching_cm = matplotlib.cm.get_cmap(percent_touching_cm_name) if self.show_window: workspace.display_data.neighbor_cm_name = neighbor_cm_name workspace.display_data.percent_touching_cm_name = percent_touching_cm_name workspace.display_data.orig_labels = objects.segmented workspace.display_data.expanded_labels = expanded_labels workspace.display_data.object_mask = object_mask