class KaryML_Main(BaseWidget): LENGTH_FEATURE = "Chromosome length" AREA_FEATURE = "Chromosome area" CENTROMERIC_INDEX_FEATURE = "Centromeric Index" BANDING_PATTERN_FEATURE = "Banding pattern" FEATURES = [ LENGTH_FEATURE, CENTROMERIC_INDEX_FEATURE, BANDING_PATTERN_FEATURE ] APP_NAME = 'KaryML Framework' def __init__(self): super(KaryML_Main, self).__init__(self.APP_NAME) self._app_title = ControlLabel(self.APP_NAME) self._input_image_path = ControlFile('Input image') self._pairs_path = ControlFile('Expected karyotype (optional)') self._features_label = ControlLabel("Chose features to be extracted") self._f1_check_box = ControlCheckBox(label=self.LENGTH_FEATURE, default=True) self._f1_check_box.changed_event = self._f1_check_box_changed self._f2_check_box = ControlCheckBox(label=self.CENTROMERIC_INDEX_FEATURE, default=True) self._f2_check_box.changed_event = self._f2_check_box_changed self._f3_check_box = ControlCheckBox(label=self.BANDING_PATTERN_FEATURE, default=True) self._f3_check_box.changed_event = self._f3_check_box_changed self._f4_check_box = ControlCheckBox(label=self.AREA_FEATURE, default=True) self._f4_check_box.changed_event = self._f4_check_box_changed self._eu_dist = ControlButton(EUCLIDEAN_DISTANCE) self._we_eu_dist = ControlButton(WEIGHTED_EUCLIDEAN_DISTANCE) self._man_dist = ControlButton(MANHATTAN_DISTANCE) self._dist_label = ControlLabel(label="Distance to use: " + EUCLIDEAN_DISTANCE.upper(), default="Distance to use: " + EUCLIDEAN_DISTANCE) self._f1_w = ControlSlider(label="Chromosome length", default=25, minimum=0, maximum=100, visible=False) self._f2_w = ControlSlider(label=" Centromeric Index", default=25, minimum=0, maximum=100, visible=False) self._f3_w = ControlSlider(label=" Banding pattern", default=25, minimum=0, maximum=100, visible=False) self._f4_w = ControlSlider(label="Chromosome area", default=25, minimum=0, maximum=100, visible=False) self._epochs_no = ControlSlider(label=" Epochs Nr.", default=200000, minimum=50000, maximum=400000) self._rows = ControlSlider(label=" Map rows", default=50, minimum=10, maximum=100) self._cols = ControlSlider(label="Map columns", default=50, minimum=10, maximum=100) self.errors_label_text = ControlLabel(label="Errors:", default="Errors:", visible=True) self.errors_label = ControlLabel(label="Errors", default="", visible=False) self.info_label_text = ControlLabel(label="Info:", default="Info:", visible=True) self.info_label = ControlLabel(label="Info", default="", visible=False) self._button = ControlButton('Start {}'.format(self.APP_NAME)) self._button.value = self._runKarySomAction self._eu_dist.value = self.__dist_changed_eu self._we_eu_dist.value = self.__dist_changed_we_eu self._man_dist.value = self.__dist_changed_man self.t = None @staticmethod def set_message(label, message): label.value = message label.show() def get_number_of_selected_features(self): return len([2 ** j for j in range(4) if [self._f1_check_box, self._f2_check_box, self._f3_check_box, self._f4_check_box][j].value]) def _runKarySomAction(self): """Button action event""" dist_lbl = self.manage_pre_run_gui() self.errors_label.hide() if self.get_number_of_selected_features() < 1: self.set_message(self.errors_label, "At least one feature is required") return cfg = self.__initialize_cfg(dist_lbl) if dist_lbl == WEIGHTED_EUCLIDEAN_DISTANCE and self.get_sum_of_weights() != 100: self.set_message(self.errors_label, "Sum of weights must be 100") return if not os.path.exists(self._input_image_path.value): self.set_message(self.errors_label, "Image path {} doesn't exists".format(self._input_image_path.value)) return print("Start processing using cfg:") pprint.pprint(cfg) self.t = Thread(target=start_process_for_one_image, args=[cfg["input"], cfg["mdist"], "", sum(cfg["features"]), cfg["epochs"], cfg["rows"], cfg["cols"], cfg["weights"], self]) self.t.start() msg = "" if not os.path.isfile(self._pairs_path.value): msg += "Expected karyotype missing or file not exists. PrecKar value won't be calculated." else: msg += "Karyotype file found. Will compute PrecKar value" dir_path = '.'.join(self._input_image_path.value.split('.')[:-1]) if not os.path.isdir(dir_path): os.makedirs(dir_path) shutil.copy2(self._pairs_path.value, os.path.join(dir_path, "pairs.txt")) self.set_message(self.info_label, msg + "\n" + "Start KarySOM for current configuration. Processing...") def manage_pre_run_gui(self): if self.info_label.visible is True: self.info_label.hide() if self._dist_label.value.split()[len(self._dist_label.value.split()) - 2] == "Weighted": dist_lbl = " ".join(self._dist_label.value.split()[len(self._dist_label.value.split()) - 2:]) else: dist_lbl = self._dist_label.value.split()[len(self._dist_label.value.split()) - 1] return dist_lbl def __initialize_cfg(self, dist_lbl): cfg = {"distance": dist_lbl, "feature_names": [self.FEATURES[i] for i in [j for j in range(3) if [self._f1_check_box.value, self._f2_check_box.value, self._f3_check_box.value, self._f4_check_box.value][j]]], "features": [2 ** j for j in range(4) if [self._f1_check_box, self._f2_check_box, self._f3_check_box, self._f4_check_box][j].value], "epochs": self._epochs_no.value, "input": self._input_image_path.value, "pairs": self._pairs_path.value, "rows": self._rows.value, "cols": self._cols.value, "weights": dict()} if self._f1_check_box.value: cfg["weights"][1] = self._f1_w.value / 100 if self._f2_check_box.value: cfg["weights"][2] = self._f2_w.value / 100 if self._f3_check_box.value: cfg["weights"][3] = self._f3_w.value / 100 if self._f4_check_box.value: cfg["weights"][4] = self._f4_w.value / 100 cfg["mdist"] = False if dist_lbl == MANHATTAN_DISTANCE: cfg["mdist"] = True return cfg def __dist_changed_eu(self): self._dist_label.value = "Distance to use: " + EUCLIDEAN_DISTANCE self._dist_label.label = "Distance to use: " + EUCLIDEAN_DISTANCE.upper() self._f1_w.hide() self._f2_w.hide() self._f3_w.hide() self._f4_w.hide() self.info_label.hide() def __dist_changed_we_eu(self): self._dist_label.value = "Distance to use: " + WEIGHTED_EUCLIDEAN_DISTANCE self._dist_label.label = "Distance to use: " + WEIGHTED_EUCLIDEAN_DISTANCE.upper() if self._f1_check_box.value: self._f1_w.show() if self._f2_check_box.value: self._f2_w.show() if self._f3_check_box.value: self._f3_w.show() if self._f4_check_box.value: self._f4_w.show() self.info_label.hide() def __dist_changed_man(self): self._dist_label.value = "Distance to use: " + MANHATTAN_DISTANCE self._dist_label.label = "Distance to use: " + MANHATTAN_DISTANCE.upper() self._f1_w.hide() self._f2_w.hide() self._f3_w.hide() self._f4_w.hide() self.info_label.hide() def get_sum_of_weights(self): weights_sum = 0 if self._f1_check_box.value: weights_sum += self._f1_w.value if self._f2_check_box.value: weights_sum += self._f2_w.value if self._f3_check_box.value: weights_sum += self._f3_w.value if self._f4_check_box.value: weights_sum += self._f4_w.value return weights_sum def _f1_check_box_changed(self): if self._f1_check_box.value and "weighted" in self._dist_label.value.lower(): self._f1_w.show() else: self._f1_w.hide() def _f2_check_box_changed(self): if self._f2_check_box.value and "weighted" in self._dist_label.value.lower(): self._f2_w.show() else: self._f2_w.hide() def _f3_check_box_changed(self): if self._f3_check_box.value and "weighted" in self._dist_label.value.lower(): self._f3_w.show() else: self._f3_w.hide() def _f4_check_box_changed(self): if self._f4_check_box.value and "weighted" in self._dist_label.value.lower(): self._f4_w.show() else: self._f4_w.hide()
class VideosExporterGui(BaseWidget, VideosExporterPreview, VideosExporterProcess): def __init__(self, parent=None): super(VideosExporterGui, self).__init__('Videos exporter', parent_win=parent) self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(400) self._toolbox = ControlToolBox('Tool') self._panel_area = ControlEmptyWidget('Set the object area', default=DatasetsDialog(self)) self._panel_colors = ControlEmptyWidget('Set the object color', default=DatasetsDialog(self)) self._panel_imgs = ControlEmptyWidget('Set the video background', default=ImagesDialog(self)) #### path panel ################################################ self._panel_path = ControlEmptyWidget('Set the object path', default=DatasetsDialog(self)) self._drawpath = ControlCheckBox('Draw paths') ################################################################ #### draw events ############################################### self._drawevents = ControlCheckBoxList('Events') self._eventstitles = ControlCheckBox('Draw titles') self._evtsreload1 = ControlButton('Reload events') ################################################################ #### split by events ########################################### self._splitevents = ControlCheckBoxList('Events') self._evtsreload2 = ControlButton('Reload events') ################################################################ self._codec = ControlCheckBox('Force AVI') self._outdir = ControlDir('Output directory') self._outfile = ControlText('Output file name') self._player = ControlPlayer('Player') self._progress = ControlProgress('Progress') self._apply = ControlButton('Export video(s)', checkable=True) self._apply.icon = conf.ANNOTATOR_ICON_PATH self._apply.enabled = False self._usefixedsize = ControlCheckBox('Use a fixed size') self._usefixedcolor = ControlCheckBox('Use a fixed color') self._radius = ControlSlider('Circle radius', default=10, minimum=1, maximum=300) self._color = ControlText('BGR color', default='255,255,255') self.formset = [('_toolbox', '||', '_player'), '=', '_outdir', ('_outfile', '_codec'), '_apply', '_progress'] self._toolbox.value = [ ('Path', [self._panel_path, self._drawpath]), ('Circle (optional)', [self._panel_area, (self._usefixedsize, self._radius)]), ('Circle color (optional)', [self._panel_colors, (self._usefixedcolor, self._color)]), ('Background (optional)', [self._panel_imgs]), ('Draw events (optional)', [self._evtsreload1, self._drawevents, self._eventstitles]), ('Split files by events (optional)', [self._evtsreload2, self._splitevents]), ] self._panel_path.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) #self._panel_area.value.datasets_filter = lambda x: isinstance(x, Value ) self._panel_colors.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) and hasattr(x, 'has_colors_avg' ) and x.has_colors_avg ### Set the controls events ############################################# self._evtsreload1.value = self.__reload_events self._evtsreload2.value = self.__reload_events self._outfile.changed_event = self.outputfile_changed_event self._usefixedsize.changed_event = self.__usefixedsize_changed_event self._usefixedcolor.changed_event = self.__usefixedcolor_changed_event self._splitevents.selection_changed_event = self.outputfile_changed_event self._panel_path.value.video_selection_changed_event = self.__video_selection_changed_event self._codec.changed_event = self.__video_selection_changed_event ## function from VideosExporterProcess class self._apply.value = self.apply_event ## function from VideosExporterPreview class self._player.process_frame_event = self.player_processframe_event self._evtsreload1.icon = conf.ANNOTATOR_ICON_REFRESH self._evtsreload2.icon = conf.ANNOTATOR_ICON_REFRESH self._progress.hide() self._radius.hide() self._color.hide() self.__check_areatab_event() ########################################################################### ### UTILS ################################################################# ########################################################################### def __reload_events(self): """ Find all the events available on the timeline """ timeline = self.parent().timeline rows = timeline.rows events = {} for row in rows: for event in row.events: events[event.title] = True events = sorted(events.keys()) loaded_events = dict(self._drawevents.items) self._drawevents.value = [(e, loaded_events.get(e, False)) for e in events] loaded_events = dict(self._splitevents.items) self._splitevents.value = [(e, loaded_events.get(e, False)) for e in events] ########################################################################### ### EVENTS ################################################################ ########################################################################### def show(self): """ Load the events when the window is oppened """ super(VideosExporterGui, self).show() self.__reload_events() def __check_areatab_event(self): """ Activate or deactivate the color tab """ if len(list(self._panel_area.value.datasets) ) > 0 or self._usefixedsize.value: self._toolbox.set_item_enabled(2, True) else: self._toolbox.set_item_enabled(2, False) def __usefixedcolor_changed_event(self): if self._usefixedcolor.value: self._color.show() self._panel_colors.hide() else: self._color.hide() self._panel_colors.show() def __usefixedsize_changed_event(self): self.__check_areatab_event() if self._usefixedsize.value: self._radius.show() self._panel_area.hide() else: self._radius.hide() self._panel_area.show() def outputfile_changed_event(self): """ Update the output filename """ filename = self._outfile.value video = self._panel_path.value.selected_video if video is not None: filename = filename if len(filename) > 0 else video.filename videofilepath, video_extension = os.path.splitext(video.filename) outfilepath, outfile_extension = os.path.splitext(filename) names = [outfilepath] if len(outfilepath) > 0 else [] if '{videoindex}' not in outfilepath: names.append('{videoindex}') if len(list(self._splitevents.value)) > 0: if '{event}' not in outfilepath: names.append('{event}') if '{start}' not in outfilepath: names.append('{start}') if '{end}' not in outfilepath: names.append('{end}') self._outfile.value = ('-'.join(names) + video_extension) self._apply.enabled = True else: self._apply.enabled = False def __video_selection_changed_event(self): """ Activate the video preview """ video = self._panel_path.value.selected_video if video is not None: self._player.value = video.video_capture def get_object_area(self, path, areas, index): try: if self._usefixedsize.value: area = (self._radius.value**2 * math.pi) elif len(areas) > 0: a = areas[0] if isinstance(a, Value): area = a.get_value(index) else: area = a.get_area_value(index) else: area = path.get_area_value(index) return area except: return None def get_object_color(self, path, colors, index): try: if self._usefixedcolor.value: color = tuple(eval(self._color.value)) elif len(colors) > 0: color = colors[0].get_color_avg(index) else: color = path.get_color_avg(index) if color is None: raise Exception() except: color = 255, 255, 255 return color