예제 #1
0
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()
예제 #2
0
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