Пример #1
0
def core_helper(plate, settings_dict, imagecontainer, position, version,
                redirect=True, debug=False):
    """Embeds analysis of a positon in a single function"""
    # see http://stackoverflow.com/questions/3288595/
    # multiprocessing-using-pool-map-on-a-function-defined-in-a-class
    logger =  logging.getLogger(str(os.getpid()))
    import numpy
    reload(numpy.core._dotblas)
    try:
        settings = ConfigSettings()
        settings.from_dict(settings_dict)
        settings.set('General', 'constrain_positions', True)
        settings.set('General', 'positions', position)

        environ = CecogEnvironment(version, redirect=redirect, debug=debug)
        if debug:
            environ.pprint()
        analyzer = AnalyzerCore(plate, settings, imagecontainer)
        post_hdf5_link_list = analyzer.processPositions()
        return plate, position, copy.deepcopy(post_hdf5_link_list)
    except Exception as e:
        errortxt = "plate: %s, position: %s\n" %(plate, position)
        errortxt = "".join([errortxt] + \
                               traceback.format_exception(*sys.exc_info()))
        logger.error(errortxt)
        raise e.__class__(errortxt)
Пример #2
0
    def iter_check_plates(cls, settings):
        settings.set_section(SECTION_NAME_GENERAL)
        path_in = CecogEnvironment.convert_package_path(
            settings.get2('pathin'))
        path_out = CecogEnvironment.convert_package_path(
            settings.get2('pathout'))
        has_multiple_plates = settings.get2('has_multiple_plates')

        if has_multiple_plates:
            plate_folders = [x for x in os.listdir(path_in)
                             if os.path.isdir(os.path.join(path_in, x))]
        else:
            plate_folders = [os.path.split(path_in)[1]]

        for plate_id in plate_folders:

            if has_multiple_plates:
                path_plate_in = os.path.join(path_in, plate_id)
                path_plate_out = os.path.join(path_out, plate_id)
            else:
                path_plate_in = path_in
                path_plate_out = path_out

            # check if structure file exists
            filename = cls._get_structure_filename(settings, plate_id, path_plate_in, path_plate_out)
            if not os.path.isfile(filename):
                # check old (hidden) filename for compatibility reasons
                filename = cls._get_structure_filename(settings, plate_id, path_plate_in, path_plate_out, use_old=True)
                if not os.path.isfile(filename):
                    filename = None
            yield plate_id, path_plate_in, path_plate_out, filename
Пример #3
0
def core_helper(plate,
                settings_dict,
                imagecontainer,
                position,
                version,
                redirect=True,
                debug=False):
    """Embeds analysis of a positon in a single function"""
    # see http://stackoverflow.com/questions/3288595/
    # multiprocessing-using-pool-map-on-a-function-defined-in-a-class
    logger = logging.getLogger(str(os.getpid()))
    import numpy
    reload(numpy.core._dotblas)
    try:
        settings = ConfigSettings()
        settings.from_dict(settings_dict)
        settings.set('General', 'constrain_positions', True)
        settings.set('General', 'positions', position)

        environ = CecogEnvironment(version, redirect=redirect, debug=debug)
        if debug:
            environ.pprint()
        analyzer = AnalyzerCore(plate, settings, imagecontainer)
        post_hdf5_link_list = analyzer.processPositions()
        return plate, position, copy.deepcopy(post_hdf5_link_list)
    except Exception as e:
        errortxt = "plate: %s, position: %s\n" % (plate, position)
        errortxt = "".join([errortxt] + \
                               traceback.format_exception(*sys.exc_info()))
        logger.error(errortxt)
        raise e.__class__(errortxt)
Пример #4
0
    def load_classifier(self, check=True):
        _resolve = lambda x,y: self._settings.get(x, '%s_%s'
                                                  % (self._channel, y))
        clfdir = CecogEnvironment.convert_package_path(_resolve('Classification',
                                               'classification_envpath'))
        # XXX - where does the "." come
        if not isdir(clfdir) or clfdir == ".":
            return
        else:
            self._learner = CommonClassPredictor( \
                clf_dir=clfdir,
                name=self._channel,
                channels={self._channel.title(): _resolve('Classification', 'classification_regionname')},
                color_channel=_resolve('ObjectDetection', 'channelid'))
            result = self._learner.check()

            if check:
                b = lambda x: 'Yes' if x else 'No'
                msg =  'Classifier path: %s\n' % result['path_env']
                msg += 'Found class definition: %s\n' % b(result['has_definition'])
                msg += 'Found annotations: %s\n' % b(result['has_path_annotations'])
                msg += 'Can you pick new samples? %s\n\n' % b(self.is_pick_samples())
                msg += 'Found ARFF file: %s\n' % b(result['has_arff'])
                msg += 'Can you train a classifier? %s\n\n' % b(self.is_train_classifier())
                msg += 'Found SVM model: %s\n' % b(result['has_model'])
                msg += 'Found SVM range: %s\n' % b(result['has_range'])
                msg += 'Can you apply the classifier to images? %s\n\n' % b(self.is_apply_classifier())
                msg += 'Found samples: %s\n' % b(result['has_path_samples'])
                msg += 'Sample images are only used for visualization and annotation control at the moment.'

                txt = '%s classifier inspection results' % self._channel
                information(self, txt, info=msg)

            if result['has_arff']:
                self._learner.importFromArff()
                nr_features_prev = len(self._learner.feature_names)
                removed_features = self._learner.filter_nans(apply=True)
                nr_features = nr_features_prev - len(removed_features)
                self._label_features.setText(self.LABEL_FEATURES %(nr_features, nr_features_prev))
                self._label_features.setToolTip("removed %d features containing NA values:\n%s" %
                                                (len(removed_features), "\n".join(removed_features)))

            if result['has_definition']:
                self._learner.loadDefinition()

            if result['has_conf']:
                c, g, conf = self._learner.importConfusion()
                self._set_info(c, g, conf)
                self._init_conf_table(conf)
                self._update_conf_table(conf)
            else:
                conf = None
                self._init_conf_table(conf)
            self._set_info_table(conf)
Пример #5
0
    def __init__(self):
        RawConfigParser.__init__(self, allow_no_value=True)
        self.environ = CecogEnvironment(version)
        self._registry = OrderedDict()
        self._current_section = None
        self._old_file_format = False

        self._section_registry = SectionRegistry()
        for section_name in self._section_registry.section_names():
            self.add_section(section_name)
            section = self._section_registry.get_section(section_name)
            for trait_name in section.get_trait_names():
                trait = section.get_trait(trait_name)
                self.set(section_name, trait_name, trait.default_value)
Пример #6
0
    def __init__(self, configfile, outdir, image1, image2=None, image3=None):

        super(CmdTool, self).__init__()
        self.environ = CecogEnvironment(version, redirect=False, debug=False)
        self.mapper = SettingsMapper(configfile)

        self.images = dict()
        names = [cl.NAME for cl in self.mapper.CHANNEL_CLASSES]
        for name, image in zip(names, (image1, image2, image3)):
            if image is not None:
                self.images[name] = image

        self.classifiers = dict()
        self.outdir = outdir
        self._setupClassifier()
Пример #7
0
    def get_special_settings(cls, settings, has_timelapse=True):
        settings = settings.copy()

        # try to resolve the paths relative to the package dir
        # (only in case of an relative path given)
        converts = [('General', 'pathin'),
                    ('General', 'pathout'),
                    ('Classification', 'primary_classification_envpath'),
                    ('Classification', 'secondary_classification_envpath'),
                    ('ErrorCorrection', 'primary_graph'),
                    ('ErrorCorrection', 'secondary_graph'),
                    ('ErrorCorrection', 'mappingfile_path'),
                    ]
        for section, option in converts:
            value = settings.get(section, option)
            settings.set(section, option, CecogEnvironment.convert_package_path(value))
        return settings
Пример #8
0
    def _on_browse_name(self, name, mode):
        # FIXME: signals are send during init were registry is not set yet
        if name in self._registry:
            input = CecogEnvironment.convert_package_path(str(self._registry[name].text()))
            dir = os.path.abspath(input)
            if mode == StringTrait.STRING_FILE:
                result = QFileDialog.getOpenFileName(self, 'Select a file', dir)
            else:
                result = QFileDialog.getExistingDirectory(self, \
                               'Select a directory', dir)

            if result:
                self._registry[name].setText(result)
                self._set_value(name, result)
                # call final handler
                if name in self._final_handlers:
                    self._final_handlers[name]()
Пример #9
0
    def update_display(self, is_active):
        if self._connect():
            self._can_submit = True

            try:
                self._submit_settings = ProcessingFrame.get_special_settings( \
                    self._settings, self.imagecontainer.has_timelapse)
            except:
                self._submit_settings = ProcessingFrame.get_special_settings(
                    self._settings)

            self._label_hosturl.setText(self._host_url)
            self._label_status.setText(self._service.get_service_info())

            mappable_paths = self._get_mappable_paths()
            self._table_info.clearContents()
            self._table_info.setRowCount(len(mappable_paths))
            for idx, info in enumerate(mappable_paths):
                value = self._settings.get(*info)
                mapped = CecogEnvironment.map_path_to_os(value,
                                                         target_os=OS_LINUX,
                                                         force=False)
                self._submit_settings.set(info[0], info[1], mapped)
                status = not mapped is None
                item = QTableWidgetItem()
                item.setBackground(QBrush(
                    QColor('green' if status else 'red')))
                txt_mapped = str(mapped) if status else \
                            'Warning: path can not be mapped on the cluster'
                self._table_info.setItem(idx, 0, item)
                self._table_info.setItem(idx, 1, QTableWidgetItem(value))
                self._table_info.setItem(idx, 2, QTableWidgetItem(txt_mapped))
                self._can_submit &= status
            self._table_info.resizeColumnsToContents()
            self._table_info.resizeRowsToContents()
            self._btn_submit.setEnabled(self._can_submit and is_active)
            self._btn_terminate.setEnabled(is_active)
            self._btn_toogle.setEnabled(is_active)
            self._btn_update.setEnabled(is_active)
        else:
            self._btn_submit.setEnabled(False)
            self._btn_terminate.setEnabled(False)
            self._btn_toogle.setEnabled(False)
            self._btn_update.setEnabled(False)
Пример #10
0
    def get_special_settings(cls, settings, has_timelapse=True):
        settings = settings.copy()

        # try to resolve the paths relative to the package dir
        # (only in case of an relative path given)
        converts = [
            ('General', 'pathin'),
            ('General', 'pathout'),
            ('Classification', 'primary_classification_envpath'),
            ('Classification', 'secondary_classification_envpath'),
            ('ErrorCorrection', 'primary_graph'),
            ('ErrorCorrection', 'secondary_graph'),
            ('ErrorCorrection', 'mappingfile_path'),
        ]
        for section, option in converts:
            value = settings.get(section, option)
            settings.set(section, option,
                         CecogEnvironment.convert_package_path(value))
        return settings
Пример #11
0
    def _on_browse_name(self, name, mode):
        # FIXME: signals are send during init were registry is not set yet
        if name in self._registry:
            input = CecogEnvironment.convert_package_path(
                str(self._registry[name].text()))
            dir = os.path.abspath(input)
            if mode == StringTrait.STRING_FILE:
                result = QFileDialog.getOpenFileName(self, 'Select a file',
                                                     dir)
            else:
                result = QFileDialog.getExistingDirectory(self, \
                               'Select a directory', dir)

            if result:
                self._registry[name].setText(result)
                self._set_value(name, result)
                # call final handler
                if name in self._final_handlers:
                    self._final_handlers[name]()
Пример #12
0
    def update_display(self, is_active):
        if self._connect():
            self._can_submit = True

            try:
                self._submit_settings = self._clusterframe.get_special_settings( \
                    self._settings, self.imagecontainer.has_timelapse)
            except:
                self._submit_settings = self._clusterframe.get_special_settings(self._settings)

            self._label_hosturl.setText(self._host_url)
            self._label_status.setText(self._service.get_service_info())

            mappable_paths = self._get_mappable_paths()
            self._table_info.clearContents()
            self._table_info.setRowCount(len(mappable_paths))
            for idx, info in enumerate(mappable_paths):
                value = self._settings.get(*info)
                mapped = CecogEnvironment.map_path_to_os(
                    value, target_os='linux', force=False)
                self._submit_settings.set(info[0], info[1], mapped)
                status = not mapped is None
                item = QTableWidgetItem()
                item.setBackground(QBrush(QColor('green' if status else 'red')))
                txt_mapped = str(mapped) if status else \
                            'Warning: path can not be mapped on the cluster'
                self._table_info.setItem(idx, 0, item)
                self._table_info.setItem(idx, 1, QTableWidgetItem(value))
                self._table_info.setItem(idx, 2, QTableWidgetItem(txt_mapped))
                self._can_submit &= status
            self._table_info.resizeColumnsToContents()
            self._table_info.resizeRowsToContents()
            self._btn_submit.setEnabled(self._can_submit and is_active)
            self._btn_terminate.setEnabled(is_active)
            self._btn_toogle.setEnabled(is_active)
            self._btn_update.setEnabled(is_active)
        else:
            self._btn_submit.setEnabled(False)
            self._btn_terminate.setEnabled(False)
            self._btn_toogle.setEnabled(False)
            self._btn_update.setEnabled(False)
Пример #13
0
def core_helper(plate,
                settings_dict,
                imagecontainer,
                position,
                version,
                mode="r+",
                redirect=True):
    """Embedds analysis of a positon in a single function"""
    # see http://stackoverflow.com/questions/3288595/
    # multiprocessing-using-pool-map-on-a-function-defined-in-a-class
    logger = logging.getLogger(str(os.getpid()))

    try:
        # FIXME numpy 1.11 does not have ._dotblas
        import numpy.core._dotblas
        reload(numpy.core._dotblas)
    except ImportError as e:
        pass

    try:
        settings = ConfigSettings()
        settings.from_dict(settings_dict)
        settings.set('General', 'constrain_positions', True)
        settings.set('General', 'positions', position)

        environ = CecogEnvironment(version, redirect=redirect)

        analyzer = PlateAnalyzer(plate, settings, imagecontainer, mode=mode)
        analyzer()
        return plate, position

    except Exception as e:
        errortxt = "Plate: %s, Site: %s\n" % (plate, position)
        errortxt = "".join([errortxt] + \
                               traceback.format_exception(*sys.exc_info()))
        logger.error(errortxt)
        raise type(e)(errortxt)
Пример #14
0
class CecogAnalyzer(QtGui.QMainWindow):

    NAME_FILTERS = ['Settings files (*.conf)', 'All files (*.*)']
    modified = QtCore.pyqtSignal('bool')

    def __init__(self, appname, version, redirect, debug=False, *args, **kw):
        super(CecogAnalyzer, self).__init__(*args, **kw)
        self.setWindowTitle("%s-%s" %(appname, version) + '[*]')
        self.setCentralWidget(QtGui.QFrame(self))
        self.setObjectName(appname)

        self.version = version
        self.appname = appname
        self.debug = debug

        self.environ = CecogEnvironment(version, redirect=redirect, debug=debug)
        if debug:
            self.environ.pprint()

        self._is_initialized = False
        self._imagecontainer = None
        self._meta_data = None
        self._browser = None

        action_quit = self.create_action('&Quit', slot=self.close)
        action_pref = self.create_action('&Preferences',
                                         slot=self.open_preferences)

        action_open = self.create_action('&Open Settings...',
                                         shortcut=QtGui.QKeySequence.Open,
                                         slot=self._on_file_open)
        action_save = self.create_action('&Save Settings',
                                         shortcut=QtGui.QKeySequence.Save,
                                         slot=self._on_file_save)
        self.action_save = action_save
        action_save_as = self.create_action('&Save Settings As...',
                                            shortcut=QtGui.QKeySequence.SaveAs,
                                            slot=self._on_file_save_as)
        menu_file = self.menuBar().addMenu('&File')
        self.add_actions(menu_file, (action_pref,
                                     None, action_open,
                                     None, action_save, action_save_as,
                                     None, action_quit))

        action_open = self.create_action('&Open Browser...',
                                         shortcut=QtGui.QKeySequence('CTRL+B'),
                                         slot=self._on_browser_open)
        menu_browser = self.menuBar().addMenu('&Browser')
        self.add_actions(menu_browser, (action_open, ))

        action_log = self.create_action('&Show Log Window...',
                                        shortcut=QtGui.QKeySequence(Qt.CTRL + Qt.Key_L),
                                        slot=self._on_show_log_window)
        menu_window = self.menuBar().addMenu('&Window')
        self.add_actions(menu_window, (action_log,))

        action_help_startup = self.create_action('&Startup Help...',
                                                 shortcut=QtGui.QKeySequence.HelpContents,
                                                 slot=self._on_help_startup)
        action_about = self.create_action('&About', slot=self.on_about)

        menu_help = self.menuBar().addMenu('&Help')
        self.add_actions(menu_help, (action_help_startup, action_about))

        qApp._main_window = self
        qApp._statusbar = QtGui.QStatusBar(self)
        self.setStatusBar(qApp._statusbar)

        self._selection = QtGui.QListWidget(self.centralWidget())
        self._selection.setViewMode(QtGui.QListView.IconMode)
        self._selection.setIconSize(QtCore.QSize(35, 35))
        self._selection.setGridSize(QtCore.QSize(140, 60))
        self._selection.setMovement(QtGui.QListView.Static)
        self._selection.setMaximumWidth(self._selection.gridSize().width() + 5)
        self._selection.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._selection.setSizePolicy(
            QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
                              QtGui.QSizePolicy.Expanding))

        self._pages = QtGui.QStackedWidget(self.centralWidget())
        self._pages.main_window = self

        self._settings_filename = None
        self._settings = GuiConfigSettings(self, SECTION_REGISTRY)

        self._tab_lookup = OrderedDict()
        self._tabs = [GeneralFrame(self._settings, self._pages),
                      ObjectDetectionFrame(self._settings, self._pages),
                      FeatureExtractionFrame(self._settings, self._pages),
                      ClassificationFrame(self._settings, self._pages),
                      TrackingFrame(self._settings, self._pages),
                      ErrorCorrectionFrame(self._settings, self._pages),
                      PostProcessingFrame(self._settings, self._pages),
                      OutputFrame(self._settings, self._pages),
                      ProcessingFrame(self._settings, self._pages)]

        if self.environ.analyzer_config.get('Analyzer', 'cluster_support'):
            self._tabs.append(ClusterFrame(self._settings, self._pages,
                                           self._imagecontainer))

        widths = []
        for tab in self._tabs:
            size = self._add_page(tab)
            widths.append(size.width())
        self.set_modules_active(state=False)
        self._pages.setMinimumWidth(max(widths) + 45)

        self._selection.currentItemChanged.connect(self._on_change_page)
        self._selection.setCurrentRow(0)

        w_logo = QtGui.QLabel(self.centralWidget())
        w_logo.setPixmap(QtGui.QPixmap(':cecog_logo_w145'))

        layout = QtGui.QGridLayout(self.centralWidget())
        layout.addWidget(self._selection, 0, 0)
        layout.addWidget(w_logo, 1, 0, Qt.AlignBottom | Qt.AlignHCenter)
        layout.addWidget(self._pages, 0, 1, 2, 1)
        layout.setContentsMargins(1, 1, 1, 1)

        handler = GuiLogHandler(self)
        handler.setLevel(logging.INFO)
        formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
        handler.setFormatter(formatter)

        self.log_window = LogWindow(self, handler)
        self.log_window.setGeometry(50, 50, 600, 300)

        logger = logging.getLogger()
        logger.setLevel(logging.INFO)

        qApp._image_dialog = None
        qApp._graphics = None

        self.setGeometry(0, 0, 1200, 700)
        self.setMinimumSize(QtCore.QSize(700, 600))
        self._is_initialized = True

    def show(self):
        super(CecogAnalyzer, self).show()
        self.center()

    def closeEvent(self, event):
        # Quit dialog only if not debuging flag is not set
        if self.debug:
            return
        ret = QMessageBox.question(self, "Quit %s" %self.appname,
                                   "Do you really want to quit?",
                                   QMessageBox.Yes|QMessageBox.No)
        if self._check_settings_saved() and ret == QMessageBox.No:
            event.ignore()
        else:
            # FIXME - some dialogs are attributs of qApp
            # --> QApplication does not exit automatically
            QtGui.QApplication.exit()

    def settings_changed(self, changed):
        if self._is_initialized:
            self.setWindowModified(changed)
            self.action_save.setEnabled(changed)
            self.modified.emit(changed)

    def _add_page(self, widget):
        button = QtGui.QListWidgetItem(self._selection)
        button.setIcon(QtGui.QIcon(widget.ICON))
        button.setText(widget.get_name())
        button.setTextAlignment(Qt.AlignHCenter)
        self._pages.addWidget(widget)

        widget.toggle_tabs.connect(self._on_toggle_tabs)
        self._tab_lookup[widget.get_name()] = (button, widget)
        return widget.size()

    def _on_toggle_tabs(self, name):
        """Toggle ItemIsEnabled flag for all list items but name."""
        for name2 in self._tab_lookup:
            if name2 != name:
                item, widget = self._tab_lookup[name2]
                flags = item.flags()
                # check flag (and)
                if flags & Qt.ItemIsEnabled:
                    # remove flag (nand)
                    item.setFlags(flags & ~Qt.ItemIsEnabled)
                else:
                    # set flag (or)
                    item.setFlags(flags | Qt.ItemIsEnabled)

    def _on_change_page(self, current, previous):
        if not current:
            current = previous
        index = self._selection.row(current)
        self._pages.setCurrentIndex(index);
        widget = self._pages.widget(index)
        widget.page_changed()

    def _check_settings_saved(self):
        if self.isWindowModified():
            result = question(self, 'Settings have been modified.',
                              info='Do you want to save settings?',
                              modal=True, show_cancel=True,
                              default=QMessageBox.Yes,
                              escape=QMessageBox.Cancel)
            if result == QMessageBox.Yes:
                self.save_settings()
        else:
            result = QMessageBox.No
        return result

    def center(self):
        screen = QtGui.QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2,
        (screen.height() - size.height()) / 2)

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(self, text, slot=None, shortcut=None, icon=None,
                      tooltip=None, checkable=None, signal='triggered()',
                      checked=False):
        action = QtGui.QAction(text, self)
        if icon is not None:
            action.setIcon(QtGui.QIcon(':/%s.png' % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tooltip is not None:
            action.setToolTip(tooltip)
            action.setStatusTip(tooltip)
        if slot is not None:
            self.connect(action, QtCore.SIGNAL(signal), slot)
        if checkable is not None:
            action.setCheckable(True)
        action.setChecked(checked)
        return action

    def save_settings(self, save_as=False):
        filename = self._settings_filename
        if filename is None or save_as:
            filename = self._get_save_as_filename()
        if not filename is None:
            self._write_settings(filename)

    def _read_settings(self, filename):
        try:
            self._settings.read(filename)
        except:
            critical(self,
                     "Error loading settings file",
                     info="Could not load settings file '%s'." % filename,
                     detail_tb=True)
            status('Settings not successfully loaded.')
        else:
            self._settings_filename = filename
            title = self.windowTitle().split(' - ')[0]
            self.setWindowTitle('%s - %s[*]' % (title, filename))
            try:
                for widget in self._tabs:
                    widget.update_input()
            except:
                critical(self, "Problem loading settings file.",
                         info="Fix the problem in file '%s' and load the "\
                                "settings file again." % filename,
                         detail_tb=True)
            else:
                # convert settings
                if self.version > self._settings.get('General', 'version'):
                    print 'print new version'


                # set settings to not-changed (assume no changed since loaded from file)
                self.settings_changed(False)
                # notify tabs about new settings loaded
                for tab in self._tabs:
                    tab.settings_loaded()
                status('Settings successfully loaded.')

    def _write_settings(self, filename):
        try:
            f = file(filename, 'w')
            # create a new version (copy) of the current
            # settings which add the needed rendering information
            settings_dummy = ProcessingFrame.get_export_settings(self._settings)
            settings_dummy.write(f)
            f.close()
        except:
            critical(self,
                     "Error saving settings file",
                     info="Could not save settings file as '%s'." % filename,
                     detail_tb=True)
            status('Settings not successfully saved.')
        else:
            self._settings_filename = filename
            self.setWindowTitle('%s - %s[*]' % (self.appname, filename))
            self.settings_changed(False)
            status('Settings successfully saved.')

    def on_about(self):
        dialog = CecogAboutDialog(self)
        dialog.show()

    def open_preferences(self):
        print "pref"

    def _on_browser_open(self):
        if self._imagecontainer is None:
            warning(self, 'Data structure not loaded',
                    'The input data structure was not loaded.\n'
                    'Please click "Load image data" in General.')
        elif self._browser is None:
            try:
                browser = Browser(self._settings, self._imagecontainer)
                browser.show()
                browser.raise_()
                browser.setFocus()
                self._browser = browser
            except:
                exception(self, 'Problem opening the browser')
        else:
            self._browser.show()
            self._browser.raise_()

    def _on_load_input(self):
        txt = "Error scanning image structure"
        path_in = self._settings.get(SECTION_NAME_GENERAL, 'pathin')
        if path_in == '':
            critical(self, txt, "Image path must be defined.")
        elif not os.path.isdir(path_in) and \
             not os.path.isdir(os.path.join(self.environ.package_dir, path_in)):
            critical(self, txt, "Image path '%s' not found." % path_in)
        else:
            try:
                infos = list(ImageContainer.iter_check_plates(self._settings))
            except:
                exception(self, txt)
            else:
                found_any = numpy.any([not info[3] is None for info in infos])
                cancel = False
                if found_any:
                    found_plates = [info[0] for info in infos
                                    if not info[3] is None]
                    missing_plates = [info[0] for info in infos
                                      if info[3] is None]
                    has_missing = len(missing_plates) > 0
                    txt = '%s plates were already scanned.\nDo you want ' \
                          'to rescan the file structure(s)? ' \
                          'This can take several minutes.' % \
                          ('Some' if has_missing else 'All')
                    title = 'Rescan input structure?'

                    box = QMessageBox(QMessageBox.Question, title, title,
                                      QMessageBox.Cancel, self, Qt.Sheet)
                    box.setWindowModality(Qt.WindowModal)
                    box.setInformativeText(txt)
                    box.setDetailedText('Plates with scanned structure: \n%s\n'
                                        '\nPlates without scanned structure: '
                                        '\n%s' %
                                        ('\n'.join(found_plates),
                                         '\n'.join(missing_plates)))
                    if not has_missing:
                        btn1 = QtGui.QPushButton('No', box)
                        box.addButton(btn1, QMessageBox.NoRole)
                        box.setDefaultButton(btn1)
                    elif len(found_plates) > 0:
                        btn1 = QtGui.QPushButton('Rescan missing', box)
                        box.addButton(btn1, QMessageBox.YesRole)
                        box.setDefaultButton(btn1)
                    else:
                        btn1 = None

                    btn2 = QtGui.QPushButton('Rescan all', box)
                    box.addButton(btn2, QMessageBox.YesRole)

                    if box.exec_() == QMessageBox.Cancel:
                        cancel = True
                    else:
                        btn = box.clickedButton()
                        if btn == btn1:
                            if has_missing:
                                scan_plates = dict([(info[0], info[0] in missing_plates) for info in infos])
                            else:
                                scan_plates = dict((info[0], False) for info in infos)
                        else:
                            scan_plates = dict((info[0], True) for info in infos)
                else:
                    has_multiple = self._settings.get(SECTION_NAME_GENERAL,
                                                      "has_multiple_plates")
                    if not question(self, "No structure data found",
                                    "Are you sure to scan %s?\n\nThis can take "
                                    "several minutes depending on the number of"
                                    " images." %
                                    ("%d plates" % len(infos) if has_multiple
                                     else "one plate")):
                        cancel = True
                    scan_plates = dict((info[0], True) for info in infos)
                if not cancel:
                    self._load_image_container(infos, scan_plates)

    def _load_image_container(self, plate_infos, scan_plates=None, show_dlg=True):

        self._clear_browser()
        imagecontainer = ImageContainer()
        self._imagecontainer = imagecontainer

        if scan_plates is None:
            scan_plates = dict((info[0], False) for info in plate_infos)

        def load(dlg):
            iter = imagecontainer.iter_import_from_settings(self._settings, scan_plates)
            for idx, info in enumerate(iter):
                dlg.targetSetValue.emit(idx + 1)

            if len(imagecontainer.plates) > 0:
                plate = imagecontainer.plates[0]
                imagecontainer.set_plate(plate)

        self.dlg = waitingProgressDialog('Please wait until the input structure is scanned\n'
                                    'or the structure data loaded...', self, load, (0, len(scan_plates)))
        self.dlg.exec_(passDialog=True)

        if len(imagecontainer.plates) > 0:
            imagecontainer.check_dimensions()
            channels = imagecontainer.channels

            # do not report value changes to the main window
            self._settings.set_notify_change(False)

            self.set_image_crop_size()

            problems = []
            for prefix in ['primary', 'secondary', 'tertiary']:
                trait = self._settings.get_trait(SECTION_NAME_OBJECTDETECTION,
                                                 '%s_channelid' % prefix)
                if trait.set_list_data(channels) is None:
                    problems.append(prefix)
                self._tabs[1].get_widget('%s_channelid' % prefix).update()

            # report problems about a mismatch between channel IDs found in the data and specified by the user
            if len(problems) > 0:
                critical(self, "Selected channel IDs not valid",
                         "The selected channel IDs for %s are not valid.\nValid IDs are %s." %
                         (", ".join(["'%s Channel'" % s.capitalize() for s in problems]),
                          ", ".join(["'%s'" % s for s in channels])))
                # a mismatch between settings and data will cause changed settings
                self.settings_changed(True)

            trait = self._settings.get_trait(SECTION_NAME_TRACKING,
                                             'tracking_duration_unit')

            # allow time-base tracking durations only if time-stamp
            # information is present
            meta_data = imagecontainer.get_meta_data()
            if meta_data.has_timestamp_info:
                result = trait.set_list_data(TRACKING_DURATION_UNITS_TIMELAPSE)
            else:
                result = trait.set_list_data(TRACKING_DURATION_UNITS_DEFAULT)
            if result is None:
                critical(self, "Could not set tracking duration units",
                         "The tracking duration units selected to match the load data. Please check your settings.")
                # a mismatch between settings and data will cause changed settings
                self.settings_changed(True)

            # activate change notification again
            self._settings.set_notify_change(True)


            self.set_modules_active(state=True)
            if show_dlg:
                information(self, "Plate(s) successfully loaded",
                            "%d plates loaded successfully." % len(imagecontainer.plates))
        else:
            critical(self, "No valid image data found",
                     "The naming schema provided might not fit your image data"
                     "or the coordinate file is not correct.\n\nPlease modify "
                     "the values and scan the structure again.")

    def set_image_crop_size(self):
        x0, y0, x1, y1 = self._settings.get('General', 'crop_image_x0'), \
                         self._settings.get('General', 'crop_image_y0'), \
                         self._settings.get('General', 'crop_image_x1'), \
                         self._settings.get('General', 'crop_image_y1')

        x0_, y0_, x1_, y1_ = 0, \
                             0, \
                             self._imagecontainer.get_meta_data().dim_x, \
                             self._imagecontainer.get_meta_data().dim_y

        tr_x0 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_x0')
        tr_y0 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_y0')
        tr_x1 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_x1')
        tr_y1 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_y1')

        # Check if the crop values are valid
        if x0 > 0 and y0 > 0 and x1 <= x1_ and y1 <= y1_ and \
                x0 != x1 and y0 != y1:
            # Set to default values
            tr_x0.set_value(tr_x0.get_widget(), x0)
            tr_y0.set_value(tr_y0.get_widget(), y0)
            tr_x1.set_value(tr_x1.get_widget(), x1)
            tr_y0.set_value(tr_y1.get_widget(), y1)
        else:
            tr_x0.set_value(tr_x0.get_widget(), x0_)
            tr_y0.set_value(tr_y0.get_widget(), y0_)
            tr_x1.set_value(tr_x1.get_widget(), x1_)
            tr_y0.set_value(tr_y1.get_widget(), y1_)

        # Set GUI widget valid ranges
        tr_x0.set_min_value(x0_)
        tr_x0.set_max_value(x1_)
        tr_y0.set_min_value(y0_)
        tr_y0.set_max_value(y1_)
        tr_x1.set_min_value(x0_)
        tr_x1.set_max_value(x1_)
        tr_y1.set_min_value(y0_)
        tr_y1.set_max_value(y1_)

    def set_modules_active(self, state=True):
        for name, (button, widget) in self._tab_lookup.iteritems():
            widget.set_active(state)

    @QtCore.pyqtSlot()
    def _on_file_open(self):
        if self._check_settings_saved() != QMessageBox.Cancel:
            dir = ""
            if not self._settings_filename is None:
                settings_filename = self.environ.convert_package_path(
                    self._settings_filename)
                if os.path.isfile(settings_filename):
                    dir = settings_filename
            filename = QtGui.QFileDialog.getOpenFileName(self, 'Open config file',
                                                          dir, ';;'.join(self.NAME_FILTERS))
            if filename:
                self._read_settings(filename)
                if self._settings.was_old_file_format():
                    information(self, ('Selected config file had an old '
                                       'version <= 1.3.0. The current version is %s. '
                                       'The config file was  be updated...' %self.version))
                else:
                    information(self, "Config file version %s found"  \
                                %self._settings.get('General', 'version'))
                self._clear_browser()
                self.set_modules_active(state=False)

    @QtCore.pyqtSlot()
    def _on_file_save(self):
        self.save_settings(False)

    @QtCore.pyqtSlot()
    def _on_file_save_as(self):
        self.save_settings(True)

    def _clear_browser(self):
        # close and delete the current browser instance
        if not self._browser is None:
            self._browser.close()
            self._browser = None

    def _on_show_log_window(self):
        logger = logging.getLogger()
        logger.addHandler(self.log_window.handler)
        self.log_window.show()
        #self.log_window.raise_()

    def _get_save_as_filename(self):
        dir = ""
        if not self._settings_filename is None:
            settings_filename = self.environ.convert_package_path(
                self._settings_filename)
            if os.path.isfile(settings_filename):
                dir = settings_filename
        filename = QtGui.QFileDialog.getSaveFileName(
            self, 'Save config file as', dir, ';;'.join(self.NAME_FILTERS))
        return filename or None

    def _on_help_startup(self):
        show_html('_startup')
Пример #15
0
    (options, args) = parser.parse_args()

    logger = logging.getLogger()
    handler = logging.StreamHandler(sys.stdout)
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s %(levelname)-6s %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.setLevel(logging.INFO)

    logger.info("*************************************************" + '*'*len(version))
    logger.info("*** CellCognition - Batch Analyzer - Version %s ***" %version)
    logger.info("*************************************************" + '*'*len(version))
    logger.info('argv: %s' % sys.argv)

    environ = CecogEnvironment(version)

    if options.settings is None:
        parser.error('Settings filename required.')

    environ = CecogEnvironment(version, redirect=False, debug=False)

    filename_settings = os.path.abspath(options.settings)

    # read the settings data from file
    settings = ConfigSettings()
    settings.read(filename_settings)

    settings.set_section(SECTION_NAME_GENERAL)

    index = options.cluster_index
Пример #16
0
    def _on_process_start(self, name, start_again=False):
        if not self._is_running or start_again:
            is_valid = True
            self._is_abort = False
            self._has_error = False

            if self._process_items is None:
                cls = self._control_buttons[name]['cls']
                if type(cls) == types.ListType:
                    self._process_items = cls
                    self._current_process_item = 0
                    cls = cls[self._current_process_item]

                    # remove HmmThread if process is not first in list and
                    # not valid error correction was activated
                    if (HmmThread in self._process_items
                            and self._process_items.index(HmmThread) > 0 and
                            not (self._settings.get(
                                'Processing', 'primary_errorcorrection') or
                                 (self._settings.get(
                                     'Processing', 'secondary_errorcorrection')
                                  and self._settings.get(
                                      'Processing',
                                      'secondary_processchannel')))):
                        self._process_items.remove(HmmThread)

                else:
                    self._process_items = None
                    self._current_process_item = 0
            else:
                cls = self._process_items[self._current_process_item]

            if self.SECTION_NAME == 'Classification':
                result_frame = self._get_result_frame(self._tab_name)
                result_frame.load_classifier(check=False)
                learner = result_frame._learner

                if name == self.PROCESS_PICKING:
                    if not result_frame.is_pick_samples():
                        is_valid = False
                        result_frame.msg_pick_samples(self)
                    elif result_frame.is_train_classifier():
                        if not question(
                                self, 'Samples already picked',
                                'Do you want to pick samples again and '
                                'overwrite previous '
                                'results?'):
                            is_valid = False

                elif name == self.PROCESS_TRAINING:
                    if not result_frame.is_train_classifier():
                        is_valid = False
                        result_frame.msg_train_classifier(self)
                    elif result_frame.is_apply_classifier():
                        if not question(
                                self, 'Classifier already trained',
                                'Do you want to train the classifier '
                                'again?'):
                            is_valid = False

                elif name == self.PROCESS_TESTING and not result_frame.is_apply_classifier(
                ):
                    is_valid = False
                    result_frame.msg_apply_classifier(self)

            elif cls is HmmThread:

                success, cmd = HmmThread.test_executable(
                    self._settings.get('ErrorCorrection', 'filename_to_R'))
                if not success:
                    critical(self, 'Error running R',
                             "The R command line program '%s' could not be executed.\n\n"\
                             "Make sure that the R-project is installed.\n\n"\
                             "See README.txt for details." % cmd)
                    is_valid = False

            elif cls is MultiAnalyzerThread:
                ncpu = cpu_count()
                (ncpu, ok) = QInputDialog.getInt(None, "On your machine are %d processers available." % ncpu, \
                                             "Select the number of processors", \
                                              ncpu, 1, ncpu*2)
                if not ok:
                    self._process_items = None
                    is_valid = False

            if is_valid:
                self._current_process = name

                if not start_again:
                    self.parent().main_window.log_window.clear()

                    self._is_running = True
                    self._stage_infos = {}

                    self._toggle_tabs(False)
                    # disable all section button of the main widget
                    self.toggle_tabs.emit(self.get_name())

                    self._set_control_button_text(idx=1)
                    self._toggle_control_buttons()

                imagecontainer = self.parent().main_window._imagecontainer

                if cls is PickerThread:
                    self._current_settings = self._get_modified_settings(
                        name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings,
                                         imagecontainer)
                    self._set_display_renderer_info()
                    self._clear_image()

                elif cls is AnalyzerThread:
                    self._current_settings = self._get_modified_settings(
                        name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings,
                                         imagecontainer)
                    self._set_display_renderer_info()
                    self._clear_image()

                elif cls is TrainingThread:
                    self._current_settings = self._settings.copy()

                    self._analyzer = cls(self, self._current_settings,
                                         result_frame._learner)
                    self._analyzer.setTerminationEnabled(True)

                    self._analyzer.conf_result.connect(
                        result_frame.on_conf_result, Qt.QueuedConnection)
                    result_frame.reset()

                elif cls is MultiAnalyzerThread:
                    self._current_settings = self._get_modified_settings(
                        name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings,
                                         imagecontainer, ncpu)

                    self._set_display_renderer_info()

                elif cls is HmmThread:
                    self._current_settings = self._get_modified_settings(
                        name, imagecontainer.has_timelapse)

                    # FIXME: classifier handling needs revision!!!
                    learner_dict = {}
                    for kind in ['primary', 'secondary']:
                        _resolve = lambda x, y: self._settings.get(
                            x, '%s_%s' % (kind, y))
                        env_path = CecogEnvironment.convert_package_path(
                            _resolve('Classification',
                                     'classification_envpath'))
                        if (os.path.exists(env_path) and
                            (kind == 'primary' or self._settings.get(
                                'Processing', 'secondary_processchannel'))):

                            learner = CommonClassPredictor( \
                                env_path,
                                _resolve('ObjectDetection', 'channelid'),
                                _resolve('Classification', 'classification_regionname'))
                            learner.importFromArff()
                            learner_dict[kind] = learner

                    ### Whee, I like it... "self.parent().main_window._imagecontainer" crazy, crazy, michael... :-)
                    self._analyzer = cls(
                        self, self._current_settings, learner_dict,
                        self.parent().main_window._imagecontainer)
                    self._analyzer.setTerminationEnabled(True)
                    lw = self.parent().main_window.log_window
                    lw.show()

                elif cls is PostProcessingThread:
                    learner_dict = {}
                    for kind in ['primary', 'secondary']:
                        _resolve = lambda x, y: self._settings.get(
                            x, '%s_%s' % (kind, y))
                        env_path = CecogEnvironment.convert_package_path(
                            _resolve('Classification',
                                     'classification_envpath'))
                        if (_resolve('Processing', 'classification') and
                            (kind == 'primary' or self._settings.get(
                                'Processing', 'secondary_processchannel'))):
                            learner = CommonClassPredictor( \
                                env_path,
                                _resolve('ObjectDetection', 'channelid'),
                                _resolve('Classification', 'classification_regionname'))

                            learner.importFromArff()
                            learner_dict[kind] = learner
                    self._current_settings = self._get_modified_settings(
                        name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings,
                                         learner_dict, imagecontainer)
                    self._analyzer.setTerminationEnabled(True)

                self._analyzer.finished.connect(self._on_process_finished)
                self._analyzer.stage_info.connect(self._on_update_stage_info,
                                                  Qt.QueuedConnection)
                self._analyzer.analyzer_error.connect(self._on_error,
                                                      Qt.QueuedConnection)

                self._analyzer.start(QThread.LowestPriority)
                if self._current_process_item == 0:
                    status('Process started...')

        else:
            self._abort_processing()
Пример #17
0
    def __init__(self, appname, version, redirect, settings=None,
                 debug=False, *args, **kw):
        super(CecogAnalyzer, self).__init__(*args, **kw)
        self.setWindowTitle("%s-%s" %(appname, version) + '[*]')
        self.setAcceptDrops(True)
        self.setCentralWidget(QtWidgets.QFrame(self))
        self.setObjectName(appname)

        self.version = version
        self.appname = appname
        self.debug = debug

        self.environ = CecogEnvironment(version=version, redirect=redirect,
                                        debug=debug)

        if debug:
            self.environ.pprint()

        self._is_initialized = False
        self._imagecontainer = None
        self._meta_data = None
        self._browser = None

        action_quit = self.create_action('&Quit', slot=self.close)
        action_pref = self.create_action('&Preferences',
                                         slot=self.open_preferences)

        action_load = self.create_action('&Load Settings...',
                                         shortcut=QtGui.QKeySequence.Open,
                                         slot=self._on_file_open)
        action_save = self.create_action('&Save Settings',
                                         shortcut=QtGui.QKeySequence.Save,
                                         slot=self._on_file_save)
        self.action_save = action_save
        action_save_as = self.create_action('&Save Settings As...',
                                            shortcut=QtGui.QKeySequence.SaveAs,
                                            slot=self._on_file_save_as)

        menu_file = self.menuBar().addMenu('&File')
        self.add_actions(menu_file, (action_pref,
                                     None, action_load,
                                     None, action_save, action_save_as,
                                     None, action_quit))

        action_log = self.create_action('&Log window',
                                        shortcut=QtGui.QKeySequence(Qt.CTRL+Qt.Key_L),
                                        slot=self._on_show_log_window)

        action_open = self.create_action('&Browser',
                                         shortcut=QtGui.QKeySequence('CTRL+B'),
                                         slot=self._on_browser_open)

        menu_view = self.menuBar().addMenu('&View')
        self.add_actions(menu_view, (action_log,))
        self.add_actions(menu_view, (action_open,))

        action_assistant = self.create_action('&Help',
                                              shortcut=QtGui.QKeySequence.HelpContents,
                                              slot=self.show_assistant)
        action_about = self.create_action('&About', slot=self.on_about)
        action_aboutQt = self.create_action('&About Qt', slot=self.about_qt)


        menu_help = self.menuBar().addMenu('&Help')
        self.add_actions(menu_help, (action_assistant, action_about,
                                     action_aboutQt))

        self.setStatusBar(QtWidgets.QStatusBar(self))

        self._selection = QtWidgets.QListWidget(self.centralWidget())
        self._selection.setViewMode(QtWidgets.QListView.IconMode)
        self._selection.setIconSize(QtCore.QSize(35, 35))
        self._selection.setGridSize(QtCore.QSize(140, 60))
        self._selection.setMovement(QtWidgets.QListView.Static)
        self._selection.setMaximumWidth(self._selection.gridSize().width() + 5)
        self._selection.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._selection.setSizePolicy(
            QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                  QtWidgets.QSizePolicy.Expanding))

        self._pages = FrameStack(self)

        self._settings_filename = None
        self._settings = GuiConfigSettings(self)

        self._tab_lookup = OrderedDict()
        self._tabs = [GeneralFrame(self._settings, self._pages, SECTION_NAME_GENERAL),
                      ObjectDetectionFrame(self._settings, self._pages, SECTION_NAME_OBJECTDETECTION),
                      FeatureExtractionFrame(self._settings, self._pages, SECTION_NAME_FEATURE_EXTRACTION),
                      ClassificationFrame(self._settings, self._pages, SECTION_NAME_CLASSIFICATION),
                      TrackingFrame(self._settings, self._pages, SECTION_NAME_TRACKING),
                      EventSelectionFrame(self._settings, self._pages, SECTION_NAME_EVENT_SELECTION),
                      ErrorCorrectionFrame(self._settings, self._pages, SECTION_NAME_ERRORCORRECTION),
                      OutputFrame(self._settings, self._pages, SECTION_NAME_OUTPUT),
                      ProcessingFrame(self._settings, self._pages, SECTION_NAME_PROCESSING)]

        # connections for the section frames
        self._tabs[3].connect_browser_btn(self._on_browser_open)
        for frame in self._tabs:
            frame.status_message.connect(self.statusBar().showMessage)

        app = AppPreferences()
        if app.cluster_support:
            clusterframe = ClusterFrame(self._settings, self._pages, SECTION_NAME_CLUSTER)
            clusterframe.set_imagecontainer(self._imagecontainer)
            self._tabs.append(clusterframe)

        try:
            self.updateStyleSheet(loadStyle(app.stylesheet))
        except Exception as e:
            # proceed with no stylesheet
            traceback.print_exc()


        widths = []
        for tab in self._tabs:
            size = self._add_page(tab)
            widths.append(size.width())
        self.set_modules_active(state=False)
        self._pages.setMinimumWidth(max(widths) + 45)

        self._selection.currentItemChanged.connect(self._on_change_page)
        self._selection.setCurrentRow(0)

        w_logo = QtWidgets.QLabel(self.centralWidget())
        w_logo.setPixmap(QtGui.QPixmap(':cecog_logo_w145'))

        layout = QtWidgets.QGridLayout(self.centralWidget())
        layout.addWidget(self._selection, 0, 0)
        layout.addWidget(w_logo, 1, 0, Qt.AlignBottom | Qt.AlignHCenter)
        layout.addWidget(self._pages, 0, 1, 2, 1)
        layout.setContentsMargins(1, 1, 1, 1)

        self.setGeometry(0, 0, 1250, 800)
        self.setMinimumSize(QtCore.QSize(700, 600))
        self._is_initialized = True

        self._restore_geometry()
        self.show()

        # finally load (demo) - settings
        if settings is None:
            self.load_settings(self.environ.demo_settings)
        elif os.path.isfile(settings):
            self.load_settings(settings)
        else:
            QMessageBox.warning(
                self, "Warning", "File (%s) does not exist" %settings)
Пример #18
0
class CecogAnalyzer(QtWidgets.QMainWindow):

    NAME_FILTERS = ['Settings files (*.conf)', 'All files (*.*)']
    modified = QtCore.pyqtSignal('bool')

    def __init__(self, appname, version, redirect, settings=None,
                 debug=False, *args, **kw):
        super(CecogAnalyzer, self).__init__(*args, **kw)
        self.setWindowTitle("%s-%s" %(appname, version) + '[*]')
        self.setAcceptDrops(True)
        self.setCentralWidget(QtWidgets.QFrame(self))
        self.setObjectName(appname)

        self.version = version
        self.appname = appname
        self.debug = debug

        self.environ = CecogEnvironment(version=version, redirect=redirect,
                                        debug=debug)

        if debug:
            self.environ.pprint()

        self._is_initialized = False
        self._imagecontainer = None
        self._meta_data = None
        self._browser = None

        action_quit = self.create_action('&Quit', slot=self.close)
        action_pref = self.create_action('&Preferences',
                                         slot=self.open_preferences)

        action_load = self.create_action('&Load Settings...',
                                         shortcut=QtGui.QKeySequence.Open,
                                         slot=self._on_file_open)
        action_save = self.create_action('&Save Settings',
                                         shortcut=QtGui.QKeySequence.Save,
                                         slot=self._on_file_save)
        self.action_save = action_save
        action_save_as = self.create_action('&Save Settings As...',
                                            shortcut=QtGui.QKeySequence.SaveAs,
                                            slot=self._on_file_save_as)

        menu_file = self.menuBar().addMenu('&File')
        self.add_actions(menu_file, (action_pref,
                                     None, action_load,
                                     None, action_save, action_save_as,
                                     None, action_quit))

        action_log = self.create_action('&Log window',
                                        shortcut=QtGui.QKeySequence(Qt.CTRL+Qt.Key_L),
                                        slot=self._on_show_log_window)

        action_open = self.create_action('&Browser',
                                         shortcut=QtGui.QKeySequence('CTRL+B'),
                                         slot=self._on_browser_open)

        menu_view = self.menuBar().addMenu('&View')
        self.add_actions(menu_view, (action_log,))
        self.add_actions(menu_view, (action_open,))

        action_assistant = self.create_action('&Help',
                                              shortcut=QtGui.QKeySequence.HelpContents,
                                              slot=self.show_assistant)
        action_about = self.create_action('&About', slot=self.on_about)
        action_aboutQt = self.create_action('&About Qt', slot=self.about_qt)


        menu_help = self.menuBar().addMenu('&Help')
        self.add_actions(menu_help, (action_assistant, action_about,
                                     action_aboutQt))

        self.setStatusBar(QtWidgets.QStatusBar(self))

        self._selection = QtWidgets.QListWidget(self.centralWidget())
        self._selection.setViewMode(QtWidgets.QListView.IconMode)
        self._selection.setIconSize(QtCore.QSize(35, 35))
        self._selection.setGridSize(QtCore.QSize(140, 60))
        self._selection.setMovement(QtWidgets.QListView.Static)
        self._selection.setMaximumWidth(self._selection.gridSize().width() + 5)
        self._selection.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._selection.setSizePolicy(
            QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                  QtWidgets.QSizePolicy.Expanding))

        self._pages = FrameStack(self)

        self._settings_filename = None
        self._settings = GuiConfigSettings(self)

        self._tab_lookup = OrderedDict()
        self._tabs = [GeneralFrame(self._settings, self._pages, SECTION_NAME_GENERAL),
                      ObjectDetectionFrame(self._settings, self._pages, SECTION_NAME_OBJECTDETECTION),
                      FeatureExtractionFrame(self._settings, self._pages, SECTION_NAME_FEATURE_EXTRACTION),
                      ClassificationFrame(self._settings, self._pages, SECTION_NAME_CLASSIFICATION),
                      TrackingFrame(self._settings, self._pages, SECTION_NAME_TRACKING),
                      EventSelectionFrame(self._settings, self._pages, SECTION_NAME_EVENT_SELECTION),
                      ErrorCorrectionFrame(self._settings, self._pages, SECTION_NAME_ERRORCORRECTION),
                      OutputFrame(self._settings, self._pages, SECTION_NAME_OUTPUT),
                      ProcessingFrame(self._settings, self._pages, SECTION_NAME_PROCESSING)]

        # connections for the section frames
        self._tabs[3].connect_browser_btn(self._on_browser_open)
        for frame in self._tabs:
            frame.status_message.connect(self.statusBar().showMessage)

        app = AppPreferences()
        if app.cluster_support:
            clusterframe = ClusterFrame(self._settings, self._pages, SECTION_NAME_CLUSTER)
            clusterframe.set_imagecontainer(self._imagecontainer)
            self._tabs.append(clusterframe)

        try:
            self.updateStyleSheet(loadStyle(app.stylesheet))
        except Exception as e:
            # proceed with no stylesheet
            traceback.print_exc()


        widths = []
        for tab in self._tabs:
            size = self._add_page(tab)
            widths.append(size.width())
        self.set_modules_active(state=False)
        self._pages.setMinimumWidth(max(widths) + 45)

        self._selection.currentItemChanged.connect(self._on_change_page)
        self._selection.setCurrentRow(0)

        w_logo = QtWidgets.QLabel(self.centralWidget())
        w_logo.setPixmap(QtGui.QPixmap(':cecog_logo_w145'))

        layout = QtWidgets.QGridLayout(self.centralWidget())
        layout.addWidget(self._selection, 0, 0)
        layout.addWidget(w_logo, 1, 0, Qt.AlignBottom | Qt.AlignHCenter)
        layout.addWidget(self._pages, 0, 1, 2, 1)
        layout.setContentsMargins(1, 1, 1, 1)

        self.setGeometry(0, 0, 1250, 800)
        self.setMinimumSize(QtCore.QSize(700, 600))
        self._is_initialized = True

        self._restore_geometry()
        self.show()

        # finally load (demo) - settings
        if settings is None:
            self.load_settings(self.environ.demo_settings)
        elif os.path.isfile(settings):
            self.load_settings(settings)
        else:
            QMessageBox.warning(
                self, "Warning", "File (%s) does not exist" %settings)

    def dragEnterEvent(self, event):
        event.acceptProposedAction()

    def dragMoveEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event):
        mimeData = event.mimeData()
        if mimeData.hasUrls():
            if len(mimeData.urls()) == 1:
                self.load_settings(fix_path(mimeData.urls()[0].path()))
                # self._on_load_input()
        event.acceptProposedAction()

    def dragLeaveEvent(self, event):
        event.accept()

    def _save_geometry(self):
        settings = QtCore.QSettings(version.organisation, version.appname)
        settings.beginGroup('Gui')
        settings.setValue('state', self.saveState())
        settings.setValue('geometry', self.saveGeometry())

        try:
            settings.setValue(
                'clusterjobs', self._pages.widgetByType(
                    ClusterFrame).get_jobids())
        except KeyError:
            pass

        settings.endGroup()

    def _restore_geometry(self):
        settings = QtCore.QSettings(version.organisation, version.appname)
        settings.beginGroup('Gui')

        if settings.contains('geometry'):
            self.restoreGeometry(settings.value('geometry'))

        if settings.contains('state'):
            self.restoreState(settings.value('state'))

        if settings.contains('clusterjobs'):
            jobids = settings.value('clusterjobs')
            if AppPreferences().cluster_support and jobids:
                self._pages.widgetByType(ClusterFrame).restore_jobids(jobids)

        settings.endGroup()

    def closeEvent(self, event):
        self._pages.close()
        # Quit dialog only if not debuging flag is not set
        self._save_geometry()
        if self.debug:
            QtWidgets.QApplication.exit()
        ret = QMessageBox.question(self, "Quit %s" %self.appname,
                                   "Do you really want to quit?",
                                   QMessageBox.Yes|QMessageBox.No)

        if ret == QMessageBox.No:
            event.ignore()
        else:
            self._check_settings_saved(QMessageBox.Yes|QMessageBox.No)
            QtWidgets.QApplication.exit()

    def settings_changed(self, changed):
        if self._is_initialized:
            self.setWindowModified(changed)
            self.action_save.setEnabled(changed)
            self.modified.emit(changed)

    def _add_page(self, widget):
        button = QtWidgets.QListWidgetItem(self._selection)
        button.setIcon(QtGui.QIcon(widget.ICON))
        button.setText(widget.get_name())
        button.setTextAlignment(Qt.AlignHCenter)
        self._pages.addWidget(widget)

        widget.toggle_tabs.connect(self._on_toggle_tabs)
        self._tab_lookup[widget.get_name()] = (button, widget)
        return widget.size()

    def _on_toggle_tabs(self, name):
        """Toggle ItemIsEnabled flag for all list items but name."""
        for name2 in self._tab_lookup:
            if name2 != name:
                item, _ = self._tab_lookup[name2]
                flags = item.flags()
                # check flag (and)
                if flags & Qt.ItemIsEnabled:
                    # remove flag (nand)
                    item.setFlags(flags & ~Qt.ItemIsEnabled)
                else:
                    # set flag (or)
                    item.setFlags(flags | Qt.ItemIsEnabled)

    def _on_change_page(self, current, previous):
        if not current:
            current = previous
        index = self._selection.row(current)
        self._pages.setCurrentIndex(index)
        widget = self._pages.widget(index)
        widget.page_changed()

    def _check_settings_saved(
            self, buttons=QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel):
        if self.isWindowModified():
            result = QMessageBox.question(
                self, "Settings have been modified",
                "Do you want to save the settings?",
                buttons)

            if result == QMessageBox.Yes:
                self.save_settings()
        else:
            result = QMessageBox.No
        return result

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(self, text, slot=None, shortcut=None, icon=None,
                      tooltip=None, checkable=None, signal='triggered',
                      checked=False):
        action = QtWidgets.QAction(text, self)
        if icon is not None:
            action.setIcon(QtGui.QIcon(':/%s.png' % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tooltip is not None:
            action.setToolTip(tooltip)
            action.setStatusTip(tooltip)
        if slot is not None:
            getattr(action, signal).connect(slot)
        if checkable is not None:
            action.setCheckable(True)
        action.setChecked(checked)
        return action

    def save_settings(self, save_as=False):
        filename = self._settings_filename
        if filename is None or save_as:
            filename = self._get_save_as_filename()
        if not filename is None:
            self._write_settings(filename)

    def load_settings(self, filename):
        try:
            self._settings.read(filename)
        except Exception as e:
            QMessageBox.critical(self, "Error",
                                 ("Error loading settings file\n"
                                  "Could not load settings file '%s'.\n%s"
                                  %(filename, str(e))))
            self.statusBar().showMessage('Error loading settings files.')
        else:
            self._settings_filename = filename
            title = self.windowTitle().split(' - ')[0]
            self.setWindowTitle('%s - %s[*]' % (title, filename))
            try:
                # reset naming scheme to load config file completely
                nst = self._settings.get_trait("General",  "namingscheme")
                namingscheme_file = self._settings("General", "namingscheme")
                if not namingscheme_file in nst.list_data:
                    self._settings.set("General", "namingscheme", nst.default_value)
                    QMessageBox.warning(self, "Unkown naming scheme",
                                        ("%s-%s can not use the naming scheme '%s'."
                                         " Resetting to default '%s'"
                                         %(version.appname, version.version,
                                           namingscheme_file, nst.default_value)))

                for widget in self._tabs:
                    widget.update_input()
            except Exception as e:
                msg = "Could not load settings file (%s)\n.%s" \
                      %(filename, traceback.format_exc())
                QMessageBox.critical(self, "Error", msg)

            else:
                # set settings to not-changed (assume no changed since loaded from file)
                self.settings_changed(False)
                # notify tabs about new settings loaded
                for tab in self._tabs:
                    tab.settings_loaded()
                self.statusBar().showMessage('Settings successfully loaded.')

    def _write_settings(self, filename):
        try:
            f = file(filename, 'w')
            # create a new version (copy) of the current
            # settings which add the needed rendering information
            pframe = self._tab_lookup[SECTION_NAME_PROCESSING][1]
            settings_dummy = pframe.get_export_settings(self._settings)
            settings_dummy.write(f)
            f.close()
        except Exception as e:
            msg = "Could not save settings\n%s" %str(e)
            QMessageBox.critical(self, "Error", msg)
            self.statusBar().showMessage('Settings not successfully saved.')
        else:
            self._settings_filename = filename
            self.setWindowTitle('%s - %s[*]' % (self.appname, filename))
            self.settings_changed(False)
            self.statusBar().showMessage('Settings successfully saved.')

    def on_about(self):
        dialog = CecogAboutDialog(self)
        dialog.show()

    def about_qt(self):
        QMessageBox.aboutQt(self, "about Qt")

    def open_preferences(self):
        pref = PreferencesDialog(self)
        pref.exec_()

    def updateStyleSheet(self, stylesheet):
        self.setStyleSheet("")
        self.setStyleSheet(stylesheet)

        self._pages.assistant.setStyleSheet("")
        self._pages.assistant.setStyleSheet(stylesheet)

        if self._browser is not None:
            self._browser.setStyleSheet("")
            self._browser.setStyleSheet(stylesheet)

    def _on_browser_open(self):
        if self._imagecontainer is None:
            QMessageBox.warning(self, 'Data structure not loaded',
                                'The input directory structure file was not loaded.\n'
                                'Click "Scan input directory" in section "General" to proceed.')
        elif self._browser is None:
            try:
                browser = Browser(self._settings, self._imagecontainer, None)
                browser.show()
                browser.raise_()
                browser.setFocus()
                app = AppPreferences()
                browser.setStyleSheet(loadStyle(app.stylesheet))
                self._browser = browser
            except Exception as e:
                traceback.print_exc()
                QMessageBox.critical(self, "Error", str(e))
        else:
            self._browser.show()
            self._browser.raise_()

    def _on_load_input(self):
        txt = "Error scanning image structure"
        path_in = self._settings.get(SECTION_NAME_GENERAL, 'pathin')
        if path_in == '':
            QMessageBox.critical(self, "Error", "%s\nImage path must be defined." %txt)
        elif not os.path.isdir(path_in) and \
             not os.path.isdir(os.path.join(self.environ.package_dir, path_in)):
            QMessageBox.critical(self, "Error", "%s\nImage path '%s' not found."
                                 %(txt, path_in))
        else:
            try:
                infos = list(ImageContainer.iter_check_plates(self._settings))
            except Exception as e:
                QMessageBox.critical(self, "Error", "%s\n%s" %(txt, str(e)))
            else:
                found_any = numpy.any([not info[3] is None for info in infos])
                cancel = False
                if found_any:
                    found_plates = [info[0] for info in infos
                                    if not info[3] is None]
                    missing_plates = [info[0] for info in infos
                                      if info[3] is None]
                    has_missing = len(missing_plates) > 0
                    txt = '%s plates were already scanned.\nDo you want ' \
                          'to rescan the file structure(s)? ' \
                          'This can take several minutes.' % \
                          ('Some' if has_missing else 'All')
                    title = 'Rescan input structure?'

                    box = QMessageBox(QMessageBox.Question, title, title,
                                      QMessageBox.Cancel, self, Qt.Sheet)
                    box.setWindowModality(Qt.WindowModal)
                    box.setInformativeText(txt)
                    box.setDetailedText('Plates with scanned structure: \n%s\n'
                                        '\nPlates without scanned structure: '
                                        '\n%s' %
                                        ('\n'.join(found_plates),
                                         '\n'.join(missing_plates)))
                    if not has_missing:
                        btn1 = QtWidgets.QPushButton('No', box)
                        box.addButton(btn1, QMessageBox.NoRole)
                        box.setDefaultButton(btn1)
                    elif len(found_plates) > 0:
                        btn1 = QtWidgets.QPushButton('Rescan missing', box)
                        box.addButton(btn1, QMessageBox.YesRole)
                        box.setDefaultButton(btn1)
                    else:
                        btn1 = None

                    btn2 = QtWidgets.QPushButton('Rescan all', box)
                    box.addButton(btn2, QMessageBox.YesRole)

                    if box.exec_() == QMessageBox.Cancel:
                        cancel = True
                    else:
                        btn = box.clickedButton()
                        if btn == btn1:
                            if has_missing:
                                scan_plates = dict([(info[0], info[0] in missing_plates) for info in infos])
                            else:
                                scan_plates = dict((info[0], False) for info in infos)
                        else:
                            scan_plates = dict((info[0], True) for info in infos)
                else:
                    has_multiple = self._settings.get(SECTION_NAME_GENERAL,
                                                      "has_multiple_plates")
                    ret = QMessageBox.question(self, "No structure data found",
                                               ("Scanning the input directory can be time "
                                                "consuming.\n\nDo you want to proceed?"),
                                               QMessageBox.Yes|QMessageBox.No)
                    if ret == QMessageBox.No:
                        cancel = True
                    scan_plates = dict((info[0], True) for info in infos)

                if not cancel:
                    self._load_image_container(infos, scan_plates)

    def _load_image_container(self, plate_infos=None, scan_plates=None,
                              show_dialog=True):
        self._clear_browser()

        if plate_infos is None:
            plate_infos = list(ImageContainer.iter_check_plates(self._settings))

        imagecontainer = ImageContainer()
        self._imagecontainer = imagecontainer

        if scan_plates is None:
            scan_plates = dict((info[0], False) for info in plate_infos)

        def load(emitter, icontainer, settings, splates):
            iter_ = icontainer.iter_import_from_settings(settings, scan_plates=splates)
            for idx, info in enumerate(iter_):
                emitter.setValue.emit(idx)

            emitter.setLabelText.emit("checking dimensions...")
            emitter.setRange.emit(0, 0)
            QtCore.QCoreApplication.processEvents()

            if len(icontainer.plates) > 0:
                icontainer.set_plate(icontainer.plates[0])
                icontainer.check_dimensions()


        label = ('Please wait until the input structure is scanned\n'
                 'or the structure data loaded...')
        self._dlg = ProgressDialog(label, None, 0, len(scan_plates), self)
        emitter = ProgressObject()
        emitter.setRange.connect(self._dlg.setRange)
        emitter.setValue.connect(self._dlg.setValue)
        emitter.setLabelText.connect(self._dlg.setLabelText)

        try:
            func = lambda: load(emitter, imagecontainer,
                                self._settings, scan_plates)
            self._dlg.exec_(func, (emitter, ))
        except ImportError as e:
            # structure file from versions older than 1.3 contain pdk which is
            # removed
            if 'pdk' in str(e):
                QMessageBox.critical(self, "Error",
                                     ("Your structure file format is outdated.\n"
                                      "You have to rescan the plate(s)"))
            else:
                QMessageBox.critical(self, "Error", traceback.format_exc())
            return
        except Exception as e:
            QMessageBox.critical(self, "Error", str(e))


        try: # I hate lookup tables!
            self._tab_lookup['Cluster'][1].set_imagecontainer(imagecontainer)
        except KeyError:
            pass

        if len(imagecontainer.plates) > 0:
            channels = imagecontainer.channels

            # do not report value changes to the main window
            self._settings.set_notify_change(False)

            self.set_image_crop_size()

            problems = []
            for prefix in ['primary', 'secondary', 'tertiary']:
                trait = self._settings.get_trait(SECTION_NAME_OBJECTDETECTION,
                                                 '%s_channelid' % prefix)
                if trait.set_list_data(channels) is None:
                    problems.append(prefix)
                self._tabs[1].get_widget('%s_channelid' % prefix).update()

            # report problems about a mismatch between channel IDs found in the data
            # and specified by the user
            if len(problems) > 0:
                # a mismatch between settings and data will cause changed settings
                self.settings_changed(True)

            trait = self._settings.get_trait(SECTION_NAME_EVENT_SELECTION,
                                             'duration_unit')

            # allow time-base tracking durations only if time-stamp
            # information is present
            meta_data = imagecontainer.get_meta_data()
            if meta_data.has_timestamp_info:
                result = trait.set_list_data(TimeConverter.units)
            else:
                result = trait.set_list_data([TimeConverter.FRAMES])
            if result is None:
                QMessageBox.critical(self, "Could not set tracking duration units",
                                     ("The tracking duration units selected to match the "
                                      "load data. Please check your settings."))
                # a mismatch between settings and data will cause changed settings
                self.settings_changed(True)

            # activate change notification again
            self._settings.set_notify_change(True)


            self.set_modules_active(state=True)
            if show_dialog:
                QMessageBox.information(
                    self, "Information",
                    "%d plate(s) successfully loaded." % len(imagecontainer.plates))
        else:
            QMessageBox.critical(self, "Error",
                                 ("No images found\n"
                                  "Verifiy your nameing scheme and rescan the data."))

    def set_image_crop_size(self):
        x0, y0, x1, y1 = self._settings.get('General', 'crop_image_x0'), \
                         self._settings.get('General', 'crop_image_y0'), \
                         self._settings.get('General', 'crop_image_x1'), \
                         self._settings.get('General', 'crop_image_y1')

        x0_, y0_, x1_, y1_ = 0, \
                             0, \
                             self._imagecontainer.get_meta_data().dim_x, \
                             self._imagecontainer.get_meta_data().dim_y

        tr_x0 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_x0')
        tr_y0 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_y0')
        tr_x1 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_x1')
        tr_y1 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_y1')

        # Check if the crop values are valid
        if x0 > 0 and y0 > 0 and x1 <= x1_ and y1 <= y1_ and \
                x0 != x1 and y0 != y1:
            # Set to default values
            tr_x0.set_value(tr_x0.get_widget(), x0)
            tr_y0.set_value(tr_y0.get_widget(), y0)
            tr_x1.set_value(tr_x1.get_widget(), x1)
            tr_y0.set_value(tr_y1.get_widget(), y1)
        else:
            tr_x0.set_value(tr_x0.get_widget(), x0_)
            tr_y0.set_value(tr_y0.get_widget(), y0_)
            tr_x1.set_value(tr_x1.get_widget(), x1_)
            tr_y0.set_value(tr_y1.get_widget(), y1_)

        # Set GUI widget valid ranges
        tr_x0.set_min_value(x0_)
        tr_x0.set_max_value(x1_)
        tr_y0.set_min_value(y0_)
        tr_y0.set_max_value(y1_)
        tr_x1.set_min_value(x0_)
        tr_x1.set_max_value(x1_)
        tr_y1.set_min_value(y0_)
        tr_y1.set_max_value(y1_)

    def set_modules_active(self, state=True):
        for name, (button, widget) in self._tab_lookup.iteritems():
            widget.set_active(state)

    @QtCore.pyqtSlot()
    def _on_file_open(self):

        if self._check_settings_saved() != QMessageBox.Cancel:
            home = ""
            if self._settings_filename is not None:
                settings_filename = self.environ.demo_settings
                if os.path.isfile(settings_filename):
                    home = settings_filename
            filename = QtWidgets.QFileDialog.getOpenFileName( \
               self, 'Open config file', home, ';;'.join(self.NAME_FILTERS))[0]
            if not bool(filename):
                return

            try:
                self.load_settings(filename)
                if self._settings.was_old_file_format():
                    QMessageBox.information(
                        self, 'Information',
                        'Config file was updated to version %s' %self.version)
            except Exception as e:
                msg = "File could not be loaded\n%s" %str(e)
                QMessageBox.critical(self, "Error", msg)
            finally:
                self._clear_browser()
                self.set_modules_active(state=False)


    @QtCore.pyqtSlot()
    def _on_file_save(self):
        self.save_settings(False)

    @QtCore.pyqtSlot()
    def _on_file_save_as(self):
        self.save_settings(True)

    def _clear_browser(self):
        if not self._browser is None:
            self._browser.close()
            self._browser = None

    def _on_show_log_window(self):
        self._pages.showLogWindow()

    def _get_save_as_filename(self):
        dir = ""
        if self._settings_filename is not None:
            settings_filename = self.environ.demo_settings
            if os.path.isfile(settings_filename):
                dir = settings_filename
        filename = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save config file as', dir, ';;'.join(self.NAME_FILTERS))[0]
        return filename or None

    def show_assistant(self):
        self._pages.assistant.show()
        self._pages.assistant.openKeyword('index')
Пример #19
0
    def __init__(self,
                 appname,
                 version,
                 redirect,
                 settings=None,
                 debug=False,
                 *args,
                 **kw):
        super(CecogAnalyzer, self).__init__(*args, **kw)
        self.setWindowTitle("%s-%s" % (appname, version) + '[*]')
        self.setAcceptDrops(True)
        self.setCentralWidget(QtWidgets.QFrame(self))
        self.setObjectName(appname)

        self.version = version
        self.appname = appname
        self.debug = debug

        self.environ = CecogEnvironment(version=version,
                                        redirect=redirect,
                                        debug=debug)

        if debug:
            self.environ.pprint()

        self._is_initialized = False
        self._imagecontainer = None
        self._meta_data = None
        self._browser = None

        action_quit = self.create_action('&Quit', slot=self.close)
        action_pref = self.create_action('&Preferences',
                                         slot=self.open_preferences)

        action_load = self.create_action('&Load Settings...',
                                         shortcut=QtGui.QKeySequence.Open,
                                         slot=self._on_file_open)
        action_save = self.create_action('&Save Settings',
                                         shortcut=QtGui.QKeySequence.Save,
                                         slot=self._on_file_save)
        self.action_save = action_save
        action_save_as = self.create_action('&Save Settings As...',
                                            shortcut=QtGui.QKeySequence.SaveAs,
                                            slot=self._on_file_save_as)

        menu_file = self.menuBar().addMenu('&File')
        self.add_actions(menu_file,
                         (action_pref, None, action_load, None, action_save,
                          action_save_as, None, action_quit))

        action_log = self.create_action('&Log window',
                                        shortcut=QtGui.QKeySequence(Qt.CTRL +
                                                                    Qt.Key_L),
                                        slot=self._on_show_log_window)

        action_open = self.create_action('&Browser',
                                         shortcut=QtGui.QKeySequence('CTRL+B'),
                                         slot=self._on_browser_open)

        menu_view = self.menuBar().addMenu('&View')
        self.add_actions(menu_view, (action_log, ))
        self.add_actions(menu_view, (action_open, ))

        action_assistant = self.create_action(
            '&Help',
            shortcut=QtGui.QKeySequence.HelpContents,
            slot=self.show_assistant)
        action_about = self.create_action('&About', slot=self.on_about)
        action_aboutQt = self.create_action('&About Qt', slot=self.about_qt)

        menu_help = self.menuBar().addMenu('&Help')
        self.add_actions(menu_help,
                         (action_assistant, action_about, action_aboutQt))

        self.setStatusBar(QtWidgets.QStatusBar(self))

        self._selection = QtWidgets.QListWidget(self.centralWidget())
        self._selection.setViewMode(QtWidgets.QListView.IconMode)
        self._selection.setIconSize(QtCore.QSize(35, 35))
        self._selection.setGridSize(QtCore.QSize(140, 60))
        self._selection.setMovement(QtWidgets.QListView.Static)
        self._selection.setMaximumWidth(self._selection.gridSize().width() + 5)
        self._selection.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._selection.setSizePolicy(
            QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                  QtWidgets.QSizePolicy.Expanding))

        self._pages = FrameStack(self)

        self._settings_filename = None
        self._settings = GuiConfigSettings(self)

        self._tab_lookup = OrderedDict()
        self._tabs = [
            GeneralFrame(self._settings, self._pages, SECTION_NAME_GENERAL),
            ObjectDetectionFrame(self._settings, self._pages,
                                 SECTION_NAME_OBJECTDETECTION),
            FeatureExtractionFrame(self._settings, self._pages,
                                   SECTION_NAME_FEATURE_EXTRACTION),
            ClassificationFrame(self._settings, self._pages,
                                SECTION_NAME_CLASSIFICATION),
            TrackingFrame(self._settings, self._pages, SECTION_NAME_TRACKING),
            EventSelectionFrame(self._settings, self._pages,
                                SECTION_NAME_EVENT_SELECTION),
            ErrorCorrectionFrame(self._settings, self._pages,
                                 SECTION_NAME_ERRORCORRECTION),
            OutputFrame(self._settings, self._pages, SECTION_NAME_OUTPUT),
            ProcessingFrame(self._settings, self._pages,
                            SECTION_NAME_PROCESSING)
        ]

        # connections for the section frames
        self._tabs[3].connect_browser_btn(self._on_browser_open)
        for frame in self._tabs:
            frame.status_message.connect(self.statusBar().showMessage)

        app = AppPreferences()
        if app.cluster_support:
            clusterframe = ClusterFrame(self._settings, self._pages,
                                        SECTION_NAME_CLUSTER)
            clusterframe.set_imagecontainer(self._imagecontainer)
            self._tabs.append(clusterframe)

        try:
            self.updateStyleSheet(loadStyle(app.stylesheet))
        except Exception as e:
            # proceed with no stylesheet
            traceback.print_exc()

        widths = []
        for tab in self._tabs:
            size = self._add_page(tab)
            widths.append(size.width())
        self.set_modules_active(state=False)
        self._pages.setMinimumWidth(max(widths) + 45)

        self._selection.currentItemChanged.connect(self._on_change_page)
        self._selection.setCurrentRow(0)

        w_logo = QtWidgets.QLabel(self.centralWidget())
        w_logo.setPixmap(QtGui.QPixmap(':cecog_logo_w145'))

        layout = QtWidgets.QGridLayout(self.centralWidget())
        layout.addWidget(self._selection, 0, 0)
        layout.addWidget(w_logo, 1, 0, Qt.AlignBottom | Qt.AlignHCenter)
        layout.addWidget(self._pages, 0, 1, 2, 1)
        layout.setContentsMargins(1, 1, 1, 1)

        self.setGeometry(0, 0, 1250, 800)
        self.setMinimumSize(QtCore.QSize(700, 600))
        self._is_initialized = True

        self._restore_geometry()
        self.show()

        # finally load (demo) - settings
        if settings is None:
            self.load_settings(self.environ.demo_settings)
        elif os.path.isfile(settings):
            self.load_settings(settings)
        else:
            QMessageBox.warning(self, "Warning",
                                "File (%s) does not exist" % settings)
Пример #20
0
    def __init__(self, appname, version, redirect, debug=False, *args, **kw):
        super(CecogAnalyzer, self).__init__(*args, **kw)
        self.setWindowTitle("%s-%s" %(appname, version) + '[*]')
        self.setCentralWidget(QtGui.QFrame(self))
        self.setObjectName(appname)

        self.version = version
        self.appname = appname
        self.debug = debug

        self.environ = CecogEnvironment(version, redirect=redirect, debug=debug)
        if debug:
            self.environ.pprint()

        self._is_initialized = False
        self._imagecontainer = None
        self._meta_data = None
        self._browser = None

        action_quit = self.create_action('&Quit', slot=self.close)
        action_pref = self.create_action('&Preferences',
                                         slot=self.open_preferences)

        action_open = self.create_action('&Open Settings...',
                                         shortcut=QtGui.QKeySequence.Open,
                                         slot=self._on_file_open)
        action_save = self.create_action('&Save Settings',
                                         shortcut=QtGui.QKeySequence.Save,
                                         slot=self._on_file_save)
        self.action_save = action_save
        action_save_as = self.create_action('&Save Settings As...',
                                            shortcut=QtGui.QKeySequence.SaveAs,
                                            slot=self._on_file_save_as)
        menu_file = self.menuBar().addMenu('&File')
        self.add_actions(menu_file, (action_pref,
                                     None, action_open,
                                     None, action_save, action_save_as,
                                     None, action_quit))

        action_open = self.create_action('&Open Browser...',
                                         shortcut=QtGui.QKeySequence('CTRL+B'),
                                         slot=self._on_browser_open)
        menu_browser = self.menuBar().addMenu('&Browser')
        self.add_actions(menu_browser, (action_open, ))

        action_log = self.create_action('&Show Log Window...',
                                        shortcut=QtGui.QKeySequence(Qt.CTRL + Qt.Key_L),
                                        slot=self._on_show_log_window)
        menu_window = self.menuBar().addMenu('&Window')
        self.add_actions(menu_window, (action_log,))

        action_help_startup = self.create_action('&Startup Help...',
                                                 shortcut=QtGui.QKeySequence.HelpContents,
                                                 slot=self._on_help_startup)
        action_about = self.create_action('&About', slot=self.on_about)

        menu_help = self.menuBar().addMenu('&Help')
        self.add_actions(menu_help, (action_help_startup, action_about))

        qApp._main_window = self
        qApp._statusbar = QtGui.QStatusBar(self)
        self.setStatusBar(qApp._statusbar)

        self._selection = QtGui.QListWidget(self.centralWidget())
        self._selection.setViewMode(QtGui.QListView.IconMode)
        self._selection.setIconSize(QtCore.QSize(35, 35))
        self._selection.setGridSize(QtCore.QSize(140, 60))
        self._selection.setMovement(QtGui.QListView.Static)
        self._selection.setMaximumWidth(self._selection.gridSize().width() + 5)
        self._selection.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._selection.setSizePolicy(
            QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
                              QtGui.QSizePolicy.Expanding))

        self._pages = QtGui.QStackedWidget(self.centralWidget())
        self._pages.main_window = self

        self._settings_filename = None
        self._settings = GuiConfigSettings(self, SECTION_REGISTRY)

        self._tab_lookup = OrderedDict()
        self._tabs = [GeneralFrame(self._settings, self._pages),
                      ObjectDetectionFrame(self._settings, self._pages),
                      FeatureExtractionFrame(self._settings, self._pages),
                      ClassificationFrame(self._settings, self._pages),
                      TrackingFrame(self._settings, self._pages),
                      ErrorCorrectionFrame(self._settings, self._pages),
                      PostProcessingFrame(self._settings, self._pages),
                      OutputFrame(self._settings, self._pages),
                      ProcessingFrame(self._settings, self._pages)]

        if self.environ.analyzer_config.get('Analyzer', 'cluster_support'):
            self._tabs.append(ClusterFrame(self._settings, self._pages,
                                           self._imagecontainer))

        widths = []
        for tab in self._tabs:
            size = self._add_page(tab)
            widths.append(size.width())
        self.set_modules_active(state=False)
        self._pages.setMinimumWidth(max(widths) + 45)

        self._selection.currentItemChanged.connect(self._on_change_page)
        self._selection.setCurrentRow(0)

        w_logo = QtGui.QLabel(self.centralWidget())
        w_logo.setPixmap(QtGui.QPixmap(':cecog_logo_w145'))

        layout = QtGui.QGridLayout(self.centralWidget())
        layout.addWidget(self._selection, 0, 0)
        layout.addWidget(w_logo, 1, 0, Qt.AlignBottom | Qt.AlignHCenter)
        layout.addWidget(self._pages, 0, 1, 2, 1)
        layout.setContentsMargins(1, 1, 1, 1)

        handler = GuiLogHandler(self)
        handler.setLevel(logging.INFO)
        formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
        handler.setFormatter(formatter)

        self.log_window = LogWindow(self, handler)
        self.log_window.setGeometry(50, 50, 600, 300)

        logger = logging.getLogger()
        logger.setLevel(logging.INFO)

        qApp._image_dialog = None
        qApp._graphics = None

        self.setGeometry(0, 0, 1200, 700)
        self.setMinimumSize(QtCore.QSize(700, 600))
        self._is_initialized = True
Пример #21
0
    for idx, info in enumerate(import_iter):
        pass

    if len(imagecontainer.plates) > 0:
        plate = imagecontainer.plates[0]
        imagecontainer.set_plate(plate)
    return imagecontainer


def load_settings(settings_file):
    settings = GuiConfigSettings(None)
    settings.read(settings_file)
    return settings


if __name__ == "__main__":
    import sys
    from cecog.environment import CecogEnvironment
    from cecog.version import version
    environ = CecogEnvironment(version)
    app = QApplication(sys.argv)

    settings = load_settings((r'C:\Users\sommerc\data\cecog'
                              '\Settings\exp911_version_150.conf'))
    imagecontainer = load_image_container_from_settings(settings)

    browser = Browser(settings, imagecontainer)

    browser.show()
    app.exec_()
Пример #22
0
    def __init__(self, appname, version, redirect, settings=None, debug=False, *args, **kw):
        super(CecogAnalyzer, self).__init__(*args, **kw)
        self.setWindowTitle("%s-%s" %(appname, version) + '[*]')
        self.setCentralWidget(QtGui.QFrame(self))
        self.setObjectName(appname)

        self.version = version
        self.appname = appname
        self.debug = debug

        self.environ = CecogEnvironment(version=version, redirect=redirect, debug=debug)
        if debug:
            self.environ.pprint()

        self._is_initialized = False
        self._imagecontainer = None
        self._meta_data = None
        self._browser = None

        action_quit = self.create_action('&Quit', slot=self.close)
        action_pref = self.create_action('&Preferences',
                                         slot=self.open_preferences)

        action_open = self.create_action('&Open Settings...',
                                         shortcut=QtGui.QKeySequence.Open,
                                         slot=self._on_file_open)
        action_save = self.create_action('&Save Settings',
                                         shortcut=QtGui.QKeySequence.Save,
                                         slot=self._on_file_save)
        self.action_save = action_save
        action_save_as = self.create_action('&Save Settings As...',
                                            shortcut=QtGui.QKeySequence.SaveAs,
                                            slot=self._on_file_save_as)
        menu_file = self.menuBar().addMenu('&File')
        self.add_actions(menu_file, (action_pref,
                                     None, action_open,
                                     None, action_save, action_save_as,
                                     None, action_quit))

        action_open = self.create_action('&Open Browser...',
                                         shortcut=QtGui.QKeySequence('CTRL+B'),
                                         slot=self._on_browser_open)
        menu_browser = self.menuBar().addMenu('&Browser')
        self.add_actions(menu_browser, (action_open, ))

        action_log = self.create_action('&Show Log Window...',
                                        shortcut=QtGui.QKeySequence(Qt.CTRL+Qt.Key_L),
                                        slot=self._on_show_log_window)
        menu_window = self.menuBar().addMenu('&Window')
        self.add_actions(menu_window, (action_log,))

        action_help_startup = self.create_action('&Startup Help...',
                                                 shortcut=QtGui.QKeySequence.HelpContents,
                                                 slot=self._on_help_startup)
        action_about = self.create_action('&About', slot=self.on_about)

        menu_help = self.menuBar().addMenu('&Help')
        self.add_actions(menu_help, (action_help_startup, action_about))

        self.setStatusBar(QtGui.QStatusBar(self))

        self._selection = QtGui.QListWidget(self.centralWidget())
        self._selection.setViewMode(QtGui.QListView.IconMode)
        self._selection.setIconSize(QtCore.QSize(35, 35))
        self._selection.setGridSize(QtCore.QSize(140, 60))
        self._selection.setMovement(QtGui.QListView.Static)
        self._selection.setMaximumWidth(self._selection.gridSize().width() + 5)
        self._selection.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._selection.setSizePolicy(
            QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
                              QtGui.QSizePolicy.Expanding))

        self._pages = FrameStack(self)

        self._settings_filename = None
        self._settings = GuiConfigSettings(self)

        self._tab_lookup = OrderedDict()
        self._tabs = [GeneralFrame(self._settings, self._pages, SECTION_NAME_GENERAL),
                      ObjectDetectionFrame(self._settings, self._pages, SECTION_NAME_OBJECTDETECTION),
                      FeatureExtractionFrame(self._settings, self._pages, SECTION_NAME_FEATURE_EXTRACTION),
                      ClassificationFrame(self._settings, self._pages, SECTION_NAME_CLASSIFICATION),
                      TrackingFrame(self._settings, self._pages, SECTION_NAME_TRACKING),
                      EventSelectionFrame(self._settings, self._pages, SECTION_NAME_EVENT_SELECTION),
                      ErrorCorrectionFrame(self._settings, self._pages, SECTION_NAME_ERRORCORRECTION),
                      PostProcessingFrame(self._settings, self._pages, SECTION_NAME_POST_PROCESSING),
                      OutputFrame(self._settings, self._pages, SECTION_NAME_OUTPUT),
                      ProcessingFrame(self._settings, self._pages, SECTION_NAME_PROCESSING)]

        # connections for the section frames
        self._tabs[3].connect_browser_btn(self._on_browser_open)
        for frame in self._tabs:
            frame.status_message.connect(self.statusBar().showMessage)

        if self.environ.analyzer_config.get('Analyzer', 'cluster_support'):
            clusterframe = ClusterFrame(self._settings, self._pages, SECTION_NAME_CLUSTER)
            clusterframe.set_imagecontainer(self._imagecontainer)
            self._tabs.append(clusterframe)

        widths = []
        for tab in self._tabs:
            size = self._add_page(tab)
            widths.append(size.width())
        self.set_modules_active(state=False)
        self._pages.setMinimumWidth(max(widths) + 45)

        self._selection.currentItemChanged.connect(self._on_change_page)
        self._selection.setCurrentRow(0)

        w_logo = QtGui.QLabel(self.centralWidget())
        w_logo.setPixmap(QtGui.QPixmap(':cecog_logo_w145'))

        layout = QtGui.QGridLayout(self.centralWidget())
        layout.addWidget(self._selection, 0, 0)
        layout.addWidget(w_logo, 1, 0, Qt.AlignBottom | Qt.AlignHCenter)
        layout.addWidget(self._pages, 0, 1, 2, 1)
        layout.setContentsMargins(1, 1, 1, 1)

        handler = GuiLogHandler(self)
        handler.setLevel(logging.INFO)
        formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
        handler.setFormatter(formatter)

        self.log_window = LogWindow(self, handler)
        self.log_window.setGeometry(50, 50, 600, 300)

        logger = logging.getLogger()
        logger.setLevel(logging.INFO)

        self.setGeometry(0, 0, 1250, 800)
        self.setMinimumSize(QtCore.QSize(700, 600))
        self._is_initialized = True

        # finally load (demo) - settings
        if settings is None:
            self.load_settings(self.environ.demo_settings)
        elif os.path.isfile(settings):
            self.load_settings(settings)
        else:
            raise RuntimeError("settings file does not exits (%s)" %settings)
Пример #23
0
    def load_classifier(self, check=True):
        _resolve = lambda x, y: self._settings.get(
            x, '%s_%s' % (self._channel, y))
        clfdir = CecogEnvironment.convert_package_path(
            _resolve('Classification', 'classification_envpath'))
        # XXX - where does the "." come
        if not isdir(clfdir) or clfdir == ".":
            return
        else:
            self._learner = CommonClassPredictor( \
                clf_dir=clfdir,
                name=self._channel,
                channels={self._channel.title(): _resolve('Classification', 'classification_regionname')},
                color_channel=_resolve('ObjectDetection', 'channelid'))
            result = self._learner.check()

            if check:
                b = lambda x: 'Yes' if x else 'No'
                msg = 'Classifier path: %s\n' % result['path_env']
                msg += 'Found class definition: %s\n' % b(
                    result['has_definition'])
                msg += 'Found annotations: %s\n' % b(
                    result['has_path_annotations'])
                msg += 'Can you pick new samples? %s\n\n' % b(
                    self.is_pick_samples())
                msg += 'Found ARFF file: %s\n' % b(result['has_arff'])
                msg += 'Can you train a classifier? %s\n\n' % b(
                    self.is_train_classifier())
                msg += 'Found SVM model: %s\n' % b(result['has_model'])
                msg += 'Found SVM range: %s\n' % b(result['has_range'])
                msg += 'Can you apply the classifier to images? %s\n\n' % b(
                    self.is_apply_classifier())
                msg += 'Found samples: %s\n' % b(result['has_path_samples'])
                msg += 'Sample images are only used for visualization and annotation control at the moment.'

                txt = '%s classifier inspection results' % self._channel
                information(self, txt, info=msg)

            if result['has_arff']:
                self._learner.importFromArff()
                nr_features_prev = len(self._learner.feature_names)
                removed_features = self._learner.filter_nans(apply=True)
                nr_features = nr_features_prev - len(removed_features)
                self._label_features.setText(self.LABEL_FEATURES %
                                             (nr_features, nr_features_prev))
                self._label_features.setToolTip(
                    "removed %d features containing NA values:\n%s" %
                    (len(removed_features), "\n".join(removed_features)))

            if result['has_definition']:
                self._learner.loadDefinition()

            if result['has_conf']:
                c, g, conf = self._learner.importConfusion()
                self._set_info(c, g, conf)
                self._init_conf_table(conf)
                self._update_conf_table(conf)
            else:
                conf = None
                self._init_conf_table(conf)
            self._set_info_table(conf)
Пример #24
0
class CecogAnalyzer(QtWidgets.QMainWindow):

    NAME_FILTERS = ['Settings files (*.conf)', 'All files (*.*)']
    modified = QtCore.pyqtSignal('bool')

    def __init__(self,
                 appname,
                 version,
                 redirect,
                 settings=None,
                 debug=False,
                 *args,
                 **kw):
        super(CecogAnalyzer, self).__init__(*args, **kw)
        self.setWindowTitle("%s-%s" % (appname, version) + '[*]')
        self.setAcceptDrops(True)
        self.setCentralWidget(QtWidgets.QFrame(self))
        self.setObjectName(appname)

        self.version = version
        self.appname = appname
        self.debug = debug

        self.environ = CecogEnvironment(version=version,
                                        redirect=redirect,
                                        debug=debug)

        if debug:
            self.environ.pprint()

        self._is_initialized = False
        self._imagecontainer = None
        self._meta_data = None
        self._browser = None

        action_quit = self.create_action('&Quit', slot=self.close)
        action_pref = self.create_action('&Preferences',
                                         slot=self.open_preferences)

        action_load = self.create_action('&Load Settings...',
                                         shortcut=QtGui.QKeySequence.Open,
                                         slot=self._on_file_open)
        action_save = self.create_action('&Save Settings',
                                         shortcut=QtGui.QKeySequence.Save,
                                         slot=self._on_file_save)
        self.action_save = action_save
        action_save_as = self.create_action('&Save Settings As...',
                                            shortcut=QtGui.QKeySequence.SaveAs,
                                            slot=self._on_file_save_as)

        menu_file = self.menuBar().addMenu('&File')
        self.add_actions(menu_file,
                         (action_pref, None, action_load, None, action_save,
                          action_save_as, None, action_quit))

        action_log = self.create_action('&Log window',
                                        shortcut=QtGui.QKeySequence(Qt.CTRL +
                                                                    Qt.Key_L),
                                        slot=self._on_show_log_window)

        action_open = self.create_action('&Browser',
                                         shortcut=QtGui.QKeySequence('CTRL+B'),
                                         slot=self._on_browser_open)

        menu_view = self.menuBar().addMenu('&View')
        self.add_actions(menu_view, (action_log, ))
        self.add_actions(menu_view, (action_open, ))

        action_assistant = self.create_action(
            '&Help',
            shortcut=QtGui.QKeySequence.HelpContents,
            slot=self.show_assistant)
        action_about = self.create_action('&About', slot=self.on_about)
        action_aboutQt = self.create_action('&About Qt', slot=self.about_qt)

        menu_help = self.menuBar().addMenu('&Help')
        self.add_actions(menu_help,
                         (action_assistant, action_about, action_aboutQt))

        self.setStatusBar(QtWidgets.QStatusBar(self))

        self._selection = QtWidgets.QListWidget(self.centralWidget())
        self._selection.setViewMode(QtWidgets.QListView.IconMode)
        self._selection.setIconSize(QtCore.QSize(35, 35))
        self._selection.setGridSize(QtCore.QSize(140, 60))
        self._selection.setMovement(QtWidgets.QListView.Static)
        self._selection.setMaximumWidth(self._selection.gridSize().width() + 5)
        self._selection.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._selection.setSizePolicy(
            QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                  QtWidgets.QSizePolicy.Expanding))

        self._pages = FrameStack(self)

        self._settings_filename = None
        self._settings = GuiConfigSettings(self)

        self._tab_lookup = OrderedDict()
        self._tabs = [
            GeneralFrame(self._settings, self._pages, SECTION_NAME_GENERAL),
            ObjectDetectionFrame(self._settings, self._pages,
                                 SECTION_NAME_OBJECTDETECTION),
            FeatureExtractionFrame(self._settings, self._pages,
                                   SECTION_NAME_FEATURE_EXTRACTION),
            ClassificationFrame(self._settings, self._pages,
                                SECTION_NAME_CLASSIFICATION),
            TrackingFrame(self._settings, self._pages, SECTION_NAME_TRACKING),
            EventSelectionFrame(self._settings, self._pages,
                                SECTION_NAME_EVENT_SELECTION),
            ErrorCorrectionFrame(self._settings, self._pages,
                                 SECTION_NAME_ERRORCORRECTION),
            OutputFrame(self._settings, self._pages, SECTION_NAME_OUTPUT),
            ProcessingFrame(self._settings, self._pages,
                            SECTION_NAME_PROCESSING)
        ]

        # connections for the section frames
        self._tabs[3].connect_browser_btn(self._on_browser_open)
        for frame in self._tabs:
            frame.status_message.connect(self.statusBar().showMessage)

        app = AppPreferences()
        if app.cluster_support:
            clusterframe = ClusterFrame(self._settings, self._pages,
                                        SECTION_NAME_CLUSTER)
            clusterframe.set_imagecontainer(self._imagecontainer)
            self._tabs.append(clusterframe)

        try:
            self.updateStyleSheet(loadStyle(app.stylesheet))
        except Exception as e:
            # proceed with no stylesheet
            traceback.print_exc()

        widths = []
        for tab in self._tabs:
            size = self._add_page(tab)
            widths.append(size.width())
        self.set_modules_active(state=False)
        self._pages.setMinimumWidth(max(widths) + 45)

        self._selection.currentItemChanged.connect(self._on_change_page)
        self._selection.setCurrentRow(0)

        w_logo = QtWidgets.QLabel(self.centralWidget())
        w_logo.setPixmap(QtGui.QPixmap(':cecog_logo_w145'))

        layout = QtWidgets.QGridLayout(self.centralWidget())
        layout.addWidget(self._selection, 0, 0)
        layout.addWidget(w_logo, 1, 0, Qt.AlignBottom | Qt.AlignHCenter)
        layout.addWidget(self._pages, 0, 1, 2, 1)
        layout.setContentsMargins(1, 1, 1, 1)

        self.setGeometry(0, 0, 1250, 800)
        self.setMinimumSize(QtCore.QSize(700, 600))
        self._is_initialized = True

        self._restore_geometry()
        self.show()

        # finally load (demo) - settings
        if settings is None:
            self.load_settings(self.environ.demo_settings)
        elif os.path.isfile(settings):
            self.load_settings(settings)
        else:
            QMessageBox.warning(self, "Warning",
                                "File (%s) does not exist" % settings)

    def dragEnterEvent(self, event):
        event.acceptProposedAction()

    def dragMoveEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event):
        mimeData = event.mimeData()
        if mimeData.hasUrls():
            if len(mimeData.urls()) == 1:
                self.load_settings(fix_path(mimeData.urls()[0].path()))
                # self._on_load_input()
        event.acceptProposedAction()

    def dragLeaveEvent(self, event):
        event.accept()

    def _save_geometry(self):
        settings = QtCore.QSettings(version.organisation, version.appname)
        settings.beginGroup('Gui')
        settings.setValue('state', self.saveState())
        settings.setValue('geometry', self.saveGeometry())

        try:
            settings.setValue(
                'clusterjobs',
                self._pages.widgetByType(ClusterFrame).get_jobids())
        except KeyError:
            pass

        settings.endGroup()

    def _restore_geometry(self):
        settings = QtCore.QSettings(version.organisation, version.appname)
        settings.beginGroup('Gui')

        if settings.contains('geometry'):
            self.restoreGeometry(settings.value('geometry'))

        if settings.contains('state'):
            self.restoreState(settings.value('state'))

        if settings.contains('clusterjobs'):
            jobids = settings.value('clusterjobs')
            if AppPreferences().cluster_support and jobids:
                self._pages.widgetByType(ClusterFrame).restore_jobids(jobids)

        settings.endGroup()

    def closeEvent(self, event):
        self._pages.close()
        # Quit dialog only if not debuging flag is not set
        self._save_geometry()
        if self.debug:
            QtWidgets.QApplication.exit()
        ret = QMessageBox.question(self, "Quit %s" % self.appname,
                                   "Do you really want to quit?",
                                   QMessageBox.Yes | QMessageBox.No)

        if ret == QMessageBox.No:
            event.ignore()
        else:
            self._check_settings_saved(QMessageBox.Yes | QMessageBox.No)
            QtWidgets.QApplication.exit()

    def settings_changed(self, changed):
        if self._is_initialized:
            self.setWindowModified(changed)
            self.action_save.setEnabled(changed)
            self.modified.emit(changed)

    def _add_page(self, widget):
        button = QtWidgets.QListWidgetItem(self._selection)
        button.setIcon(QtGui.QIcon(widget.ICON))
        button.setText(widget.get_name())
        button.setTextAlignment(Qt.AlignHCenter)
        self._pages.addWidget(widget)

        widget.toggle_tabs.connect(self._on_toggle_tabs)
        self._tab_lookup[widget.get_name()] = (button, widget)
        return widget.size()

    def _on_toggle_tabs(self, name):
        """Toggle ItemIsEnabled flag for all list items but name."""
        for name2 in self._tab_lookup:
            if name2 != name:
                item, _ = self._tab_lookup[name2]
                flags = item.flags()
                # check flag (and)
                if flags & Qt.ItemIsEnabled:
                    # remove flag (nand)
                    item.setFlags(flags & ~Qt.ItemIsEnabled)
                else:
                    # set flag (or)
                    item.setFlags(flags | Qt.ItemIsEnabled)

    def _on_change_page(self, current, previous):
        if not current:
            current = previous
        index = self._selection.row(current)
        self._pages.setCurrentIndex(index)
        widget = self._pages.widget(index)
        widget.page_changed()

    def _check_settings_saved(self,
                              buttons=QMessageBox.Yes | QMessageBox.No
                              | QMessageBox.Cancel):
        if self.isWindowModified():
            result = QMessageBox.question(self, "Settings have been modified",
                                          "Do you want to save the settings?",
                                          buttons)

            if result == QMessageBox.Yes:
                self.save_settings()
        else:
            result = QMessageBox.No
        return result

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(self,
                      text,
                      slot=None,
                      shortcut=None,
                      icon=None,
                      tooltip=None,
                      checkable=None,
                      signal='triggered',
                      checked=False):
        action = QtWidgets.QAction(text, self)
        if icon is not None:
            action.setIcon(QtGui.QIcon(':/%s.png' % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tooltip is not None:
            action.setToolTip(tooltip)
            action.setStatusTip(tooltip)
        if slot is not None:
            getattr(action, signal).connect(slot)
        if checkable is not None:
            action.setCheckable(True)
        action.setChecked(checked)
        return action

    def save_settings(self, save_as=False):
        filename = self._settings_filename
        if filename is None or save_as:
            filename = self._get_save_as_filename()
        if not filename is None:
            self._write_settings(filename)

    def load_settings(self, filename):
        try:
            self._settings.read(filename)
        except Exception as e:
            QMessageBox.critical(self, "Error",
                                 ("Error loading settings file\n"
                                  "Could not load settings file '%s'.\n%s" %
                                  (filename, str(e))))
            self.statusBar().showMessage('Error loading settings files.')
        else:
            self._settings_filename = filename
            title = self.windowTitle().split(' - ')[0]
            self.setWindowTitle('%s - %s[*]' % (title, filename))
            try:
                # reset naming scheme to load config file completely
                nst = self._settings.get_trait("General", "namingscheme")
                namingscheme_file = self._settings("General", "namingscheme")
                if not namingscheme_file in nst.list_data:
                    self._settings.set("General", "namingscheme",
                                       nst.default_value)
                    QMessageBox.warning(
                        self, "Unkown naming scheme",
                        ("%s-%s can not use the naming scheme '%s'."
                         " Resetting to default '%s'" %
                         (version.appname, version.version, namingscheme_file,
                          nst.default_value)))

                for widget in self._tabs:
                    widget.update_input()
            except Exception as e:
                msg = "Could not load settings file (%s)\n.%s" \
                      %(filename, traceback.format_exc())
                QMessageBox.critical(self, "Error", msg)

            else:
                # set settings to not-changed (assume no changed since loaded from file)
                self.settings_changed(False)
                # notify tabs about new settings loaded
                for tab in self._tabs:
                    tab.settings_loaded()
                self.statusBar().showMessage('Settings successfully loaded.')

    def _write_settings(self, filename):
        try:
            f = file(filename, 'w')
            # create a new version (copy) of the current
            # settings which add the needed rendering information
            pframe = self._tab_lookup[SECTION_NAME_PROCESSING][1]
            settings_dummy = pframe.get_export_settings(self._settings)
            settings_dummy.write(f)
            f.close()
        except Exception as e:
            msg = "Could not save settings\n%s" % str(e)
            QMessageBox.critical(self, "Error", msg)
            self.statusBar().showMessage('Settings not successfully saved.')
        else:
            self._settings_filename = filename
            self.setWindowTitle('%s - %s[*]' % (self.appname, filename))
            self.settings_changed(False)
            self.statusBar().showMessage('Settings successfully saved.')

    def on_about(self):
        dialog = CecogAboutDialog(self)
        dialog.show()

    def about_qt(self):
        QMessageBox.aboutQt(self, "about Qt")

    def open_preferences(self):
        pref = PreferencesDialog(self)
        pref.exec_()

    def updateStyleSheet(self, stylesheet):
        self.setStyleSheet("")
        self.setStyleSheet(stylesheet)

        self._pages.assistant.setStyleSheet("")
        self._pages.assistant.setStyleSheet(stylesheet)

        if self._browser is not None:
            self._browser.setStyleSheet("")
            self._browser.setStyleSheet(stylesheet)

    def _on_browser_open(self):
        if self._imagecontainer is None:
            QMessageBox.warning(
                self, 'Data structure not loaded',
                'The input directory structure file was not loaded.\n'
                'Click "Scan input directory" in section "General" to proceed.'
            )
        elif self._browser is None:
            try:
                browser = Browser(self._settings, self._imagecontainer, None)
                browser.show()
                browser.raise_()
                browser.setFocus()
                app = AppPreferences()
                browser.setStyleSheet(loadStyle(app.stylesheet))
                self._browser = browser
            except Exception as e:
                traceback.print_exc()
                QMessageBox.critical(self, "Error", str(e))
        else:
            self._browser.show()
            self._browser.raise_()

    def _on_load_input(self):
        txt = "Error scanning image structure"
        path_in = self._settings.get(SECTION_NAME_GENERAL, 'pathin')
        if path_in == '':
            QMessageBox.critical(self, "Error",
                                 "%s\nImage path must be defined." % txt)
        elif not os.path.isdir(path_in) and \
             not os.path.isdir(os.path.join(self.environ.package_dir, path_in)):
            QMessageBox.critical(
                self, "Error",
                "%s\nImage path '%s' not found." % (txt, path_in))
        else:
            try:
                infos = list(ImageContainer.iter_check_plates(self._settings))
            except Exception as e:
                QMessageBox.critical(self, "Error", "%s\n%s" % (txt, str(e)))
            else:
                found_any = numpy.any([not info[3] is None for info in infos])
                cancel = False
                if found_any:
                    found_plates = [
                        info[0] for info in infos if not info[3] is None
                    ]
                    missing_plates = [
                        info[0] for info in infos if info[3] is None
                    ]
                    has_missing = len(missing_plates) > 0
                    txt = '%s plates were already scanned.\nDo you want ' \
                          'to rescan the file structure(s)? ' \
                          'This can take several minutes.' % \
                          ('Some' if has_missing else 'All')
                    title = 'Rescan input structure?'

                    box = QMessageBox(QMessageBox.Question, title, title,
                                      QMessageBox.Cancel, self, Qt.Sheet)
                    box.setWindowModality(Qt.WindowModal)
                    box.setInformativeText(txt)
                    box.setDetailedText(
                        'Plates with scanned structure: \n%s\n'
                        '\nPlates without scanned structure: '
                        '\n%s' %
                        ('\n'.join(found_plates), '\n'.join(missing_plates)))
                    if not has_missing:
                        btn1 = QtWidgets.QPushButton('No', box)
                        box.addButton(btn1, QMessageBox.NoRole)
                        box.setDefaultButton(btn1)
                    elif len(found_plates) > 0:
                        btn1 = QtWidgets.QPushButton('Rescan missing', box)
                        box.addButton(btn1, QMessageBox.YesRole)
                        box.setDefaultButton(btn1)
                    else:
                        btn1 = None

                    btn2 = QtWidgets.QPushButton('Rescan all', box)
                    box.addButton(btn2, QMessageBox.YesRole)

                    if box.exec_() == QMessageBox.Cancel:
                        cancel = True
                    else:
                        btn = box.clickedButton()
                        if btn == btn1:
                            if has_missing:
                                scan_plates = dict([(info[0], info[0]
                                                     in missing_plates)
                                                    for info in infos])
                            else:
                                scan_plates = dict(
                                    (info[0], False) for info in infos)
                        else:
                            scan_plates = dict(
                                (info[0], True) for info in infos)
                else:
                    has_multiple = self._settings.get(SECTION_NAME_GENERAL,
                                                      "has_multiple_plates")
                    ret = QMessageBox.question(
                        self, "No structure data found",
                        ("Scanning the input directory can be time "
                         "consuming.\n\nDo you want to proceed?"),
                        QMessageBox.Yes | QMessageBox.No)
                    if ret == QMessageBox.No:
                        cancel = True
                    scan_plates = dict((info[0], True) for info in infos)

                if not cancel:
                    self._load_image_container(infos, scan_plates)

    def _load_image_container(self,
                              plate_infos=None,
                              scan_plates=None,
                              show_dialog=True):
        self._clear_browser()

        if plate_infos is None:
            plate_infos = list(ImageContainer.iter_check_plates(
                self._settings))

        imagecontainer = ImageContainer()
        self._imagecontainer = imagecontainer

        if scan_plates is None:
            scan_plates = dict((info[0], False) for info in plate_infos)

        def load(emitter, icontainer, settings, splates):
            iter_ = icontainer.iter_import_from_settings(settings,
                                                         scan_plates=splates)
            for idx, info in enumerate(iter_):
                emitter.setValue.emit(idx)

            emitter.setLabelText.emit("checking dimensions...")
            emitter.setRange.emit(0, 0)
            QtCore.QCoreApplication.processEvents()

            if len(icontainer.plates) > 0:
                icontainer.set_plate(icontainer.plates[0])
                icontainer.check_dimensions()

        label = ('Please wait until the input structure is scanned\n'
                 'or the structure data loaded...')
        self._dlg = ProgressDialog(label, None, 0, len(scan_plates), self)
        emitter = ProgressObject()
        emitter.setRange.connect(self._dlg.setRange)
        emitter.setValue.connect(self._dlg.setValue)
        emitter.setLabelText.connect(self._dlg.setLabelText)

        try:
            func = lambda: load(emitter, imagecontainer, self._settings,
                                scan_plates)
            self._dlg.exec_(func, (emitter, ))
        except ImportError as e:
            # structure file from versions older than 1.3 contain pdk which is
            # removed
            if 'pdk' in str(e):
                QMessageBox.critical(
                    self, "Error", ("Your structure file format is outdated.\n"
                                    "You have to rescan the plate(s)"))
            else:
                QMessageBox.critical(self, "Error", traceback.format_exc())
            return
        except Exception as e:
            QMessageBox.critical(self, "Error", str(e))

        try:  # I hate lookup tables!
            self._tab_lookup['Cluster'][1].set_imagecontainer(imagecontainer)
        except KeyError:
            pass

        if len(imagecontainer.plates) > 0:
            channels = imagecontainer.channels

            # do not report value changes to the main window
            self._settings.set_notify_change(False)

            self.set_image_crop_size()

            problems = []
            for prefix in ['primary', 'secondary', 'tertiary']:
                trait = self._settings.get_trait(SECTION_NAME_OBJECTDETECTION,
                                                 '%s_channelid' % prefix)
                if trait.set_list_data(channels) is None:
                    problems.append(prefix)
                self._tabs[1].get_widget('%s_channelid' % prefix).update()

            # report problems about a mismatch between channel IDs found in the data
            # and specified by the user
            if len(problems) > 0:
                # a mismatch between settings and data will cause changed settings
                self.settings_changed(True)

            trait = self._settings.get_trait(SECTION_NAME_EVENT_SELECTION,
                                             'duration_unit')

            # allow time-base tracking durations only if time-stamp
            # information is present
            meta_data = imagecontainer.get_meta_data()
            if meta_data.has_timestamp_info:
                result = trait.set_list_data(TimeConverter.units)
            else:
                result = trait.set_list_data([TimeConverter.FRAMES])
            if result is None:
                QMessageBox.critical(
                    self, "Could not set tracking duration units",
                    ("The tracking duration units selected to match the "
                     "load data. Please check your settings."))
                # a mismatch between settings and data will cause changed settings
                self.settings_changed(True)

            # activate change notification again
            self._settings.set_notify_change(True)

            self.set_modules_active(state=True)
            if show_dialog:
                QMessageBox.information(
                    self, "Information", "%d plate(s) successfully loaded." %
                    len(imagecontainer.plates))
        else:
            QMessageBox.critical(
                self, "Error",
                ("No images found\n"
                 "Verifiy your nameing scheme and rescan the data."))

    def set_image_crop_size(self):
        x0, y0, x1, y1 = self._settings.get('General', 'crop_image_x0'), \
                         self._settings.get('General', 'crop_image_y0'), \
                         self._settings.get('General', 'crop_image_x1'), \
                         self._settings.get('General', 'crop_image_y1')

        x0_, y0_, x1_, y1_ = 0, \
                             0, \
                             self._imagecontainer.get_meta_data().dim_x, \
                             self._imagecontainer.get_meta_data().dim_y

        tr_x0 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_x0')
        tr_y0 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_y0')
        tr_x1 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_x1')
        tr_y1 = self._settings.get_trait(SECTION_NAME_GENERAL, 'crop_image_y1')

        # Check if the crop values are valid
        if x0 > 0 and y0 > 0 and x1 <= x1_ and y1 <= y1_ and \
                x0 != x1 and y0 != y1:
            # Set to default values
            tr_x0.set_value(tr_x0.get_widget(), x0)
            tr_y0.set_value(tr_y0.get_widget(), y0)
            tr_x1.set_value(tr_x1.get_widget(), x1)
            tr_y0.set_value(tr_y1.get_widget(), y1)
        else:
            tr_x0.set_value(tr_x0.get_widget(), x0_)
            tr_y0.set_value(tr_y0.get_widget(), y0_)
            tr_x1.set_value(tr_x1.get_widget(), x1_)
            tr_y0.set_value(tr_y1.get_widget(), y1_)

        # Set GUI widget valid ranges
        tr_x0.set_min_value(x0_)
        tr_x0.set_max_value(x1_)
        tr_y0.set_min_value(y0_)
        tr_y0.set_max_value(y1_)
        tr_x1.set_min_value(x0_)
        tr_x1.set_max_value(x1_)
        tr_y1.set_min_value(y0_)
        tr_y1.set_max_value(y1_)

    def set_modules_active(self, state=True):
        for name, (button, widget) in self._tab_lookup.iteritems():
            widget.set_active(state)

    @QtCore.pyqtSlot()
    def _on_file_open(self):

        dir_ = os.path.dirname(self._settings_filename)
        if self._check_settings_saved() != QMessageBox.Cancel:
            if self._settings_filename is not None:
                settings_filename = self.environ.demo_settings
                if os.path.isfile(settings_filename):
                    home = settings_filename
            filename = QtWidgets.QFileDialog.getOpenFileName( \
               self, 'Open config file', dir_, ';;'.join(self.NAME_FILTERS))[0]
            if not bool(filename):
                return

            try:
                self.load_settings(filename)
                if self._settings.was_old_file_format():
                    QMessageBox.information(
                        self, 'Information',
                        'Config file was updated to version %s' % self.version)
            except Exception as e:
                msg = "File could not be loaded\n%s" % str(e)
                QMessageBox.critical(self, "Error", msg)
            finally:
                self._clear_browser()
                self.set_modules_active(state=False)

    def _on_file_save(self):
        self.save_settings(False)

    def _on_file_save_as(self):
        self.save_settings(True)

    def _clear_browser(self):
        if not self._browser is None:
            self._browser.close()
            self._browser = None

    def _on_show_log_window(self):
        self._pages.showLogWindow()

    def _get_save_as_filename(self):
        dir = ""
        if self._settings_filename is not None:
            settings_filename = self.environ.demo_settings
            if os.path.isfile(settings_filename):
                dir = settings_filename
        filename = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save config file as', dir, ';;'.join(self.NAME_FILTERS))[0]
        return filename or None

    def show_assistant(self):
        self._pages.assistant.show()
        self._pages.assistant.openKeyword('index')
Пример #25
0
    def _on_process_start(self, name, start_again=False):
        if not self._is_running or start_again:
            is_valid = True
            self._is_abort = False
            self._has_error = False

            if self._process_items is None:
                cls = self._control_buttons[name]['cls']
                if type(cls) == types.ListType:
                    self._process_items = cls
                    self._current_process_item = 0
                    cls = cls[self._current_process_item]

                    # remove HmmThread if process is not first in list and
                    # not valid error correction was activated
                    if (HmmThread in self._process_items and
                        self._process_items.index(HmmThread) > 0 and
                        not (self._settings.get('Processing', 'primary_errorcorrection') or
                             (self._settings.get('Processing', 'secondary_errorcorrection') and
                              self._settings.get('Processing', 'secondary_processchannel')))):
                        self._process_items.remove(HmmThread)

                else:
                    self._process_items = None
                    self._current_process_item = 0
            else:
                cls = self._process_items[self._current_process_item]


            if self.SECTION_NAME == 'Classification':
                result_frame = self._get_result_frame(self._tab_name)
                result_frame.load_classifier(check=False)
                learner = result_frame._learner

                if name == self.PROCESS_PICKING:
                    if not result_frame.is_pick_samples():
                        is_valid = False
                        result_frame.msg_pick_samples(self)
                    elif result_frame.is_train_classifier():
                        if not question(self, 'Samples already picked',
                                    'Do you want to pick samples again and '
                                    'overwrite previous '
                                    'results?'):
                            is_valid = False

                elif name == self.PROCESS_TRAINING:
                    if not result_frame.is_train_classifier():
                        is_valid = False
                        result_frame.msg_train_classifier(self)
                    elif result_frame.is_apply_classifier():
                        if not question(self, 'Classifier already trained',
                                    'Do you want to train the classifier '
                                    'again?'):
                            is_valid = False

                elif name == self.PROCESS_TESTING and not result_frame.is_apply_classifier():
                    is_valid = False
                    result_frame.msg_apply_classifier(self)

            elif cls is HmmThread:

                success, cmd = HmmThread.test_executable(self._settings.get('ErrorCorrection', 'filename_to_R'))
                if not success:
                    critical(self, 'Error running R',
                             "The R command line program '%s' could not be executed.\n\n"\
                             "Make sure that the R-project is installed.\n\n"\
                             "See README.txt for details." % cmd)
                    is_valid = False

            elif cls is MultiAnalyzerThread:
                ncpu = cpu_count()
                (ncpu, ok) = QInputDialog.getInt(None, "On your machine are %d processers available." % ncpu, \
                                             "Select the number of processors", \
                                              ncpu, 1, ncpu*2)
                if not ok:
                    self._process_items = None
                    is_valid = False

            if is_valid:
                self._current_process = name

                if not start_again:
                    self.parent().main_window.log_window.clear()

                    self._is_running = True
                    self._stage_infos = {}

                    self._toggle_tabs(False)
                    # disable all section button of the main widget
                    self.toggle_tabs.emit(self.get_name())

                    self._set_control_button_text(idx=1)
                    self._toggle_control_buttons()

                imagecontainer = self.parent().main_window._imagecontainer

                if cls is PickerThread:
                    self._current_settings = self._get_modified_settings(name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings, imagecontainer)
                    self._set_display_renderer_info()
                    self._clear_image()

                elif cls is AnalyzerThread:
                    self._current_settings = self._get_modified_settings(name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings, imagecontainer)
                    self._set_display_renderer_info()
                    self._clear_image()

                elif cls is TrainingThread:
                    self._current_settings = self._settings.copy()

                    self._analyzer = cls(self, self._current_settings, result_frame._learner)
                    self._analyzer.setTerminationEnabled(True)

                    self._analyzer.conf_result.connect(result_frame.on_conf_result,
                                                       Qt.QueuedConnection)
                    result_frame.reset()

                elif cls is MultiAnalyzerThread:
                    self._current_settings = self._get_modified_settings(name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings, imagecontainer, ncpu)

                    self._set_display_renderer_info()

                elif cls is HmmThread:
                    self._current_settings = self._get_modified_settings(name, imagecontainer.has_timelapse)

                      # FIXME: classifier handling needs revision!!!
                    learner_dict = {}
                    for kind in ['primary', 'secondary']:
                        _resolve = lambda x,y: self._settings.get(x, '%s_%s' % (kind, y))
                        env_path = CecogEnvironment.convert_package_path(_resolve('Classification', 'classification_envpath'))
                        if (os.path.exists(env_path)
                              and (kind == 'primary' or self._settings.get('Processing', 'secondary_processchannel'))
                             ):

                            learner = CommonClassPredictor( \
                                env_path,
                                _resolve('ObjectDetection', 'channelid'),
                                _resolve('Classification', 'classification_regionname'))
                            learner.importFromArff()
                            learner_dict[kind] = learner

                    ### Whee, I like it... "self.parent().main_window._imagecontainer" crazy, crazy, michael... :-)
                    self._analyzer = cls(self, self._current_settings,
                                         learner_dict,
                                         self.parent().main_window._imagecontainer)
                    self._analyzer.setTerminationEnabled(True)
                    lw = self.parent().main_window.log_window
                    lw.show()


                elif cls is PostProcessingThread:
                    learner_dict = {}
                    for kind in ['primary', 'secondary']:
                        _resolve = lambda x,y: self._settings.get(x, '%s_%s' % (kind, y))
                        env_path = CecogEnvironment.convert_package_path(_resolve('Classification', 'classification_envpath'))
                        if (_resolve('Processing', 'classification') and
                            (kind == 'primary' or self._settings.get('Processing', 'secondary_processchannel'))):
                            learner = CommonClassPredictor( \
                                env_path,
                                _resolve('ObjectDetection', 'channelid'),
                                _resolve('Classification', 'classification_regionname'))

                            learner.importFromArff()
                            learner_dict[kind] = learner
                    self._current_settings = self._get_modified_settings(name, imagecontainer.has_timelapse)
                    self._analyzer = cls(self, self._current_settings, learner_dict, imagecontainer)
                    self._analyzer.setTerminationEnabled(True)

                self._analyzer.finished.connect(self._on_process_finished)
                self._analyzer.stage_info.connect(self._on_update_stage_info, Qt.QueuedConnection)
                self._analyzer.analyzer_error.connect(self._on_error, Qt.QueuedConnection)

                self._analyzer.start(QThread.LowestPriority)
                if self._current_process_item == 0:
                    status('Process started...')

        else:
            self._abort_processing()