class Browser(QMainWindow): ZOOM_STEP = 1.05 show_objects_toggled = pyqtSignal('bool') show_contours_toggled = pyqtSignal('bool') coordinates_changed = pyqtSignal(Coordinate) def __init__(self, settings, imagecontainer): super(Browser, self).__init__() frame = QFrame(self) self.setCentralWidget(frame) self._settings = settings self._imagecontainer = imagecontainer self._show_objects = False self._object_region = None self.coordinate = Coordinate() self.grabGesture(Qt.SwipeGesture) self.setStyleSheet("QStatusBar { border-top: 1px solid gray; }") layout = QVBoxLayout(frame) layout.setContentsMargins(0, 0, 0, 0) splitter = QSplitter(Qt.Horizontal, frame) #splitter.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, # QSizePolicy.Expanding)) layout.addWidget(splitter) frame = QFrame(self) frame_side = QStackedWidget(splitter) #splitter.setChildrenCollapsible(False) splitter.addWidget(frame) splitter.addWidget(frame_side) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setSizes([-1, 80]) self.coordinate.plate = self._imagecontainer.plates[0] self._imagecontainer.set_plate(self.coordinate.plate) self.coordinate.channel = self._imagecontainer.channels[0] meta_data = self._imagecontainer.get_meta_data() self.max_time = meta_data.times[-1] self.min_time = meta_data.times[0] self.max_frame = meta_data.dim_t-1 layout = QGridLayout(frame) layout.setContentsMargins(0, 0, 0, 0) self.image_viewer = ImageViewer(frame, auto_resize=True) layout.addWidget(self.image_viewer, 0, 0) #self.image_viewer.image_mouse_dblclk.connect(self._on_dbl_clk) self.image_viewer.zoom_info_updated.connect(self.on_zoom_info_updated) self._t_slider = QSlider(Qt.Horizontal, frame) self._t_slider.setMinimum(self.min_time) self._t_slider.setMaximum(self.max_time) # self._t_slider.setMaximum(self.max_frame) self._t_slider.setTickPosition(QSlider.TicksBelow) self._t_slider.valueChanged.connect(self.on_time_changed_by_slider, Qt.DirectConnection) if self._imagecontainer.has_timelapse: self._t_slider.show() else: self._t_slider.hide() layout.addWidget(self._t_slider, 1, 0) self.coordinate.position = meta_data.positions[0] self.coordinate.time = self._t_slider.minimum() # menus act_next_t = self.create_action('Next Time-point', shortcut=QKeySequence('Right'), slot=self.on_act_next_t) act_prev_t = self.create_action('Previous Time-point', shortcut=QKeySequence('Left'), slot=self.on_act_prev_t) act_next_pos = self.create_action('Next Position', shortcut=QKeySequence('Shift+Down'), slot=self.on_act_next_pos) act_prev_pos = self.create_action('Previous Position', shortcut=QKeySequence('Shift+Up'), slot=self.on_act_prev_pos) act_next_plate = self.create_action('Next Plate', shortcut=QKeySequence('Shift+Alt+Down'), slot=self.on_act_next_plate) act_prev_plate = self.create_action('Previous Plate', shortcut=QKeySequence('Shift+Alt+Up'), slot=self.on_act_prev_plate) act_resize = self.create_action('Automatically Resize', shortcut=QKeySequence('SHIFT+CTRL+R'), slot=self.on_act_autoresize, signal='triggered(bool)', checkable=True, checked=True) self._act_resize = act_resize act_zoomfit = self.create_action('Zoom to Fit', shortcut=QKeySequence('CTRL+0'), slot=self.on_act_zoomfit) act_zoom100 = self.create_action('Actual Size', shortcut=QKeySequence('CTRL+1'), slot=self.on_act_zoom100) act_zoomin = self.create_action('Zoom In', shortcut=QKeySequence('CTRL++'), slot=self.on_act_zoomin) act_zoomout = self.create_action('Zoom Out', shortcut=QKeySequence('CTRL+-'), slot=self.on_act_zoomout) act_refresh = self.create_action('Refresh', shortcut=QKeySequence('F5'), slot=self.on_refresh) act_fullscreen = self.create_action('Full Screen', shortcut=QKeySequence('CTRL+F'), slot=self.on_act_fullscreen, signal='triggered(bool)', checkable=True, checked=False) self._act_fullscreen = act_fullscreen act_show_contours = self.create_action('Show Object Contours', shortcut=QKeySequence('ALT+C'), slot=self.on_act_show_contours, signal='triggered(bool)', checkable=True, checked=self.image_viewer.show_contours) self._act_show_contours = act_show_contours act_anti = self.create_action('Antialiasing', shortcut=QKeySequence('CTRL+ALT+A'), slot=self.on_act_antialiasing, signal='triggered(bool)', checkable=True, checked=True) act_smooth = self.create_action('Smooth Transform', shortcut=QKeySequence('CTRL+ALT+S'), slot=self.on_act_smoothtransform, signal='triggered(bool)', checkable=True, checked=True) view_menu = self.menuBar().addMenu('&View') self.add_actions(view_menu, (act_resize, None, act_zoom100, act_zoomfit, act_zoomin, act_zoomout, None, act_prev_t, act_next_t, act_prev_pos, act_next_pos, act_prev_plate, act_next_plate, None, act_refresh, act_fullscreen, None, act_show_contours, None, act_anti, act_smooth, )) self._statusbar = QStatusBar(self) self.setStatusBar(self._statusbar) # tool bar toolbar = self.addToolBar('Toolbar') toolbar.setMovable(False) toolbar.setFloatable(False) region_names = [] for prefix in ['primary', 'secondary', 'tertiary']: region_names.extend(['%s - %s' % (prefix.capitalize(), name) \ for name in REGION_INFO.names[prefix]]) # FIXME: something went wrong with setting up the current region self._object_region = region_names[0].split(' - ') # create a new ModuleManager with a QToolbar and QStackedFrame self._module_manager = ModuleManager(toolbar, frame_side) NavigationModule(self._module_manager, self, self._imagecontainer) DisplayModule(self._module_manager, self, self._imagecontainer, region_names) AnnotationModule(self._module_manager, self, self._settings, self._imagecontainer) # set the Navigation module activated self._module_manager.activate_tab(NavigationModule.NAME) # process and display the first image self._process_image() def create_action(self, text, slot=None, shortcut=None, icon=None, tooltip=None, checkable=None, signal='triggered()', checked=False): action = QAction(text, self) if icon is not None: action.setIcon(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, SIGNAL(signal), slot, Qt.DirectConnection) if checkable is not None: action.setCheckable(True) action.setChecked(checked) return action def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def set_coords(self, coords): self.image_viewer.remove_objects() self.image_viewer.set_objects_by_crackcoords(coords) widget = self._module_manager.get_widget(AnnotationModule.NAME) widget.set_coords() def show_image(self, image_dict): widget = self._module_manager.get_widget(DisplayModule.NAME) widget.set_image_dict(image_dict) self.update_statusbar() def update_statusbar(self): meta_data = self._imagecontainer.get_meta_data() if meta_data.has_timelapse: timestamp = meta_data.get_timestamp_relative(self.coordinate) time_info = ' | Frame: %d' % self.coordinate.time if not numpy.isnan(timestamp): time_info += ' (%.1f min)' % (timestamp / 60) else: time_info = '' msg = 'Plate: %s | Position: %s%s || Zoom: %.1f%%' % \ (self.coordinate.plate, self.coordinate.position, time_info, self.image_viewer.scale_factor*100) self._statusbar.showMessage(msg) def get_coordinate(self): return self.coordinate.copy() def on_coordinate_changed(self, coordinate): """ All coordinate changes are handled via the Navigator. The change event from the Navigator is processed here and further propagated via a new Browser event (the Modules are not supposed to know each other). """ self.coordinate = coordinate.copy() self._t_slider.blockSignals(True) self._imagecontainer.set_plate(coordinate.plate) # the slider is always working with frames. # reason: it is difficult to forbid slider values between allowed values. frame = int(round(self.max_frame * (coordinate.time - self.min_time) / max(float(self.max_time - self.min_time), 1))) self._t_slider.setValue(frame) self._t_slider.blockSignals(False) self._process_image() # propagate the signal further to other modules self.coordinates_changed.emit(coordinate) def set_coordinate(self, coordinate): """ Changes the Navigator to a fixed coordinate """ nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_coordinate(coordinate) def _process_image(self): settings = _ProcessorMixin.get_special_settings(self._settings) settings.set_section('General') settings.set2('constrain_positions', True) settings.set2('positions', self.coordinate.position) settings.set2('redofailedonly', False) settings.set2('framerange', True) settings.set2('framerange_begin', self.coordinate.time) settings.set2('framerange_end', self.coordinate.time) settings.set_section('ObjectDetection') prim_id = PrimaryChannel.NAME #sec_id = SecondaryChannel.NAME #sec_regions = settings.get2('secondary_regions') settings.set_section('Processing') settings.set2('primary_classification', False) settings.set2('secondary_classification', False) settings.set2('tertiary_classification', False) settings.set2('merged_classification', False) settings.set2('primary_featureextraction', False) settings.set2('secondary_featureextraction', False) settings.set2('objectdetection', self._show_objects) settings.set2('tracking', False) settings.set_section('Output') settings.set2('rendering_contours_discwrite', False) settings.set2('rendering_class_discwrite', False) settings.set2('export_object_counts', False) settings.set2('export_object_details', False) settings.set2('export_track_data', False) settings.set2('hdf5_create_file', False) settings.set_section('Classification') settings.set2('collectsamples', False) settings.set('General', 'rendering', {}) settings.set('General', 'rendering_class', {}) settings.set('Output', 'events_export_gallery_images', False) # turn of output: settings.set('Output', 'export_object_counts', False) settings.set('Output', 'export_object_details', False) settings.set('Output', 'export_file_names', False) settings.set('Output', 'events_export_gallery_images', False) settings.set('Output', 'export_track_data', False) settings.set('Output', 'export_tracking_as_dot', False) nchannels = len(self._imagecontainer.channels) # XXX channel mapping unclear # processing channel <--> color channel # i.e problems if 2 processing channels have the # same color if nchannels == 2: settings.set('Processing', 'secondary_processChannel', True) elif nchannels == 3: settings.set('Processing', 'secondary_processChannel', True) settings.set('Processing', 'tertiary_processChannel', True) # need turn of virtual channels settings.set('Processing', 'merged_processChannel', False) settings.set('General', 'rendering', {}) analyzer = AnalyzerCore(self.coordinate.plate, settings, self._imagecontainer) # as long the GIL is not released, if GIL is released # just use self.setCursor try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) analyzer.processPositions(myhack=self) except Exception, e: import traceback traceback.print_exc() raise(e) finally:
class Browser(QMainWindow): ZOOM_STEP = 1.05 show_objects_toggled = pyqtSignal('bool') show_contours_toggled = pyqtSignal('bool') #coordinates_changed = pyqtSignal(Coordinate) update_regions = pyqtSignal(dict) def __init__(self, settings, imagecontainer, parent=None): super(Browser, self).__init__(parent) self.setWindowTitle('Annotation Browser') frame = QFrame(self) self.setCentralWidget(frame) self._settings = settings self._imagecontainer = imagecontainer # These params are used by process_image and contour visualization self._detect_objects = False self._show_objects_by = 'color' self._object_region = None self._contour_color = '#000000' self._show_objects = True self.coordinate = Coordinate() self.grabGesture(Qt.SwipeGesture) self.setStyleSheet("QStatusBar { border-top: 1px solid gray; }") layout = QVBoxLayout(frame) layout.setContentsMargins(0, 0, 0, 0) splitter = QSplitter(Qt.Horizontal, frame) layout.addWidget(splitter) frame = QFrame(self) frame_side = QStackedWidget(splitter) splitter.addWidget(frame) splitter.addWidget(frame_side) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setSizes([-1, 80]) self.coordinate.plate = self._imagecontainer.plates[0] self._imagecontainer.set_plate(self.coordinate.plate) self.coordinate.channel = self._imagecontainer.channels[0] meta_data = self._imagecontainer.get_meta_data() self.max_time = meta_data.times[-1] self.min_time = meta_data.times[0] self.max_frame = meta_data.dim_t-1 layout = QGridLayout(frame) layout.setContentsMargins(0, 0, 0, 0) self.image_viewers = { 'image' : ImageViewer(frame, auto_resize=True), 'gallery' : GalleryViewer(frame) } self.image_viewer = self.image_viewers['image'] layout.addWidget(self.image_viewer , 0, 0) self.image_viewer.zoom_info_updated.connect(self.on_zoom_info_updated) self._t_slider = TSlider(Qt.Horizontal, frame) self._t_slider.setMinimum(self.min_time) self._t_slider.setMaximum(self.max_time) self._t_slider.setTickPosition(QSlider.NoTicks) self._t_slider.newValue.connect(self.on_time_changed_by_slider, Qt.DirectConnection) self._t_slider.valueChanged.connect(self.timeToolTip) self._imagecontainer.check_dimensions() if self._imagecontainer.has_timelapse: self._t_slider.show() else: self._t_slider.hide() layout.addWidget(self._t_slider, 1, 0) self.coordinate.position = meta_data.positions[0] self.coordinate.time = self._t_slider.minimum() # menus act_close = self.create_action('Close', shortcut=QKeySequence('CTRL+C'), slot=self.close) act_next_t = self.create_action('Next Time-point', shortcut=QKeySequence('Right'), slot=self.on_act_next_t) act_prev_t = self.create_action('Previous Time-point', shortcut=QKeySequence('Left'), slot=self.on_act_prev_t) act_next_pos = self.create_action('Next Position', shortcut=QKeySequence('Shift+Down'), slot=self.on_act_next_pos) act_prev_pos = self.create_action('Previous Position', shortcut=QKeySequence('Shift+Up'), slot=self.on_act_prev_pos) act_next_plate = self.create_action( 'Next Plate', shortcut=QKeySequence('Shift+Alt+Down'), slot=self.on_act_next_plate) act_prev_plate = self.create_action( 'Previous Plate', shortcut=QKeySequence('Shift+Alt+Up'), slot=self.on_act_prev_plate) act_resize = self.create_action('Automatically Resize', shortcut=QKeySequence('SHIFT+CTRL+R'), slot=self.on_act_autoresize, signal='triggered(bool)', checkable=True, checked=True) self._act_resize = act_resize act_zoomfit = self.create_action('Zoom to Fit', shortcut=QKeySequence('CTRL+0'), slot=self.on_act_zoomfit) act_zoom100 = self.create_action('Actual Size', shortcut=QKeySequence('CTRL+1'), slot=self.on_act_zoom100) act_zoomin = self.create_action('Zoom In', shortcut=QKeySequence('CTRL++'), slot=self.on_act_zoomin) act_zoomout = self.create_action('Zoom Out', shortcut=QKeySequence('CTRL+-'), slot=self.on_act_zoomout) act_refresh = self.create_action('Refresh', shortcut=QKeySequence('F5'), slot=self.on_refresh) act_fullscreen = self.create_action( 'Full Screen', shortcut=QKeySequence('CTRL+F'), slot=self.on_act_fullscreen, signal='triggered(bool)', checkable=True, checked=False ) self._act_fullscreen = act_fullscreen act_show_contours = self.create_action( 'Show Object Contours', shortcut=QKeySequence('ALT+C'), slot=self.on_act_show_contours, signal='triggered(bool)', checkable=True, checked=self.image_viewer.show_contours ) self._act_show_contours = act_show_contours act_anti = self.create_action('Antialiasing', shortcut=QKeySequence('CTRL+ALT+A'), slot=self.on_act_antialiasing, signal='triggered(bool)', checkable=True, checked=True) act_smooth = self.create_action('Smooth Transform', shortcut=QKeySequence('CTRL+ALT+S'), slot=self.on_act_smoothtransform, signal='triggered(bool)', checkable=True, checked=True) view_menu = self.menuBar().addMenu('&View') self.add_actions(view_menu, (act_resize, None, act_zoom100, act_zoomfit, act_zoomin, act_zoomout, None, act_prev_t, act_next_t, act_prev_pos, act_next_pos, act_prev_plate, act_next_plate, None, act_refresh, act_fullscreen, None, act_show_contours, None, act_anti, act_smooth, None, act_close)) self._statusbar = QStatusBar(self) self.setStatusBar(self._statusbar) toolbar = self.addToolBar('Toolbar') toolbar.setObjectName('Toolbar') toolbar.setMovable(False) toolbar.setFloatable(False) # fallback if no Segmentation plugins have been specified rdict = self._region_names() if len(rdict) > 0: self._object_region = rdict.keys()[0].split(' - ') else: self._object_region = ('Primary', 'primary') # create a new ModuleManager with a QToolbar and QStackedFrame self._module_manager = ModuleManager(toolbar, frame_side) NavigationModule(self._module_manager, self, self._imagecontainer) defautl_display_module = DisplayModule( self._module_manager, self, self._imagecontainer, rdict) self.set_display_module(defautl_display_module) AnnotationModule(self._module_manager, self, self._settings, self._imagecontainer) try: CellH5EventModule(self._module_manager, self, self._settings, self._imagecontainer) except Exception as e: warning(self, str(e)) # set the Navigation module activated self._module_manager.activate_tab(NavigationModule.NAME) self.layout = layout # process and display the first image self._restore_geometry() self._process_image() def closeEvent(self, event): self._save_geometry() def _save_geometry(self): settings = QSettings(version.organisation, version.appname) settings.beginGroup('AnnotationBrowser') settings.setValue('state', self.saveState()) settings.setValue('geometry', self.saveGeometry()) settings.endGroup() def _restore_geometry(self): settings = QSettings(version.organisation, version.appname) settings.beginGroup('AnnotationBrowser') if settings.contains('geometry'): self.restoreGeometry(settings.value('geometry')) if settings.contains('state'): self.restoreState(settings.value('state')) settings.endGroup() def _region_names(self): rdict = OrderedDict() reginfo = MetaPluginManager().region_info for channel, regions in reginfo.names.iteritems(): for region in regions: rdict['%s - %s' % (channel.capitalize(), region)] = \ (channel.capitalize(), region) return rdict def set_image_viewer(self, viewer_type): self.image_viewer.hide() self.layout.removeWidget(self.image_viewer) self.image_viewer = self.image_viewers[viewer_type] self.layout.addWidget(self.image_viewer, 0, 0) self.image_viewer.show() def create_action(self, text, slot=None, shortcut=None, icon=None, tooltip=None, checkable=None, signal='triggered()', checked=False): action = QAction(text, self) if icon is not None: action.setIcon(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: if signal == "triggered()": action.triggered.connect(slot, Qt.DirectConnection) else: action.triggered[bool].connect(slot, Qt.DirectConnection) if checkable is not None: action.setCheckable(True) action.setChecked(checked) return action def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def set_coords(self, coords): self.image_viewer.set_objects_by_crackcoords(coords) widget = self._module_manager.get_widget(AnnotationModule.NAME) widget.set_coords() def set_classified_crack_contours(self, coords): self.image_viewer.set_objects_by_crackcoords_with_colors(coords) widget = self._module_manager.get_widget(AnnotationModule.NAME) widget.set_coords() def show_image(self, image_dict): widget = self.get_display_module() widget.set_image_dict(image_dict) self.update_statusbar() def set_display_module(self, display_module ): self.display_module = display_module def get_display_module(self): return self.display_module def update_statusbar(self): meta_data = self._imagecontainer.get_meta_data() if meta_data.has_timelapse: timestamp = meta_data.get_timestamp_relative(self.coordinate) time_info = ' | Frame: %d' % self.coordinate.time if not numpy.isnan(timestamp): time_info += ' (%.1f min)' % (timestamp / 60) else: time_info = '' msg = 'Plate: %s | Position: %s%s || Zoom: %.1f%%' % \ (self.coordinate.plate, self.coordinate.position, time_info, self.image_viewer.scalefactor*100) self._statusbar.showMessage(msg) def get_coordinate(self): return self.coordinate.copy() def on_coordinate_changed(self, coordinate): """ All coordinate changes are handled via the Navigator. The change event from the Navigator is processed here and further propagated via a new Browser event (the Modules are not supposed to know each other). """ self.coordinate = coordinate.copy() self._t_slider.blockSignals(True) self._imagecontainer.set_plate(coordinate.plate) self._t_slider.setValue(coordinate.time) self._t_slider.blockSignals(False) self._process_image() # propagate the signal further to other modules #self.coordinates_changed.emit(coordinate) def set_coordinate(self, coordinate): """ Changes the Navigator to a fixed coordinate """ nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_coordinate(coordinate) def _process_image(self, ): self.image_viewer.remove_objects() settings = BaseProcessorFrame.get_special_settings(self._settings) settings.set_section('General') settings.set2('constrain_positions', True) settings.set2('positions', self.coordinate.position) settings.set2('redofailedonly', False) settings.set2('framerange', True) settings.set2('framerange_begin', self.coordinate.time) settings.set2('framerange_end', self.coordinate.time) settings.set_section('Processing') _classify_objects = self._show_objects_by == 'classification' settings.set2('primary_classification', _classify_objects ) settings.set2('secondary_classification', _classify_objects) settings.set2('tertiary_classification', _classify_objects) settings.set2('merged_classification', _classify_objects) settings.set2('primary_featureextraction', _classify_objects) settings.set2('secondary_featureextraction', _classify_objects) settings.set2('objectdetection', self._detect_objects) settings.set2('tracking', False) settings.set_section('Output') settings.set2('rendering_contours_discwrite', False) settings.set2('rendering_class_discwrite', False) settings.set2('export_object_counts', False) settings.set2('export_object_details', False) settings.set2('export_track_data', False) settings.set2('hdf5_create_file', False) settings.set_section('Classification') settings.set2('collectsamples', False) settings.set('General', 'rendering', {}) settings.set('General', 'rendering_class', {}) settings.set('Output', 'events_export_gallery_images', False) # turn of output: settings.set('Output', 'export_object_counts', False) settings.set('Output', 'export_object_details', False) settings.set('Output', 'export_file_names', False) settings.set('Output', 'events_export_gallery_images', False) settings.set('Output', 'export_track_data', False) settings.set('Output', 'export_tracking_as_dot', False) nchannels = len(self._imagecontainer.channels) # XXX channel mapping unclear # processing channel <--> color channel # i.e problems if 2 processing channels have the same color if nchannels == 2: settings.set('General', 'process_secondary', True) elif nchannels >= 3: settings.set('General', 'process_secondary', True) settings.set('General', 'process_tertiary', True) settings.set('General', 'rendering', {}) analyzer = AnalyzerBrowser(self.coordinate.plate, settings, self._imagecontainer) res = None try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) res = analyzer.processPositions() self.render_browser(res) except Exception, e: import traceback from cecog.gui.util import exception traceback.print_exc() exception(self, str(e)) raise finally:
class Browser(QMainWindow): ZOOM_STEP = 1.05 show_objects_toggled = pyqtSignal('bool') show_contours_toggled = pyqtSignal('bool') update_regions = pyqtSignal(dict) def __init__(self, settings, imagecontainer, parent=None): super(Browser, self).__init__(parent) self.setWindowTitle('Annotation Browser') frame = QFrame(self) self.setCentralWidget(frame) self._settings = settings self._imagecontainer = imagecontainer # These params are used by process_image and contour visualization self._detect_objects = False self._show_objects_by = 'color' self._object_region = None self._contour_color = '#000000' self._show_objects = True self.coordinate = Coordinate() self.grabGesture(Qt.SwipeGesture) self.setStyleSheet("QStatusBar { border-top: 1px solid gray; }") layout = QVBoxLayout(frame) layout.setContentsMargins(0, 0, 0, 0) splitter = QSplitter(Qt.Horizontal, frame) layout.addWidget(splitter) frame = QFrame(self) frame_side = QStackedWidget(splitter) splitter.addWidget(frame) splitter.addWidget(frame_side) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setSizes([-1, 80]) self.coordinate.plate = self._imagecontainer.plates[0] self._imagecontainer.set_plate(self.coordinate.plate) self.coordinate.channel = self._imagecontainer.channels[0] meta_data = self._imagecontainer.get_meta_data() self.max_time = meta_data.times[-1] self.min_time = meta_data.times[0] self.max_frame = meta_data.dim_t - 1 layout = QGridLayout(frame) layout.setContentsMargins(0, 0, 0, 0) self.image_viewers = { 'image': ImageViewer(frame, auto_resize=True), 'gallery': GalleryViewer(frame) } self.image_viewer = self.image_viewers['image'] layout.addWidget(self.image_viewer, 0, 0) self.image_viewer.zoom_info_updated.connect(self.on_zoom_info_updated) self._t_slider = TSlider(Qt.Horizontal, frame) self._t_slider.setMinimum(self.min_time) self._t_slider.setMaximum(self.max_time) self._t_slider.setTickPosition(QSlider.NoTicks) self._t_slider.newValue.connect(self.on_time_changed_by_slider, Qt.DirectConnection) self._t_slider.valueChanged.connect(self.timeToolTip) self._imagecontainer.check_dimensions() if self._imagecontainer.has_timelapse: self._t_slider.show() else: self._t_slider.hide() layout.addWidget(self._t_slider, 1, 0) self.coordinate.position = meta_data.positions[0] self.coordinate.time = self._t_slider.minimum() # menus act_close = self.create_action('Close', shortcut=QKeySequence('CTRL+C'), slot=self.close) act_next_t = self.create_action('Next Time-point', shortcut=QKeySequence('Right'), slot=self.on_act_next_t) act_prev_t = self.create_action('Previous Time-point', shortcut=QKeySequence('Left'), slot=self.on_act_prev_t) act_next_pos = self.create_action('Next Position', shortcut=QKeySequence('Shift+Down'), slot=self.on_act_next_pos) act_prev_pos = self.create_action('Previous Position', shortcut=QKeySequence('Shift+Up'), slot=self.on_act_prev_pos) act_next_plate = self.create_action( 'Next Plate', shortcut=QKeySequence('Shift+Alt+Down'), slot=self.on_act_next_plate) act_prev_plate = self.create_action( 'Previous Plate', shortcut=QKeySequence('Shift+Alt+Up'), slot=self.on_act_prev_plate) act_resize = self.create_action('Automatically Resize', shortcut=QKeySequence('SHIFT+CTRL+R'), slot=self.on_act_autoresize, signal='triggered(bool)', checkable=True, checked=True) self._act_resize = act_resize act_zoomfit = self.create_action('Zoom to Fit', shortcut=QKeySequence('CTRL+0'), slot=self.on_act_zoomfit) act_zoom100 = self.create_action('Actual Size', shortcut=QKeySequence('CTRL+1'), slot=self.on_act_zoom100) act_zoomin = self.create_action('Zoom In', shortcut=QKeySequence('CTRL++'), slot=self.on_act_zoomin) act_zoomout = self.create_action('Zoom Out', shortcut=QKeySequence('CTRL+-'), slot=self.on_act_zoomout) act_refresh = self.create_action('Refresh', shortcut=QKeySequence('F5'), slot=self.on_refresh) act_fullscreen = self.create_action('Full Screen', shortcut=QKeySequence('CTRL+F'), slot=self.on_act_fullscreen, signal='triggered(bool)', checkable=True, checked=False) self._act_fullscreen = act_fullscreen act_show_contours = self.create_action( 'Show Object Contours', shortcut=QKeySequence('ALT+C'), slot=self.on_act_show_contours, signal='triggered(bool)', checkable=True, checked=self.image_viewer.show_contours) self._act_show_contours = act_show_contours act_anti = self.create_action('Antialiasing', shortcut=QKeySequence('CTRL+ALT+A'), slot=self.on_act_antialiasing, signal='triggered(bool)', checkable=True, checked=True) act_smooth = self.create_action('Smooth Transform', shortcut=QKeySequence('CTRL+ALT+S'), slot=self.on_act_smoothtransform, signal='triggered(bool)', checkable=True, checked=True) view_menu = self.menuBar().addMenu('&View') self.add_actions( view_menu, (act_resize, None, act_zoom100, act_zoomfit, act_zoomin, act_zoomout, None, act_prev_t, act_next_t, act_prev_pos, act_next_pos, act_prev_plate, act_next_plate, None, act_refresh, act_fullscreen, None, act_show_contours, None, act_anti, act_smooth, None, act_close)) self._statusbar = QStatusBar(self) self.setStatusBar(self._statusbar) toolbar = self.addToolBar('Toolbar') toolbar.setObjectName('Toolbar') toolbar.setMovable(False) toolbar.setFloatable(False) # fallback if no Segmentation plugins have been specified rdict = self._region_names() if len(rdict) > 0: self._object_region = rdict.keys()[0].split(' - ') else: self._object_region = ('Primary', 'primary') # create a new ModuleManager with a QToolbar and QStackedFrame self._module_manager = ModuleManager(toolbar, frame_side) NavigationModule(self._module_manager, self, self._imagecontainer) defautl_display_module = DisplayModule(self._module_manager, self, self._imagecontainer, rdict) self.set_display_module(defautl_display_module) AnnotationModule(self._module_manager, self, self._settings, self._imagecontainer) try: CellH5EventModule(self._module_manager, self, self._settings, self._imagecontainer) except Exception as e: QMessageBox.warning(self, "Warning", str(e)) # set the Navigation module activated self._module_manager.activate_tab(NavigationModule.NAME) self.layout = layout # process and display the first image self._restore_geometry() self._process_image() def closeEvent(self, event): self._save_geometry() def _save_geometry(self): settings = QSettings(version.organisation, version.appname) settings.beginGroup('AnnotationBrowser') settings.setValue('state', self.saveState()) settings.setValue('geometry', self.saveGeometry()) settings.endGroup() def _restore_geometry(self): settings = QSettings(version.organisation, version.appname) settings.beginGroup('AnnotationBrowser') if settings.contains('geometry'): self.restoreGeometry(settings.value('geometry')) if settings.contains('state'): self.restoreState(settings.value('state')) settings.endGroup() def _region_names(self): rdict = OrderedDict() reginfo = MetaPluginManager().region_info for channel, regions in reginfo.names.iteritems(): for region in regions: rdict['%s - %s' % (channel.capitalize(), region)] = \ (channel.capitalize(), region) return rdict def set_image_viewer(self, viewer_type): self.image_viewer.hide() self.layout.removeWidget(self.image_viewer) self.image_viewer = self.image_viewers[viewer_type] self.layout.addWidget(self.image_viewer, 0, 0) self.image_viewer.show() def create_action(self, text, slot=None, shortcut=None, icon=None, tooltip=None, checkable=None, signal='triggered()', checked=False): action = QAction(text, self) if icon is not None: action.setIcon(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: if signal == "triggered()": action.triggered.connect(slot, Qt.DirectConnection) else: action.triggered[bool].connect(slot, Qt.DirectConnection) if checkable is not None: action.setCheckable(True) action.setChecked(checked) return action def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def set_coords(self, coords): self.image_viewer.set_objects_by_crackcoords(coords) widget = self._module_manager.get_widget(AnnotationModule.NAME) widget.set_coords() def set_classified_crack_contours(self, coords): self.image_viewer.set_objects_by_crackcoords_with_colors(coords) widget = self._module_manager.get_widget(AnnotationModule.NAME) widget.set_coords() def show_image(self, image_dict): widget = self.get_display_module() widget.set_image_dict(image_dict) self.update_statusbar() def set_display_module(self, display_module): self.display_module = display_module def get_display_module(self): return self.display_module def update_statusbar(self): meta_data = self._imagecontainer.get_meta_data() if meta_data.has_timelapse: timestamp = meta_data.get_timestamp_relative(self.coordinate) time_info = ' | Frame: %d' % self.coordinate.time if not numpy.isnan(timestamp): time_info += ' (%.1f min)' % (timestamp / 60) else: time_info = '' msg = 'Plate: %s | Position: %s%s || Zoom: %.1f%%' % \ (self.coordinate.plate, self.coordinate.position, time_info, self.image_viewer.scalefactor*100) self._statusbar.showMessage(msg) def get_coordinate(self): return self.coordinate.copy() def on_coordinate_changed(self, coordinate): """ All coordinate changes are handled via the Navigator. The change event from the Navigator is processed here and further propagated via a new Browser event (the Modules are not supposed to know each other). """ self.coordinate = coordinate.copy() self._t_slider.blockSignals(True) self._imagecontainer.set_plate(coordinate.plate) self._t_slider.setValue(coordinate.time) self._t_slider.blockSignals(False) self._process_image() # propagate the signal further to other modules #self.coordinates_changed.emit(coordinate) def set_coordinate(self, coordinate): """ Changes the Navigator to a fixed coordinate """ nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_coordinate(coordinate) def _process_image(self, ): self.image_viewer.remove_objects() settings = BaseProcessorFrame.get_special_settings(self._settings) settings.set_section('General') settings.set2('constrain_positions', True) settings.set2('positions', self.coordinate.position) settings.set2('skip_finished', False) settings.set2('framerange', True) settings.set2('framerange_begin', self.coordinate.time) settings.set2('framerange_end', self.coordinate.time) settings.set_section('Processing') _classify_objects = self._show_objects_by == 'classification' settings.set2('primary_classification', _classify_objects) settings.set2('secondary_classification', _classify_objects) settings.set2('tertiary_classification', _classify_objects) settings.set2('merged_classification', _classify_objects) settings.set2('primary_featureextraction', _classify_objects) settings.set2('secondary_featureextraction', _classify_objects) settings.set2('objectdetection', self._detect_objects) settings.set2('tracking', False) settings.set('Output', 'hdf5_create_file', False) settings.set('General', 'rendering', {}) settings.set('General', 'rendering_class', {}) nchannels = len(self._imagecontainer.channels) # XXX channel mapping unclear # processing channel <--> color channel # i.e problems if 2 processing channels have the same color if nchannels == 2: settings.set('General', 'process_secondary', True) elif nchannels >= 3: settings.set('General', 'process_secondary', True) settings.set('General', 'process_tertiary', True) settings.set('General', 'rendering', {}) analyzer = AnalyzerBrowser(self.coordinate.plate, settings, self._imagecontainer) res = None try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) res = analyzer() self.render_browser(res) except Exception, e: import traceback traceback.print_exc() QMessageBox.critical(self, "Error", str(e)) raise finally:
class Browser(QMainWindow): ZOOM_STEP = 1.05 show_objects_toggled = pyqtSignal('bool') show_contours_toggled = pyqtSignal('bool') coordinates_changed = pyqtSignal(Coordinate) def __init__(self, settings, imagecontainer): super(Browser, self).__init__() frame = QFrame(self) self.setCentralWidget(frame) self._settings = settings self._imagecontainer = imagecontainer self._show_objects = False self._object_region = None self.coordinate = Coordinate() self.grabGesture(Qt.SwipeGesture) self.setStyleSheet("QStatusBar { border-top: 1px solid gray; }") layout = QVBoxLayout(frame) layout.setContentsMargins(0, 0, 0, 0) splitter = QSplitter(Qt.Horizontal, frame) #splitter.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, # QSizePolicy.Expanding)) layout.addWidget(splitter) frame = QFrame(self) frame_side = QStackedWidget(splitter) #splitter.setChildrenCollapsible(False) splitter.addWidget(frame) splitter.addWidget(frame_side) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setSizes([-1, 80]) self.coordinate.plate = self._imagecontainer.plates[0] self._imagecontainer.set_plate(self.coordinate.plate) self.coordinate.channel = self._imagecontainer.channels[0] meta_data = self._imagecontainer.get_meta_data() self.max_time = meta_data.times[-1] self.min_time = meta_data.times[0] self.max_frame = meta_data.dim_t - 1 layout = QGridLayout(frame) layout.setContentsMargins(0, 0, 0, 0) self.image_viewer = ImageViewer(frame, auto_resize=True) layout.addWidget(self.image_viewer, 0, 0) #self.image_viewer.image_mouse_dblclk.connect(self._on_dbl_clk) self.image_viewer.zoom_info_updated.connect(self.on_zoom_info_updated) self._t_slider = QSlider(Qt.Horizontal, frame) self._t_slider.setMinimum(self.min_time) self._t_slider.setMaximum(self.max_time) # self._t_slider.setMaximum(self.max_frame) self._t_slider.setTickPosition(QSlider.TicksBelow) self._t_slider.valueChanged.connect(self.on_time_changed_by_slider, Qt.DirectConnection) if self._imagecontainer.has_timelapse: self._t_slider.show() else: self._t_slider.hide() layout.addWidget(self._t_slider, 1, 0) self.coordinate.position = meta_data.positions[0] self.coordinate.time = self._t_slider.minimum() # menus act_next_t = self.create_action('Next Time-point', shortcut=QKeySequence('Right'), slot=self.on_act_next_t) act_prev_t = self.create_action('Previous Time-point', shortcut=QKeySequence('Left'), slot=self.on_act_prev_t) act_next_pos = self.create_action('Next Position', shortcut=QKeySequence('Shift+Down'), slot=self.on_act_next_pos) act_prev_pos = self.create_action('Previous Position', shortcut=QKeySequence('Shift+Up'), slot=self.on_act_prev_pos) act_next_plate = self.create_action( 'Next Plate', shortcut=QKeySequence('Shift+Alt+Down'), slot=self.on_act_next_plate) act_prev_plate = self.create_action( 'Previous Plate', shortcut=QKeySequence('Shift+Alt+Up'), slot=self.on_act_prev_plate) act_resize = self.create_action('Automatically Resize', shortcut=QKeySequence('SHIFT+CTRL+R'), slot=self.on_act_autoresize, signal='triggered(bool)', checkable=True, checked=True) self._act_resize = act_resize act_zoomfit = self.create_action('Zoom to Fit', shortcut=QKeySequence('CTRL+0'), slot=self.on_act_zoomfit) act_zoom100 = self.create_action('Actual Size', shortcut=QKeySequence('CTRL+1'), slot=self.on_act_zoom100) act_zoomin = self.create_action('Zoom In', shortcut=QKeySequence('CTRL++'), slot=self.on_act_zoomin) act_zoomout = self.create_action('Zoom Out', shortcut=QKeySequence('CTRL+-'), slot=self.on_act_zoomout) act_refresh = self.create_action('Refresh', shortcut=QKeySequence('F5'), slot=self.on_refresh) act_fullscreen = self.create_action('Full Screen', shortcut=QKeySequence('CTRL+F'), slot=self.on_act_fullscreen, signal='triggered(bool)', checkable=True, checked=False) self._act_fullscreen = act_fullscreen act_show_contours = self.create_action( 'Show Object Contours', shortcut=QKeySequence('ALT+C'), slot=self.on_act_show_contours, signal='triggered(bool)', checkable=True, checked=self.image_viewer.show_contours) self._act_show_contours = act_show_contours act_anti = self.create_action('Antialiasing', shortcut=QKeySequence('CTRL+ALT+A'), slot=self.on_act_antialiasing, signal='triggered(bool)', checkable=True, checked=True) act_smooth = self.create_action('Smooth Transform', shortcut=QKeySequence('CTRL+ALT+S'), slot=self.on_act_smoothtransform, signal='triggered(bool)', checkable=True, checked=True) view_menu = self.menuBar().addMenu('&View') self.add_actions(view_menu, ( act_resize, None, act_zoom100, act_zoomfit, act_zoomin, act_zoomout, None, act_prev_t, act_next_t, act_prev_pos, act_next_pos, act_prev_plate, act_next_plate, None, act_refresh, act_fullscreen, None, act_show_contours, None, act_anti, act_smooth, )) self._statusbar = QStatusBar(self) self.setStatusBar(self._statusbar) # tool bar toolbar = self.addToolBar('Toolbar') toolbar.setMovable(False) toolbar.setFloatable(False) region_names = [] for prefix in ['primary', 'secondary', 'tertiary']: region_names.extend(['%s - %s' % (prefix.capitalize(), name) \ for name in REGION_INFO.names[prefix]]) # FIXME: something went wrong with setting up the current region self._object_region = region_names[0].split(' - ') # create a new ModuleManager with a QToolbar and QStackedFrame self._module_manager = ModuleManager(toolbar, frame_side) NavigationModule(self._module_manager, self, self._imagecontainer) DisplayModule(self._module_manager, self, self._imagecontainer, region_names) AnnotationModule(self._module_manager, self, self._settings, self._imagecontainer) # set the Navigation module activated self._module_manager.activate_tab(NavigationModule.NAME) # process and display the first image self._process_image() def create_action(self, text, slot=None, shortcut=None, icon=None, tooltip=None, checkable=None, signal='triggered()', checked=False): action = QAction(text, self) if icon is not None: action.setIcon(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, SIGNAL(signal), slot, Qt.DirectConnection) if checkable is not None: action.setCheckable(True) action.setChecked(checked) return action def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def set_coords(self, coords): self.image_viewer.remove_objects() self.image_viewer.set_objects_by_crackcoords(coords) widget = self._module_manager.get_widget(AnnotationModule.NAME) widget.set_coords() def show_image(self, image_dict): widget = self._module_manager.get_widget(DisplayModule.NAME) widget.set_image_dict(image_dict) self.update_statusbar() def update_statusbar(self): meta_data = self._imagecontainer.get_meta_data() if meta_data.has_timelapse: timestamp = meta_data.get_timestamp_relative(self.coordinate) time_info = ' | Frame: %d' % self.coordinate.time if not numpy.isnan(timestamp): time_info += ' (%.1f min)' % (timestamp / 60) else: time_info = '' msg = 'Plate: %s | Position: %s%s || Zoom: %.1f%%' % \ (self.coordinate.plate, self.coordinate.position, time_info, self.image_viewer.scale_factor*100) self._statusbar.showMessage(msg) def get_coordinate(self): return self.coordinate.copy() def on_coordinate_changed(self, coordinate): """ All coordinate changes are handled via the Navigator. The change event from the Navigator is processed here and further propagated via a new Browser event (the Modules are not supposed to know each other). """ self.coordinate = coordinate.copy() self._t_slider.blockSignals(True) self._imagecontainer.set_plate(coordinate.plate) # the slider is always working with frames. # reason: it is difficult to forbid slider values between allowed values. frame = int( round(self.max_frame * (coordinate.time - self.min_time) / max(float(self.max_time - self.min_time), 1))) self._t_slider.setValue(frame) self._t_slider.blockSignals(False) self._process_image() # propagate the signal further to other modules self.coordinates_changed.emit(coordinate) def set_coordinate(self, coordinate): """ Changes the Navigator to a fixed coordinate """ nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_coordinate(coordinate) def _process_image(self): settings = _ProcessorMixin.get_special_settings(self._settings) settings.set_section('General') settings.set2('constrain_positions', True) settings.set2('positions', self.coordinate.position) settings.set2('redofailedonly', False) settings.set2('framerange', True) settings.set2('framerange_begin', self.coordinate.time) settings.set2('framerange_end', self.coordinate.time) settings.set_section('ObjectDetection') prim_id = PrimaryChannel.NAME #sec_id = SecondaryChannel.NAME #sec_regions = settings.get2('secondary_regions') settings.set_section('Processing') settings.set2('primary_classification', False) settings.set2('secondary_classification', False) settings.set2('tertiary_classification', False) settings.set2('merged_classification', False) settings.set2('primary_featureextraction', False) settings.set2('secondary_featureextraction', False) settings.set2('objectdetection', self._show_objects) settings.set2('tracking', False) settings.set_section('Output') settings.set2('rendering_contours_discwrite', False) settings.set2('rendering_class_discwrite', False) settings.set2('export_object_counts', False) settings.set2('export_object_details', False) settings.set2('export_track_data', False) settings.set2('hdf5_create_file', False) settings.set_section('Classification') settings.set2('collectsamples', False) settings.set('General', 'rendering', {}) settings.set('General', 'rendering_class', {}) settings.set('Output', 'events_export_gallery_images', False) # turn of output: settings.set('Output', 'export_object_counts', False) settings.set('Output', 'export_object_details', False) settings.set('Output', 'export_file_names', False) settings.set('Output', 'events_export_gallery_images', False) settings.set('Output', 'export_track_data', False) settings.set('Output', 'export_tracking_as_dot', False) nchannels = len(self._imagecontainer.channels) # XXX channel mapping unclear # processing channel <--> color channel # i.e problems if 2 processing channels have the # same color if nchannels == 2: settings.set('Processing', 'secondary_processChannel', True) elif nchannels == 3: settings.set('Processing', 'secondary_processChannel', True) settings.set('Processing', 'tertiary_processChannel', True) # need turn of virtual channels settings.set('Processing', 'merged_processChannel', False) settings.set('General', 'rendering', {}) analyzer = AnalyzerCore(self.coordinate.plate, settings, self._imagecontainer) # as long the GIL is not released, if GIL is released # just use self.setCursor try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) analyzer.processPositions(myhack=self) except Exception, e: import traceback traceback.print_exc() raise (e) finally:
class Browser(QMainWindow): ZOOM_STEP = 1.05 show_objects_toggled = pyqtSignal('bool') show_contours_toggled = pyqtSignal('bool') coordinates_changed = pyqtSignal(Coordinate) def __init__(self, settings, imagecontainer): QMainWindow.__init__(self) frame = QFrame(self) self.setCentralWidget(frame) self._stopwatch = StopWatch() self._settings = settings self._imagecontainer = imagecontainer self._show_objects = False self._object_region = None self.coordinate = Coordinate() self.grabGesture(Qt.SwipeGesture) self.setStyleSheet( """ QStatusBar { border-top: 1px solid gray; } """) layout = QVBoxLayout(frame) layout.setContentsMargins(0, 0, 0, 0) splitter = QSplitter(Qt.Horizontal, frame) #splitter.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, # QSizePolicy.Expanding)) layout.addWidget(splitter) frame = QFrame(self) frame_side = QStackedWidget(splitter) #splitter.setChildrenCollapsible(False) splitter.addWidget(frame) splitter.addWidget(frame_side) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setSizes([-1, 80]) self.coordinate.plate = self._imagecontainer.plates[0] self._imagecontainer.set_plate(self.coordinate.plate) self.coordinate.channel = self._imagecontainer.channels[0] meta_data = self._imagecontainer.get_meta_data() layout = QGridLayout(frame) layout.setContentsMargins(0, 0, 0, 0) self.image_viewer = ImageViewer(frame, auto_resize=True) layout.addWidget(self.image_viewer, 0, 0) #self.image_viewer.image_mouse_dblclk.connect(self._on_dbl_clk) self.image_viewer.zoom_info_updated.connect(self.on_zoom_info_updated) self._t_slider = QSlider(Qt.Horizontal, frame) self._t_slider.setMinimum(meta_data.times[0]) self._t_slider.setMaximum(meta_data.times[-1]) self._t_slider.setTickPosition(QSlider.TicksBelow) self._t_slider.valueChanged.connect(self.on_time_changed_by_slider, Qt.DirectConnection) if self._imagecontainer.has_timelapse: self._t_slider.show() else: self._t_slider.hide() layout.addWidget(self._t_slider, 1, 0) self.coordinate.position = meta_data.positions[0] self.coordinate.time = self._t_slider.minimum() # menus act_next_t = self.create_action('Next Time-point', shortcut=QKeySequence('Right'), slot=self.on_act_next_t) act_prev_t = self.create_action('Previous Time-point', shortcut=QKeySequence('Left'), slot=self.on_act_prev_t) act_next_pos = self.create_action('Next Position', shortcut=QKeySequence('Shift+Down'), slot=self.on_act_next_pos) act_prev_pos = self.create_action('Previous Position', shortcut=QKeySequence('Shift+Up'), slot=self.on_act_prev_pos) act_next_plate = self.create_action('Next Plate', shortcut=QKeySequence('Shift+Alt+Down'), slot=self.on_act_next_plate) act_prev_plate = self.create_action('Previous Plate', shortcut=QKeySequence('Shift+Alt+Up'), slot=self.on_act_prev_plate) act_resize = self.create_action('Automatically Resize', shortcut=QKeySequence('SHIFT+CTRL+R'), slot=self.on_act_autoresize, signal='triggered(bool)', checkable=True, checked=True) self._act_resize = act_resize act_zoomfit = self.create_action('Zoom to Fit', shortcut=QKeySequence('CTRL+0'), slot=self.on_act_zoomfit) act_zoom100 = self.create_action('Actual Size', shortcut=QKeySequence('CTRL+1'), slot=self.on_act_zoom100) act_zoomin = self.create_action('Zoom In', shortcut=QKeySequence('CTRL++'), slot=self.on_act_zoomin) act_zoomout = self.create_action('Zoom Out', shortcut=QKeySequence('CTRL+-'), slot=self.on_act_zoomout) act_fullscreen = self.create_action('Full Screen', shortcut=QKeySequence('CTRL+F'), slot=self.on_act_fullscreen, signal='triggered(bool)', checkable=True, checked=False) self._act_fullscreen = act_fullscreen act_show_contours = self.create_action('Show Object Contours', shortcut=QKeySequence('ALT+C'), slot=self.on_act_show_contours, signal='triggered(bool)', checkable=True, checked=self.image_viewer.show_contours) self._act_show_contours = act_show_contours act_anti = self.create_action('Antialiasing', shortcut=QKeySequence('CTRL+ALT+A'), slot=self.on_act_antialiasing, signal='triggered(bool)', checkable=True, checked=True) act_smooth = self.create_action('Smooth Transform', shortcut=QKeySequence('CTRL+ALT+S'), slot=self.on_act_smoothtransform, signal='triggered(bool)', checkable=True, checked=True) view_menu = self.menuBar().addMenu('&View') self.add_actions(view_menu, (act_resize, None, act_zoom100, act_zoomfit, act_zoomin, act_zoomout, None, act_prev_t, act_next_t, act_prev_pos, act_next_pos, act_prev_plate, act_next_plate, None, act_fullscreen, None, act_show_contours, None, act_anti, act_smooth, )) self._statusbar = QStatusBar(self) self.setStatusBar(self._statusbar) # tool bar toolbar = self.addToolBar('Toolbar') toolbar.setMovable(False) toolbar.setFloatable(False) region_names = ['Primary - primary'] self._settings.set_section('ObjectDetection') for prefix in ['secondary', 'tertiary']: if self._settings.get('Processing', '%s_processchannel' % prefix): for name in REGION_NAMES_SECONDARY: if self._settings.get2('%s_regions_%s' % (prefix, name)): region_names.append('%s - %s' % (prefix.capitalize(), name)) # FIXME: something went wrong with setting up the current region self._object_region = region_names[0].split(' - ') # create a new ModuleManager with a QToolbar and QStackedFrame self._module_manager = ModuleManager(toolbar, frame_side) NavigationModule(self._module_manager, self, self._imagecontainer) DisplayModule(self._module_manager, self, self._imagecontainer, region_names) AnnotationModule(self._module_manager, self, self._settings, self._imagecontainer) # set the Navigation module activated self._module_manager.activate_tab(NavigationModule.NAME) # process and display the first image self._process_image() def create_action(self, text, slot=None, shortcut=None, icon=None, tooltip=None, checkable=None, signal='triggered()', checked=False): action = QAction(text, self) if icon is not None: action.setIcon(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, SIGNAL(signal), slot, Qt.DirectConnection) if checkable is not None: action.setCheckable(True) action.setChecked(checked) return action def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def set_coords(self, coords): self.image_viewer.remove_objects() self.image_viewer.set_objects_by_crackcoords(coords) widget = self._module_manager.get_widget(AnnotationModule.NAME) widget.set_coords() def set_image(self, image_dict): widget = self._module_manager.get_widget(DisplayModule.NAME) widget.set_image_dict(image_dict) self.update_statusbar() def update_statusbar(self): meta_data = self._imagecontainer.get_meta_data() if meta_data.has_timelapse: timestamp = meta_data.get_timestamp_relative(self.coordinate) time_info = ' | Frame: %d' % self.coordinate.time if not numpy.isnan(timestamp): time_info += ' (%.1f min)' % (timestamp / 60) else: time_info = '' msg = 'Plate: %s | Position: %s%s || Zoom: %.1f%%' % \ (self.coordinate.plate, self.coordinate.position, time_info, self.image_viewer.scale_factor*100) self._statusbar.showMessage(msg) def get_coordinate(self): return self.coordinate.copy() def on_coordinate_changed(self, coordinate): """ All coordinate changes are handled via the Navigator. The change event from the Navigator is processed here and further propagated via a new Browser event (the Modules are not supposed to know each other). """ self.coordinate = coordinate.copy() self._t_slider.blockSignals(True) self._imagecontainer.set_plate(coordinate.plate) meta_data = self._imagecontainer.get_meta_data() self._t_slider.setMaximum(meta_data.dim_t) self._t_slider.setValue(coordinate.time) self._t_slider.blockSignals(False) self._process_image() # propagate the signal further to other modules self.coordinates_changed.emit(coordinate) def set_coordinate(self, coordinate): """ Changes the Navigator to a fixed coordinate """ nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_coordinate(coordinate) def _process_image(self): print 'process image' self._stopwatch.reset() s = StopWatch() settings = _ProcessorMixin.get_special_settings(self._settings) settings.set_section('General') settings.set2('constrain_positions', True) settings.set2('positions', self.coordinate.position) settings.set2('redofailedonly', False) settings.set2('framerange', True) settings.set2('framerange_begin', self.coordinate.time) settings.set2('framerange_end', self.coordinate.time) settings.set_section('ObjectDetection') prim_id = PrimaryChannel.NAME #sec_id = SecondaryChannel.NAME #sec_regions = settings.get2('secondary_regions') settings.set_section('Processing') settings.set2('primary_classification', False) settings.set2('secondary_classification', False) settings.set2('primary_featureextraction', False) settings.set2('secondary_featureextraction', False) settings.set2('objectdetection', self._show_objects) settings.set2('tracking', False) settings.set_section('Output') settings.set2('rendering_contours_discwrite', False) settings.set2('rendering_class_discwrite', False) settings.set2('export_object_counts', False) settings.set2('export_object_details', False) settings.set2('export_track_data', False) settings.set_section('Classification') settings.set2('collectsamples', False) settings.set('General', 'rendering', {}) settings.set('General', 'rendering_class', {}) if len(self._imagecontainer.channels) > 1: settings.set('Processing', 'secondary_processChannel', True) settings.set('General', 'rendering', {}) print settings analyzer = AnalyzerCore(self.coordinate.plate, settings, self._imagecontainer) analyzer.processPositions(myhack=self) print('PROCESS IMAGE: %s' % s) # slots def on_zoom_info_updated(self, info): self.update_statusbar() def on_time_changed_by_slider(self, time): nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_time(time) def on_object_region_changed(self, channel, region): self._object_region = channel, region self._process_image() def on_act_prev_t(self): self._t_slider.setValue(self._t_slider.value()-1) def on_act_next_t(self): self._t_slider.setValue(self._t_slider.value()+1) def on_act_prev_pos(self): nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_prev_position() def on_act_next_pos(self): nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_next_position() def on_act_prev_plate(self): nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_prev_plate() def on_act_next_plate(self): nav = self._module_manager.get_widget(NavigationModule.NAME) nav.nav_to_next_plate() def on_act_fullscreen(self, checked): if checked: self.showFullScreen() else: self.showNormal() self.raise_() def on_act_show_contours(self, checked): self._act_show_contours.blockSignals(True) self._act_show_contours.setChecked(checked) self._act_show_contours.blockSignals(False) self.image_viewer.set_show_contours(checked) self.show_contours_toggled.emit(checked) def on_act_antialiasing(self, checked): self.image_viewer.setRenderHint(QPainter.Antialiasing, checked) self.image_viewer.update() def on_act_smoothtransform(self, checked): self.image_viewer.setRenderHint(QPainter.SmoothPixmapTransform, checked) self.image_viewer.update() def on_act_autoresize(self, state): self.image_viewer.set_auto_resize(state) if state: self.image_viewer.scale_to_fit() def on_act_zoom100(self): self.image_viewer.set_auto_resize(False) self._act_resize.setChecked(False) self.image_viewer.scale_reset() def on_act_zoomfit(self): self.image_viewer.set_auto_resize(False) self._act_resize.setChecked(False) self.image_viewer.scale_to_fit() def on_act_zoomin(self): self.image_viewer.set_auto_resize(False) self._act_resize.setChecked(False) self.image_viewer.scale_relative(self.ZOOM_STEP, ensure_fit=False) def on_act_zoomout(self): self.image_viewer.set_auto_resize(False) self._act_resize.setChecked(False) self.image_viewer.scale_relative(1/self.ZOOM_STEP, ensure_fit=True) def on_act_transform(self, checked): if checked: self.image_viewer.set_scale_transform(Qt.FastTransformation) else: self.image_viewer.set_scale_transform(Qt.SmoothTransformation) self._process_image() def on_act_class_selected(self, class_label): items = self._find_items_in_class_table(str(class_label), self.COLUMN_CLASS_LABEL) if len(items) == 1: self._class_table.setCurrentItem(items[0]) def on_show_objects(self, state): self._show_objects = state self.image_viewer.remove_objects() self._process_image() self.show_objects_toggled.emit(state) # Qt method overwrites def keyPressEvent(self, ev): QMainWindow.keyPressEvent(self, ev) # allow to return from fullscreen via the Escape key if self.isFullScreen() and ev.key() == Qt.Key_Escape: self.showNormal() self._act_fullscreen.setChecked(False) self.raise_() def gestureEvent(self, ev): # determine whether a swipe gesture was detected if not ev.gesture(Qt.SwipeGesture) is None: gesture = ev.gesture(Qt.SwipeGesture) if gesture.state() == Qt.GestureFinished: if gesture.horizontalDirection() == QSwipeGesture.Left: self._on_act_left() elif gesture.horizontalDirection() == QSwipeGesture.Right: self._on_act_right() elif gesture.horizontalDirection() == QSwipeGesture.Up: self._on_act_up() elif gesture.horizontalDirection() == QSwipeGesture.Down: self._on_act_down() return True def event(self, ev): if ev.type() == QEvent.Gesture: return self.gestureEvent(ev) return QWidget.event(self, ev)