def perform_manual_qc(imp, rois, important_channel=1): """given cell rois generated by automatic methods, allow user to delete/add/redraw as appropriate""" for ch in range(imp.getNChannels()): imp.setC(ch + 1) sat_frac = 0.99 if (ch + 1) == important_channel else 0.01 IJ.run(imp, "Enhance Contrast", "saturated={}".format(sat_frac)) imp.setC(important_channel) IJ.setTool("freehand") proceed = False roim = RoiManager() roim.runCommand("Show all with labels") for roi in rois: roim.addRoi(roi) auto_rois_only = rois while not proceed: dialog = NonBlockingGenericDialog("Perform manual segmentation") dialog.setOKLabel("Proceed to next image...") dialog.addMessage("Perform manual correction of segmentation: ") dialog.addMessage( "Draw around cells and add to the region of interest manager (Ctrl+T). " ) dialog.addMessage("Delete and redraw cells as appropriate. ") dialog.addMessage( "Then press \"proceed to next image\" when all cells have been added. " ) dialog.showDialog() if dialog.wasCanceled(): print("Manual segmentation canceled") return auto_rois_only elif dialog.wasOKed(): if roim.getCount() == 0: rois = [] confirm_dialog = GenericDialog("Continue?") confirm_dialog.addMessage( "No rois selected in this FOV. Are you sure you want to proceed?" ) confirm_dialog.setOKLabel("Yes, proceed") confirm_dialog.setCancelLabel("No, not yet") confirm_dialog.showDialog() if confirm_dialog.wasOKed(): proceed = True else: rois = roim.getRoisAsArray() proceed = True roim.reset() roim.close() for ch in range(imp.getNChannels()): imp.setC(ch + 1) IJ.run(imp, "Enhance Contrast", "saturated={}".format(0.35)) imp.setC(important_channel) return rois
def save_etc(imp, info, output_folder): """handle saving output, final labelling and UI of what to do next""" dialog = GenericDialog("Marksl1 cell shape prescreen"); dialog.addChoice("Vessel type: ", info.get_vessel_types(), info.get_vessel_type()); dialog.addStringField("Channel 1 label: ", info.get_ch1_label()); dialog.addStringField("Channel 2 label: ", info.get_ch2_label()); dialog.addStringField("Experiment identifier: ", info.get_experiment_id()); dialog.addStringField("Embryo identifier: ", info.get_embryo_id()); dialog.setOKLabel("Save preprocessing"); dialog.showDialog(); info.set_vessel_type(dialog.getNextChoice()); info.set_ch1_label(dialog.getNextString()); info.set_ch2_label(dialog.getNextString()); info.set_experiment_id(dialog.getNextString()); info.set_embryo_id(dialog.getNextString()); if dialog.wasCanceled(): return "stop"; if dialog.wasOKed(): exsting_files = os.listdir(output_folder); r = re.compile(".*" + info.get_embryo_id() + " " + info.get_vessel_type() + ".*") fns = filter(r.match, exsting_files) numbers = list((int(s) for fn in fns for s in re.findall(r'\b\d+$', os.path.splitext(fn)[0]))); append_digit = (max(numbers) + 1) if numbers else 1; ch1str = (info.get_ch1_label() + " ") if info.get_ch1_label() else ""; ch2str = (info.get_ch2_label() + " ") if info.get_ch2_label() else ""; expstr = (info.get_experiment_id() + " ") if info.get_experiment_id() else ""; file_name = ("Cropped " + ch1str + ch2str + expstr + "e" + str(info.get_embryo_id()) + " " + info.get_vessel_type() + " " + str(append_digit)); FileSaver(imp).saveAsTiff(os.path.join(output_folder, (file_name + ".tif"))); info.save_info_to_json(os.path.join(output_folder, (file_name + ".json"))); continueDialog = YesNoCancelDialog(WM.getCurrentWindow(), "Continue?", "Continue with same input image or a new input image?", "New image...", "Same image"); if continueDialog.cancelPressed(): return "stop"; if continueDialog.yesPressed(): return "continue_newimage"; return "continue_sameimage"; return "stop";
def get_image(info, default_path, used_files): """handle getting image from file""" check_for_file_overlap_OK = False; while not check_for_file_overlap_OK: info.set_input_file_path(file_location_chooser(default_path)); if info.get_input_file_path() in used_files: dlg = GenericDialog("Image already used..."); dlg.addMessage("This image has already been used in this analysis run. \n " + "Continue with this image, or choose a new one?"); dlg.setOKLabel("Continue"); dlg.setCancelLabel("Choose again..."); dlg.showDialog(); check_for_file_overlap_OK = False if dlg.wasCanceled() else True; else: check_for_file_overlap_OK = True; import_opts, info = choose_series(info.get_input_file_path(), info) imps = bf.openImagePlus(import_opts); imp = imps[0]; try: memory_usage = IJ.currentMemory()/IJ.maxMemory(); print("memory usage = " +str(memory_usage)); # arbitrary limit... if memory_usage > 0.95: IJ.run(imp, "8-bit", ""); print("WARNING - IMAGE CONVERTED TO 8 BIT TO CONSERVE MEMORY!"); info.set_metadata_file_path(os.path.splitext(info.get_input_file_path())[0] + ".txt"); metadata = import_iq3_metadata(info.get_metadata_file_path()); IJ.run(imp, "Properties...", "channels=" + str(int(metadata['n_channels'])) + " slices=" + str(int(metadata['z_pixels'])) + " frames=1 unit=" + str(metadata['x_unit']) + " pixel_width=" + str(metadata['x_physical_size']) + " pixel_height=" + str(metadata['y_physical_size']) + " voxel_depth=" + str(metadata['z_extent']/metadata['z_pixels'])); info.set_xy_pixel_size_um(metadata['x_physical_size']); info.set_z_plane_spacing_um(metadata['z_extent']/metadata['z_pixels']); info = parse_info_from_filename(info); except e as Exception: print(e.message); finally: if imp is not None: imp.close(); return imp, info;
def main(): # define here which membrane indices will be used in the analysis, with last index the "control" index membrane_indices = [-1, 0, 1, 3] # for now, work with frontmost open image... imp = IJ.getImage() im_title = imp.getTitle() settings = MembraneEvolutionAnalysisSettings( membrane_indices=membrane_indices) settings.loadPersistedSettings() timestamp = datetime.strftime(datetime.now(), '%Y-%m-%d %H-%M-%S') DirectoryChooser.setDefaultDirectory((settings.output_path)) dc = DirectoryChooser('Select the root folder for saving output') output_root = dc.getDirectory() if output_root is None: raise IOError('no output path chosen') settings.output_path = output_root # get calibration cal = imp.getCalibration() if cal.getTimeUnit() == "sec": cal.setTimeUnit('s') # pop up a dialog prompting for selection of zero time point, frame interval, and time step for analysis time_steps_not_ok = True while time_steps_not_ok: dialog = NonBlockingGenericDialog("Determine time parameters...") dialog.addNumericField("0 timepoint frame (1-index): ", settings.zero_timepoint_frame, 0) dialog.addNumericField("Acquisition time step (s): ", cal.frameInterval, 2) # assume stored in seconds dialog.addNumericField( "Time step for analysis (s): ", cal.frameInterval * settings.analysis_frame_step, 2) dialog.showDialog() if dialog.wasCanceled(): return zero_f = dialog.getNextNumber() acq_t_step = dialog.getNextNumber() analysis_t_step = dialog.getNextNumber() if acq_t_step != 0 and analysis_t_step != 0: analysis_frame_step = analysis_t_step / acq_t_step if round(analysis_frame_step) == analysis_frame_step: time_steps_not_ok = False settings.zero_timepoint_frame = zero_f settings.analysis_frame_step = analysis_frame_step if time_steps_not_ok: warning_dlg = GenericDialog("Error!") warning_dlg.addMessage( "Analysis time step must be an integer multiple of acquisition time steps, and neither should be zero!!" ) warning_dlg.setOKLabel("Try again...") warning_dlg.showDialog() if warning_dlg.wasCanceled(): return start_frame = int(((zero_f - 1) % analysis_frame_step) + 1) end_frame = int(imp.getNFrames() - (imp.getNFrames() - zero_f) % analysis_frame_step) frames = [ f + 1 for f in range(start_frame - 1, end_frame, int(analysis_frame_step)) ] print("frames = " + str(frames)) imp.killRoi() analysis_imp = SubstackMaker().makeSubstack( imp, str(start_frame) + "-" + str(end_frame) + "-" + str(int(analysis_frame_step))) imp.changes = False imp.close() analysis_imp.show() drawn_membranes = [ TimepointsMembranes(input_image_title=im_title, time_point_s=(t - 1) * acq_t_step) for t in frames ] membranes_listener = UpdateRoiImageListener(drawn_membranes) analysis_imp.addImageListener(membranes_listener) # now attach roi listener to store all 0th membranes after showing a waitforuserdialog to prompt continuation IJ.setTool("freeline") for membrane_idx in membrane_indices: # if membrane_idx>50: # IJ.setTool("line"); analysis_imp.killRoi() membranes_listener.resetLastFrame() membranes_listener.setCurrentMembraneIndex(membrane_idx) analysis_imp.setZ(1) continue_dlg = WaitForUserDialog( "Continue?", "Click OK once all the " + str(membrane_idx) + "-index membranes have been drawn") continue_dlg.show() membranes_listener.imageUpdated(analysis_imp) drawn_membranes = membranes_listener.getDrawnMembraneTimepointsList() json_path = os.path.join(output_root, "Membranes " + timestamp + ".json") f = open(json_path, 'w+') try: json.dump(drawn_membranes, f, default=encode_membrane) finally: f.close() # save csv containing mebrane measurements for current membrane index csv_path = os.path.join( output_root, ("Membrane measurements " + timestamp + ".csv")) if membrane_idx == membrane_indices[0]: try: f = open(csv_path, 'wb') writer = csv.writer(f) writer.writerow([ "Membrane index", ("Time point, " + cal.getTimeUnit()), ("Membrane length, " + cal.getUnit()), ("Euclidean length, " + cal.getUnit()), "Membrane sinuoisty" ]) finally: f.close() try: f = open(csv_path, 'ab') writer = csv.writer(f) for mems in drawn_membranes: mem = mems.getMembrane(membrane_idx) if mem is not None: writer.writerow([ membrane_idx, mems.time_point_s, mem.getPathLength() * cal.pixelWidth, mem.getEuclidean() * cal.pixelWidth, mem.getSinuosity() ]) finally: f.close() settings.persistSettings() settings.save_settings() print("Finished getting all membranes with indices " + str(membrane_indices)) analysis_imp.close()
class Colortags: ''' This class handles persistence of the name of different color channels. It instantiates a GUI window to capture and show the color names in use. Other classes such as ColorMerger needs this to determine the color of the channel being processed. ''' def __init__(self): self.window = None self.tags = {} self.prefkeys = ["{0}.{1}".format(SUBKEY, name) for name in COLORS] self.userprefs = Prefs() self.load() while not self.tags: self.edit("Please set at least one colortag.\n\n") def load(self): ''' Tries to load IBPlib colortags from IJ prefs. ''' for i in range(7): storedtags = self.userprefs.getString(".{0}".format(self.prefkeys[i]), "") if not storedtags: continue trimmedtagslist = [t.strip() for t in storedtags.split(",")] self.tags.update({i:trimmedtagslist}) def edit(self, msg=""): ''' Opens the color tags dialog to update color tags ''' self.window = GenericDialog("ColorMerger - Edit color tags") self.window.addMessage("{0}Separate tags with a comma.\nBlank values will be ignored.".format(msg)) for i in range(7): try: self.window.addStringField(COLORS[i], ", ".join(self.tags[i]), 30) except KeyError: self.window.addStringField(COLORS[i], "", 30) self.window.setOKLabel("Save") self.window.showDialog() if self.window.wasOKed(): self.__savetags() self.load() def __validate(self): fields = self.window.getStringFields() newvalues = {} for i in range(len(fields)): txt = fields[i].getText() newvalues.update({i: txt.strip()}) return newvalues def __savetags(self): newvalues = self.__validate() for i, tags in newvalues.items(): key = self.prefkeys[i] self.userprefs.set(key, tags) self.userprefs.savePreferences()