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)
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
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)
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)
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)
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()
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
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]()
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)
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
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]()
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)
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)
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')
(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
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()
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)
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')
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 __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
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_()
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)
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)
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')
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()