def main(): # ensure consistent preference settings Prefs.blackBackground = False # get locations for previous and new outputs params = Parameters() params.loadLastParams() output_folder_old, output_folder = mbio.rerun_location_chooser( params.input_image_path) params.loadParametersFromJson( os.path.join(output_folder_old, 'parameters used.json')) params.setOutputPath(output_folder) # present user with the familiar setup UI, with options that don't make sense/aren't yet implemented disabled params = mbui.analysis_parameters_gui(rerun_analysis=True, params=params) # get original image file (for overlays etc.) if not os.path.isfile(params.input_image_path): mbui.warning_dialog([ "The original data can't be found at the location specified in saved parameters. ", "(Possibly something as simple as a change in network drive mapping has occurred)", "Please specify the location of the original image file..." ]) params.setInputImagePath( mbio.input_file_location_chooser(params.output_path)) import_opts, params = mbui.choose_series(params.input_image_path, params) imps = bf.openImagePlus(import_opts) imp = imps[0] if imp.getNSlices() > 1: mbui.warning_dialog([ "More than one Z plane detected.", "I will do a maximum projection before proceeding", "Continue?" ]) imp = ZProjector.run(imp, "max all") params = mbio.get_metadata(params) params.setCurvatureLengthUm( round(params.curvature_length_um / params.pixel_physical_size) * params.pixel_physical_size) params.persistParameters() IJ.run(imp, "Set Scale...", "distance=0 known=0 pixel=1 unit=pixel") imp.show() if imp.getNChannels() > 1: imp.setPosition(params.membrane_channel_number, 1, 1) mbui.autoset_zoom(imp) IJ.run("Enhance Contrast", "saturated=0.35") # prompt user to select ROI original_imp = Duplicator().run(imp) _, crop_params = mbui.crop_to_ROI(imp, params) imp.show() if crop_params is not None: params.perform_spatial_crop = True mbui.autoset_zoom(imp) imp.updateAndDraw() review_crop = mb.check_cropping(output_folder_old, params) keep_crop = not review_crop if review_crop: keep_crop = mbui.crop_review() if not keep_crop: imp.changes = False imp.close() imp = original_imp else: original_imp.close() else: original_imp.close() # prompt user to do time cropping imp, start_end_tuple = mbui.time_crop(imp, params) params.setTimeCropStartEnd(start_end_tuple) # import edges membrane_edges = mbio.load_qcd_edges2( os.path.join(output_folder_old, "user_defined_edges.zip")) mbio.save_qcd_edges2(membrane_edges, params.output_path) calculated_objects = CalculatedObjects() calculated_objects.membrane_edges = membrane_edges if params.time_crop_start_end[0] is not None: calculated_objects.timelist = [ idx * params.frame_interval for idx in range(params.time_crop_start_end[0], params.time_crop_start_end[1] + 1) ] else: calculated_objects.timelist = [ idx * params.frame_interval for idx in range(imp.getNFrames()) ] split_channels = mbfs.split_image_plus(imp, params) membrane_channel_imp = split_channels[0] actin_channel_imp = split_channels[1] segmentation_channel_imp = None if params.photobleaching_correction: if os.path.isfile( os.path.join(output_folder_old, 'binary_membrane_stack.tif')): segmentation_binary_path = os.path.join( output_folder_old, 'binary_membrane_stack.tif') segmentation_channel_imp = IJ.openImage(segmentation_binary_path) else: segmentation_channel_imp = split_channels[2] segmentation_channel_imp = mb.make_and_clean_binary( segmentation_channel_imp, params.threshold_method) split_channels[2] = segmentation_channel_imp calculated_objects = mbfs.calculate_outputs(params, calculated_objects, split_channels) # output colormapped images and kymographs fig_imp_list = mbfs.generate_and_save_figures(imp, calculated_objects, params, membrane_channel_imp, segmentation_channel_imp) mbfs.save_csvs(calculated_objects, params) params.saveParametersToJson( os.path.join(params.output_path, "parameters used.json")) imp.changes = False IJ.setTool("zoom") if params.close_on_completion: for fig_imp in fig_imp_list: fig_imp.close() imp.close() return
def generate_edges(imp, params, calculated_objects, repeat_fraction=1): """generate edges automatically, then clean up with user step if necessary""" # binarise/segment extra_prompt_str = "" if params.inner_outer_comparison: if repeat_fraction == 1: extra_prompt_str = " OUTER" params.setOutputPath( os.path.join(os.path.dirname(params.output_path), "outer")) os.mkdir(params.output_path) else: extra_prompt_str = " INNER" params.setOutputPath(os.path.join(params.output_path, "inner")) os.mkdir(params.output_path) anchors = mbui.prompt_for_points( imp, "Select channel + extrema", "Select the membrane-label channel, and position \n" + "exactly TWO points at extremes of" + extra_prompt_str + " membrane", 2) midpoint = mbui.prompt_for_points( imp, "Choose midpoint", "Now select a point halfway between the extremes, distant from \n the membrane in the direction of bleb formation. ", 1) membrane_channel = imp.getChannel() params.setMembraneChannelNumber(membrane_channel) params.persistParameters() params.setManualAnchorMidpoint(midpoint) anchors = mb.order_anchors(anchors, midpoint) params.setManualAnchorPositions(anchors) split_channels = split_image_plus(imp, params) membrane_test_channel_imp = Duplicator().run(split_channels[0]) segmentation_channel_imp = split_channels[-1] # perform binary manipulations segmentation_channel_imp = mb.make_and_clean_binary( segmentation_channel_imp, params.threshold_method) # generate edge - this needs to be looped over slices membrane_edges = [] alternate_edges = [] fixed_anchors_list = [] previous_anchors = [] for fridx in range(0, imp.getNFrames()): imp.setPosition(membrane_channel, 1, fridx + 1) segmentation_channel_imp.setPosition(fridx + 1) # fix anchors: IJ.run(segmentation_channel_imp, "Create Selection", "") roi = segmentation_channel_imp.getRoi() fixed_anchors = mb.fix_anchors_to_membrane(anchors, roi, params) fixed_midpoint = midpoint[0] # evolve anchors... if not params.inner_outer_comparison and not params.constrain_anchors: previous_anchors, anchors = mb.evolve_anchors( previous_anchors, fixed_anchors) # identify which side of the segmented roi to use and perform interpolation/smoothing: membrane_edge, alternate_edge = mb.get_membrane_edge( roi, fixed_anchors, fixed_midpoint) fixed_anchors = mb.order_anchors(fixed_anchors, midpoint) fixed_anchors_list.append(fixed_anchors) membrane_edge = mb.check_edge_order(fixed_anchors, membrane_edge) alternate_edge = mb.check_edge_order(fixed_anchors, alternate_edge) imp.show() imp.setRoi(membrane_edge) IJ.run(imp, "Interpolate", "interval=1.0 smooth adjust") IJ.run(imp, "Fit Spline", "") #membrane_edge = mb.selectionInterpolateAndFitSpline(membrane_edge); membrane_edge = imp.getRoi() imp.setRoi(alternate_edge) IJ.run(imp, "Interpolate", "interval=1.0 smooth adjust") IJ.run(imp, "Fit Spline", "") alternate_edge = imp.getRoi() #alternate_edge = mb.selectionInterpolateAndFitSpline(alternate_edge); membrane_edges.append(membrane_edge) alternate_edges.append(alternate_edge) # perform user QC before saving anything if params.perform_user_qc: imp.hide() if imp.getNFrames() > 1: membrane_edges, fixed_anchors_list = mbui.perform_user_qc( membrane_test_channel_imp, membrane_edges, alternate_edges, fixed_anchors_list, params) else: membrane_edges, fixed_anchors_list = mbui.perform_user_qc( imp, membrane_edges, alternate_edges, fixed_anchors_list, params) imp.show() else: mbio.save_qcd_edges2(membrane_edges, params.output_path) calculated_objects.membrane_edges = membrane_edges calculated_objects.fixed_anchors_list = fixed_anchors_list return calculated_objects, params, split_channels
def perform_user_qc(in_imp, edges, alt_edges, fixed_anchors_list, params): """allow the user to intervene to fix erroneously identified membrane edges""" n_frames = in_imp.getNFrames(); n_channels = in_imp.getNChannels(); output_folder = params.output_path; current_edges = edges; rgbstack = ImageStack(in_imp.getWidth(), in_imp.getHeight()); if n_frames > 1: for tidx in range(n_frames): in_imp.setT(tidx+1); ip = in_imp.getProcessor(); rgbip = ip.convertToRGB(); rgbstack.addSlice(rgbip); else: for cidx in range(n_channels): in_imp.setC(cidx+1); ip = in_imp.getProcessor(); rgbip = ip.convertToRGB(); rgbstack.addSlice(rgbip); imp = ImagePlus(("RGB " + in_imp.getTitle()), rgbstack); IJ.run("Colors...", "foreground=red background=white selection=yellow"); for tidx in range(imp.getNSlices()): imp.setSlice(tidx+1); for anchor in params.manual_anchor_positions: imp.setRoi(PointRoi(anchor[0], anchor[1])); IJ.run(imp, "Draw", "slice"); imp.show(); autoset_zoom(imp); imp.setPosition(1); imp.setRoi(current_edges[0]); if n_frames > 1: listener = UpdateRoiImageListener(current_edges); imp.addImageListener(listener); IJ.setTool("freeline"); do_flip = True; while do_flip: dialog = NonBlockingGenericDialog("User quality control"); dialog.enableYesNoCancel("Continue", "Flip all edges"); dialog.setCancelLabel("Cancel analysis"); dialog.addMessage("Please redraw the membrane edges as necessary, \n" + "making sure to draw beyond anchor points at either end...\n" + "Click OK when done. "); p = Panel(); but = Button("Flip this edge"); al = Listener(edges, alt_edges, imp); but.addActionListener(al); p.add(but); dialog.addPanel(p); dialog.showDialog(); if dialog.wasCanceled(): raise KeyboardInterrupt("Run canceled"); elif dialog.wasOKed(): do_flip = False; else: print("flip edges"); do_flip = True; if n_frames > 1: imp.removeImageListener(listener); current_edges = alt_edges if (current_edges == edges) else edges; imp.setPosition(1); imp.setRoi(current_edges[0]); if n_frames > 1: listener = UpdateRoiImageListener(current_edges); imp.addImageListener(listener); last_roi = imp.getRoi(); if n_frames > 1: qcd_edges = listener.getRoiList(); if imp.getNFrames() > imp.getNSlices(): qcd_edges[imp.getT() - 1] = last_roi; else: qcd_edges[imp.getZ() - 1] = last_roi; imp.removeImageListener(listener); else: qcd_edges = [last_roi]; mbio.save_qcd_edges2(qcd_edges, output_folder); # next four lines are a quick and dirty hack... if n_frames > 1: nframes = imp.getNFrames() if imp.getNFrames()>imp.getNSlices() else imp.getNSlices(); else: nframes = n_frames; for fridx in range(0, nframes): if (qcd_edges[fridx].getType()==Roi.FREELINE) or (qcd_edges[fridx].getType()==Roi.POLYLINE): if (fridx == 0) or params.constrain_anchors: anchors = params.manual_anchor_positions; else: anchors = fixed_anchors_list[fridx - 1]; fixed_anchors = mb.fix_anchors_to_membrane(anchors, qcd_edges[fridx], params); fixed_anchors = mb.order_anchors(fixed_anchors, params.manual_anchor_midpoint); fixed_anchors_list[fridx] = fixed_anchors; poly = qcd_edges[fridx].getInterpolatedPolygon(0.25, False); polypoints = [(x,y) for x,y in zip(poly.xpoints, poly.ypoints)]; idx = [polypoints.index(fixed_anchors[0]), polypoints.index(fixed_anchors[1])]; idx.sort(); polypoints = polypoints[idx[0]:idx[1]]; newedge = PolygonRoi([x for (x,y) in polypoints], [y for (x,y) in polypoints], Roi.POLYLINE); newedge = mb.check_edge_order(anchors, newedge); imp.setPosition(fridx + 1); imp.setRoi(newedge); IJ.run(imp, "Interpolate", "interval=1.0 smooth adjust"); IJ.run(imp, "Fit Spline", ""); qcd_edges[fridx] = imp.getRoi(); mbio.save_qcd_edges2(qcd_edges, output_folder); imp.changes = False; imp.close(); return qcd_edges, fixed_anchors_list;
def calculate_outputs(params, calculated_objects, split_channels, inner_outer_intensity_data=None, repeat_fraction=1): """generate curvatures, lengths, areas etc.""" membrane_channel_imp = split_channels[0] actin_channel_imp = split_channels[1] segmentation_channel_imp = split_channels[2] # do calculations independent of source of edges actin_profiles = [] curvature_profiles = [] lengths_areas_and_arearois = [ mb.bleb_area(medge, params.manual_anchor_midpoint[0]) for medge in calculated_objects.membrane_edges ] mb_lengths = [ laaroi[0] * params.pixel_physical_size for laaroi in lengths_areas_and_arearois ] full_membrane_lengths = [ params.pixel_physical_size * edge.getLength() for edge in calculated_objects.membrane_edges ] euclidean_membrane_lengths = [ params.pixel_physical_size * mb.vector_length( (edge.getPolygon().xpoints[0], edge.getPolygon().ypoints[0]), (edge.getPolygon().xpoints[-1], edge.getPolygon().ypoints[-1])) for edge in calculated_objects.membrane_edges ] mb_areas = [ laaroi[1] * math.pow(params.pixel_physical_size, 2) for laaroi in lengths_areas_and_arearois ] mb_area_rois = [laaroi[2] for laaroi in lengths_areas_and_arearois] # save membrane channel with original anchors, fixed anchors and membrane edge for assessment of performance mbfig.save_membrane_edge_image(membrane_channel_imp, calculated_objects.fixed_anchors_list, calculated_objects.membrane_edges, mb_area_rois, params) # perform analysis of background regions bg_rois = mb.generate_background_rois(None, params, calculated_objects.membrane_edges, threshold_method='MinError', membrane_imp=membrane_channel_imp) # resegment, allowing more conservative guess at bg region, or... #bg_rois = mb.generate_background_rois(segmentation_channel_imp, params, calculated_objects.membrane_edges); # use existing segmentation # do qc if params.qc_background_rois: bg_rois = mbui.qc_background_regions(actin_channel_imp, bg_rois) mbio.save_qcd_edges2(bg_rois, params.output_path, "background regions.zip") calculated_objects.background_sd_profile = mb.get_stddevs_by_frame_and_region( actin_channel_imp, bg_rois) t0_actin_mean = None for fridx in range(membrane_channel_imp.getNFrames()): # generate curvature - this needs to be looped over slices membrane_edge = calculated_objects.membrane_edges[fridx] curv_profile = mb.calculate_curvature_profile(membrane_edge, params) curvature_profiles.append(curv_profile) # generate actin-channel line profile if actin channel present if actin_channel_imp is None: actin_channel_imp = Duplicator().run(membrane_channel_imp) actin_channel_imp.setPosition(fridx + 1) actin_channel_imp, t0_actin_mean = mb.apply_photobleach_correction_framewise( params, actin_channel_imp, segmentation_channel_imp, t0_value=t0_actin_mean) actin_profile = mb.maximum_line_profile( actin_channel_imp, membrane_edge, int( round(params.intensity_profile_width_um / params.pixel_physical_size))) actin_profiles.append(actin_profile) if params.inner_outer_comparison: mean_intensity = float(sum([a for ( (x, y), a) in actin_profile])) / len(actin_profile) calculated_objects.inner_outer_data.outer_means.append( mean_intensity ) if repeat_fraction == 1 else calculated_objects.inner_outer_data.inner_means.append( mean_intensity) sd = math.sqrt( sum((x - mean_intensity)**2 for ((x, y), a) in actin_profile) / len(actin_profile)) calculated_objects.inner_outer_data.outer_sds.append( sd ) if repeat_fraction == 1 else calculated_objects.inner_outer_data.inner_sds.append( sd) calculated_objects.curvature_profiles = curvature_profiles calculated_objects.actin_profiles = actin_profiles calculated_objects.bleb_perimeter_lengths = mb_lengths calculated_objects.bleb_areas = mb_areas calculated_objects.full_membrane_lengths = full_membrane_lengths calculated_objects.euclidean_membrane_lengths = euclidean_membrane_lengths params.setPhysicalCurvatureUnit(params.pixel_unit + u'\u02C9' + u'\u00B9') return calculated_objects