def display(self, workspace): # # the "figure" is really the frame around the figure. You almost always # use figure.subplot or figure.subplot_imshow to get axes to draw on # so we pretty much ignore the figure. # figure = workspace.create_or_find_figure(subplots=(3,1)) # # Show the user the input image # cimg = (workspace.display_data.input_pixels[:,:,np.newaxis] * np.ones(3)[np.newaxis, np.newaxis, :]) color = cpprefs.get_primary_outline_color() cimg[workspace.display_data.outlines, 0] = float(color[0]) / 255 cimg[workspace.display_data.outlines, 1] = float(color[1]) / 255 cimg[workspace.display_data.outlines, 2] = float(color[2]) / 255 figure.subplot_imshow_color( 0, 0, # show the image in the first row and column cimg, title = self.input_image_name.value) lead_subplot = figure.subplot(0,0) figure.subplot_imshow_labels( 1, 0, # show the image in the first row and second column workspace.display_data.input_labels, title = self.input_objects.value, sharex = lead_subplot, sharey = lead_subplot) figure.subplot_imshow_labels( 2, 0, # show the image in the first row and last column workspace.display_data.output_labels, title = self.output_objects.value, sharex = lead_subplot, sharey = lead_subplot)
def display(self, workspace, figure): from identify import TS_BINARY_IMAGE object_pct = workspace.display_data.object_pct img = workspace.display_data.img primary_outline = workspace.display_data.primary_outline secondary_outline = workspace.display_data.secondary_outline segmented_out = workspace.display_data.segmented_out global_threshold = workspace.display_data.global_threshold object_count = workspace.display_data.object_count statistics = workspace.display_data.statistics if global_threshold is not None: statistics.append(["Threshold","%.3f" % global_threshold]) if object_count > 0: areas = scind.sum(np.ones(segmented_out.shape), segmented_out, np.arange(1, object_count + 1)) areas.sort() low_diameter = (np.sqrt(float(areas[object_count / 10]) / np.pi) * 2) median_diameter = (np.sqrt(float(areas[object_count / 2]) / np.pi) * 2) high_diameter = (np.sqrt(float(areas[object_count * 9 / 10]) / np.pi) * 2) statistics.append(["10th pctile diameter", "%.1f pixels" % (low_diameter)]) statistics.append(["Median diameter", "%.1f pixels" % (median_diameter)]) statistics.append(["90th pctile diameter", "%.1f pixels" % (high_diameter)]) if self.method != M_DISTANCE_N and self.threshold_scope != TS_BINARY_IMAGE: statistics.append(["Thresholding filter size", "%.1f"%(workspace.display_data.threshold_sigma)]) statistics.append(["Area covered by objects", "%.1f %%" % object_pct]) workspace.display_data.statistics = statistics figure.set_subplots((2, 2)) title = "Input image, cycle #%d" % (workspace.measurements.image_number) figure.subplot_imshow_grayscale(0, 0, img, title) figure.subplot_imshow_labels(1, 0, segmented_out, "%s objects" % self.objects_name.value, sharexy = figure.subplot(0, 0)) primary_img = np.dstack((img, img, img)) # # Stretch the outline image to the full scale # primary_img = stretch(primary_img) # Outline the primary objects cpmi.draw_outline(primary_img, primary_outline > 0, cpprefs.get_primary_outline_color()) # Outline the secondary objects cpmi.draw_outline(primary_img, secondary_outline > 0, cpprefs.get_secondary_outline_color()) figure.subplot_imshow(0, 1, primary_img, "%s and %s outlines"%(self.primary_objects.value,self.objects_name.value), normalize=False, sharexy = figure.subplot(0, 0)) figure.subplot_table( 1, 1, [[x[1]] for x in workspace.display_data.statistics], row_labels = [x[0] for x in workspace.display_data.statistics])
def __init__(self, x, y, on_move): self.__selected = False self.__color = cpprefs.get_primary_outline_color() self.__color = np.hstack((self.__color,[255])).astype(float) / 255.0 self.__on_move = on_move super(handle, self).__init__((x-self.width/2, y-self.height/2), self.width, self.height, edgecolor = self.__color, facecolor = "none") self.set_picker(True)
def __init__(self, center, radius): """Draw an ellipse with control points at the ellipse center and a given x and y radius""" self.center_x, self.center_y = center self.radius_x = self.center_x + radius[0] / 2 self.radius_y = self.center_y + radius[1] / 2 color = cpprefs.get_primary_outline_color() color = np.hstack((color, [255])).astype(float) / 255.0 self.ellipse = M.patches.Ellipse(center, self.width, self.height, edgecolor=color, facecolor="none") self.center_handle = handle(self.center_x, self.center_y, self.move_center) self.radius_handle = handle(self.radius_x, self.radius_y, self.move_radius)
def __init__(self, x, y, on_move): x = max(0, min(x, pixel_data.shape[1])) y = max(0, min(y, pixel_data.shape[0])) self.__selected = False self.__color = cpprefs.get_primary_outline_color() self.__color = np.hstack((self.__color,[255])).astype(float) / 255.0 self.__on_move = on_move super(handle, self).__init__((x-self.width/2, y-self.height/2), self.width, self.height, edgecolor = self.__color, facecolor = "none") self.set_picker(True)
def display(self, workspace, figure): """Create an informative display for the module""" import matplotlib 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 # outlines = outline(original_labels) > 0 cm = figure.return_cmap() sm = matplotlib.cm.ScalarMappable(cmap=cm) # # Paint the labels in color # image = sm.to_rgba(final_labels, norm=False)[:, :, :3] image[final_labels == 0, :] = 0 # # Make the mask a dark gray # image[(final_labels == 0) & mask, :] = 0.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()[0:3], float) / 255 final_color = np.array(cpprefs.get_primary_outline_color()[0:3], 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, colormap=sm, ) figure.subplot_imshow_color( 1, 0, image, title=self.remaining_objects.value, sharexy=figure.subplot(0, 0), colormap=sm, )
def display(self, workspace, figure): object_pct = workspace.display_data.object_pct img = workspace.display_data.img primary_outline = workspace.display_data.primary_outline secondary_outline = workspace.display_data.secondary_outline segmented_out = workspace.display_data.segmented_out global_threshold = workspace.display_data.global_threshold object_count = workspace.display_data.object_count statistics = workspace.display_data.statistics if global_threshold is not None: statistics.append(["Threshold","%.3f" % global_threshold]) if object_count > 0: areas = scind.sum(np.ones(segmented_out.shape), segmented_out, np.arange(1, object_count + 1)) areas.sort() low_diameter = (np.sqrt(float(areas[object_count / 10]) / np.pi) * 2) median_diameter = (np.sqrt(float(areas[object_count / 2]) / np.pi) * 2) high_diameter = (np.sqrt(float(areas[object_count * 9 / 10]) / np.pi) * 2) statistics.append(["10th pctile diameter", "%.1f pixels" % (low_diameter)]) statistics.append(["Median diameter", "%.1f pixels" % (median_diameter)]) statistics.append(["90th pctile diameter", "%.1f pixels" % (high_diameter)]) if self.method != M_DISTANCE_N: statistics.append(["Thresholding filter size", "%.1f"%(workspace.display_data.threshold_sigma)]) statistics.append(["Area covered by objects", "%.1f %%" % object_pct]) workspace.display_data.statistics = statistics figure.set_subplots((2, 2)) title = "Input image, cycle #%d" % (workspace.measurements.image_number) figure.subplot_imshow_grayscale(0, 0, img, title) figure.subplot_imshow_labels(1, 0, segmented_out, "%s objects" % self.objects_name.value, sharexy = figure.subplot(0, 0)) primary_img = np.dstack((img, img, img)) cpmi.draw_outline(primary_img, primary_outline > 0, cpprefs.get_primary_outline_color()) cpmi.draw_outline(primary_img, secondary_outline > 0, cpprefs.get_secondary_outline_color()) figure.subplot_imshow(0, 1, primary_img, "%s and %s outlines"%(self.primary_objects.value,self.objects_name.value), normalize=False, sharexy = figure.subplot(0, 0)) figure.subplot_table( 1, 1, [[x[1]] for x in workspace.display_data.statistics], row_labels = [x[0] for x in workspace.display_data.statistics])
def __init__(self, top_left, bottom_right): self.__left, self.__top = top_left self.__right, self.__bottom = bottom_right color = cpprefs.get_primary_outline_color() color = np.hstack((color, [255])).astype(float) / 255.0 self.rectangle = M.patches.Rectangle( (min(self.__left, self.__right), min(self.__bottom, self.__top)), abs(self.__right - self.__left), abs(self.__top - self.__bottom), edgecolor=color, facecolor="none", ) self.top_left_handle = handle(top_left[0], top_left[1], self.handle_top_left) self.bottom_right_handle = handle(bottom_right[0], bottom_right[1], self.handle_bottom_right)
def __init__(self, center, radius): '''Draw an ellipse with control points at the ellipse center and a given x and y radius''' self.center_x, self.center_y = center self.radius_x = self.center_x + radius[0] / 2 self.radius_y = self.center_y + radius[1] / 2 color = cpprefs.get_primary_outline_color() color = np.hstack((color,[255])).astype(float) / 255.0 self.ellipse = M.patches.Ellipse(center, self.width, self.height, edgecolor = color, facecolor = "none") self.center_handle = handle(self.center_x, self.center_y, self.move_center) self.radius_handle = handle(self.radius_x, self.radius_y, self.move_radius)
def display(self, workspace, figure): '''Create an informative display for the module''' import matplotlib from cellprofiler.gui.tools 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 __init__(self, top_left, bottom_right): self.__left, self.__top = top_left self.__right, self.__bottom = bottom_right color = cpprefs.get_primary_outline_color() color = np.hstack((color, [255])).astype(float) / 255.0 self.rectangle = M.patches.Rectangle( (min(self.__left, self.__right), min(self.__bottom, self.__top)), abs(self.__right - self.__left), abs(self.__top - self.__bottom), edgecolor=color, facecolor="none") self.top_left_handle = handle(top_left[0], top_left[1], self.handle_top_left) self.bottom_right_handle = handle(bottom_right[0], bottom_right[1], self.handle_bottom_right)
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 OnPaint(self, event): dc = wx.BufferedPaintDC(self) try: dc.BackgroundMode = wx.SOLID background_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) metadata_color = get_primary_outline_color() selected_background_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT) selected_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) text_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT) dc.Background = wx.Brush(background_color) dc.Font = self.Font dc.Clear() if self.native_border: renderer = wx.RendererNative.Get() style = 0 if self.FindFocus() == self: style |= wx.CONTROL_FOCUSED | wx.CONTROL_CURRENT if not self.Enabled: style |= wx.CONTROL_DISABLED renderer.DrawTextCtrl(self, dc, (0, 0, self.ClientSize[0], self.ClientSize[1]), style) dc.SetClippingRect((self.padding, self.padding, self.ClientSize[0] - 2*self.padding, self.ClientSize[1] - 2*self.padding)) text = self.get_text(0, len(self.__tokens)) positions = self.get_positions(dc) last_state = "unknown" text_list = [] state_list = [] position_list = [] selection = None if self.selection is not None: selection = list(self.selection) selection.sort() for i, token in enumerate(self.__tokens): if isinstance(token, self.MetadataToken): current_state = "metadata" elif (self.selection != None and i >= selection[0] and i < selection[1]): current_state = "selection" else: current_state = "boring" if current_state != last_state: state_list.append(current_state) text_list.append("") last_state = current_state position_list.append((positions[i], self.padding)) text_list[-1] += self.get_text(i, i+1) colors = { "boring": (background_color, text_color), "selection": (selected_background_color, selected_color), "metadata": (metadata_color, text_color) } background_color = [colors[state][0] for state in state_list] foreground_color = [colors[state][1] for state in state_list] dc.BackgroundMode = wx.SOLID for text, position, background, foreground in zip( text_list, position_list, background_color, foreground_color): dc.SetTextBackground(background) dc.SetTextForeground(foreground) dc.DrawText(text, position[0], position[1]) finally: dc.Destroy()
def OnPaint(self, event): dc = wx.BufferedPaintDC(self) try: dc.BackgroundMode = wx.SOLID background_color = wx.SystemSettings_GetColour( wx.SYS_COLOUR_WINDOW) metadata_color = get_primary_outline_color() selected_background_color = wx.SystemSettings_GetColour( wx.SYS_COLOUR_HIGHLIGHT) selected_color = wx.SystemSettings_GetColour( wx.SYS_COLOUR_HIGHLIGHTTEXT) text_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT) dc.Background = wx.Brush(background_color) dc.Font = self.Font dc.Clear() if self.native_border: renderer = wx.RendererNative.Get() style = 0 if self.FindFocus() == self: style |= wx.CONTROL_FOCUSED | wx.CONTROL_CURRENT if not self.Enabled: style |= wx.CONTROL_DISABLED renderer.DrawTextCtrl( self, dc, (0, 0, self.ClientSize[0], self.ClientSize[1]), style) dc.SetClippingRect((self.padding, self.padding, self.ClientSize[0] - 2 * self.padding, self.ClientSize[1] - 2 * self.padding)) text = self.get_text(0, len(self.__tokens)) positions = self.get_positions(dc) last_state = "unknown" text_list = [] state_list = [] position_list = [] selection = None if self.selection is not None: selection = list(self.selection) selection.sort() for i, token in enumerate(self.__tokens): if isinstance(token, self.MetadataToken): current_state = "metadata" elif (self.selection != None and i >= selection[0] and i < selection[1]): current_state = "selection" else: current_state = "boring" if current_state != last_state: state_list.append(current_state) text_list.append("") last_state = current_state position_list.append((positions[i], self.padding)) text_list[-1] += self.get_text(i, i + 1) colors = { "boring": (background_color, text_color), "selection": (selected_background_color, selected_color), "metadata": (metadata_color, text_color) } background_color = [colors[state][0] for state in state_list] foreground_color = [colors[state][1] for state in state_list] dc.BackgroundMode = wx.SOLID for text, position, background, foreground in zip( text_list, position_list, background_color, foreground_color): dc.SetTextBackground(background) dc.SetTextForeground(foreground) dc.DrawText(text, position[0], position[1]) finally: dc.Destroy()
def run(self, workspace): assert isinstance(workspace, cpw.Workspace) image = workspace.image_set.get_image(self.image_name.value, must_be_grayscale = True) 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 elif self.threshold_method == cpthresh.TM_BINARY_IMAGE: binary_image = workspace.image_set.get_image(self.binary_image.value, must_be_binary = True) local_threshold = np.ones(img.shape) * np.max(img) + np.finfo(float).eps local_threshold[binary_image.pixel_data] = np.min(img) - np.finfo(float).eps global_threshold = cellprofiler.cpmath.otsu.otsu(img[mask], self.threshold_range.min, self.threshold_range.max) has_threshold = True else: local_threshold,global_threshold = self.get_threshold(img, mask, None, workspace) has_threshold = True if has_threshold: thresholded_image = img > local_threshold # # 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) if workspace.frame != None: object_area = np.sum(segmented_out > 0) object_pct = 100 * object_area / np.product(segmented_out.shape) my_frame=workspace.create_or_find_figure(title="IdentifySecondaryObjects, image cycle #%d"%( workspace.measurements.image_set_number),subplots=(2,2)) title = "Input image, cycle #%d"%(workspace.image_set.number+1) my_frame.subplot_imshow_grayscale(0, 0, img, title) my_frame.subplot_imshow_labels(1, 0, segmented_out, "Labeled image", sharex = my_frame.subplot(0,0), sharey = my_frame.subplot(0,0)) outline_img = np.dstack((img, img, img)) cpmi.draw_outline(outline_img, secondary_outline > 0, cpprefs.get_secondary_outline_color()) my_frame.subplot_imshow(0, 1, outline_img, "Outlined image", normalize=False, sharex = my_frame.subplot(0,0), sharey = my_frame.subplot(0,0)) primary_img = np.dstack((img, img, img)) cpmi.draw_outline(primary_img, primary_outline > 0, cpprefs.get_primary_outline_color()) cpmi.draw_outline(primary_img, secondary_outline > 0, cpprefs.get_secondary_outline_color()) my_frame.subplot_imshow(1, 1, primary_img, "Primary and output outlines", normalize=False, sharex = my_frame.subplot(0,0), sharey = my_frame.subplot(0,0)) if global_threshold is not None: my_frame.status_bar.SetFields( ["Threshold: %.3f" % global_threshold, "Area covered by objects: %.1f %%" % object_pct]) else: my_frame.status_bar.SetFields( ["Area covered by objects: %.1f %%" % object_pct]) # # 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 the background measurements if made # measurements = workspace.measurements if has_threshold: if isinstance(local_threshold,np.ndarray): ave_threshold = np.mean(local_threshold) else: ave_threshold = local_threshold measurements.add_measurement(cpmeas.IMAGE, cpmi.FF_FINAL_THRESHOLD%(objname), np.array([ave_threshold], dtype=float)) measurements.add_measurement(cpmeas.IMAGE, cpmi.FF_ORIG_THRESHOLD%(objname), np.array([global_threshold], dtype=float)) wv = cpthresh.weighted_variance(img, mask, local_threshold) measurements.add_measurement(cpmeas.IMAGE, cpmi.FF_WEIGHTED_VARIANCE%(objname), np.array([wv],dtype=float)) entropies = cpthresh.sum_of_entropies(img, mask, local_threshold) measurements.add_measurement(cpmeas.IMAGE, cpmi.FF_SUM_OF_ENTROPIES%(objname), np.array([entropies],dtype=float)) 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) # # 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)
def run(self, workspace): assert isinstance(workspace, cpw.Workspace) image = workspace.image_set.get_image(self.image_name.value, must_be_grayscale=True) 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 elif self.threshold_method == cpthresh.TM_BINARY_IMAGE: binary_image = workspace.image_set.get_image( self.binary_image.value, must_be_binary=True) local_threshold = np.ones( img.shape) * np.max(img) + np.finfo(float).eps local_threshold[ binary_image.pixel_data] = np.min(img) - np.finfo(float).eps global_threshold = cellprofiler.cpmath.otsu.otsu( img[mask], self.threshold_range.min, self.threshold_range.max) has_threshold = True else: local_threshold, global_threshold = self.get_threshold( img, mask, None, workspace) has_threshold = True if has_threshold: thresholded_image = img > local_threshold # # 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) if workspace.frame != None: object_area = np.sum(segmented_out > 0) object_pct = 100 * object_area / np.product(segmented_out.shape) my_frame = workspace.create_or_find_figure( title="IdentifySecondaryObjects, image cycle #%d" % (workspace.measurements.image_set_number), subplots=(2, 2)) title = "Input image, cycle #%d" % (workspace.image_set.number + 1) my_frame.subplot_imshow_grayscale(0, 0, img, title) my_frame.subplot_imshow_labels(1, 0, segmented_out, "Labeled image", sharex=my_frame.subplot(0, 0), sharey=my_frame.subplot(0, 0)) outline_img = np.dstack((img, img, img)) cpmi.draw_outline(outline_img, secondary_outline > 0, cpprefs.get_secondary_outline_color()) my_frame.subplot_imshow(0, 1, outline_img, "Outlined image", normalize=False, sharex=my_frame.subplot(0, 0), sharey=my_frame.subplot(0, 0)) primary_img = np.dstack((img, img, img)) cpmi.draw_outline(primary_img, primary_outline > 0, cpprefs.get_primary_outline_color()) cpmi.draw_outline(primary_img, secondary_outline > 0, cpprefs.get_secondary_outline_color()) my_frame.subplot_imshow(1, 1, primary_img, "Primary and output outlines", normalize=False, sharex=my_frame.subplot(0, 0), sharey=my_frame.subplot(0, 0)) if global_threshold is not None: my_frame.status_bar.SetFields([ "Threshold: %.3f" % global_threshold, "Area covered by objects: %.1f %%" % object_pct ]) else: my_frame.status_bar.SetFields( ["Area covered by objects: %.1f %%" % object_pct]) # # 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 the background measurements if made # measurements = workspace.measurements if has_threshold: if isinstance(local_threshold, np.ndarray): ave_threshold = np.mean(local_threshold) else: ave_threshold = local_threshold measurements.add_measurement( cpmeas.IMAGE, cpmi.FF_FINAL_THRESHOLD % (objname), np.array([ave_threshold], dtype=float)) measurements.add_measurement( cpmeas.IMAGE, cpmi.FF_ORIG_THRESHOLD % (objname), np.array([global_threshold], dtype=float)) wv = cpthresh.weighted_variance(img, mask, local_threshold) measurements.add_measurement(cpmeas.IMAGE, cpmi.FF_WEIGHTED_VARIANCE % (objname), np.array([wv], dtype=float)) entropies = cpthresh.sum_of_entropies(img, mask, local_threshold) measurements.add_measurement(cpmeas.IMAGE, cpmi.FF_SUM_OF_ENTROPIES % (objname), np.array([entropies], dtype=float)) 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) # # 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)