def _updateLabelShortcuts(self): numShortcuts = len(self._labelShortcuts) numRows = len(self._labelControlUi.labelListModel) mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo # Add any shortcuts we don't have yet. for i in range(numShortcuts, numRows): toolTipObject = LabelListModel.EntryToolTipAdapter( self._labelControlUi.labelListModel, i) action_info = ActionInfo( "Labeling", "Select Label {}".format(i + 1), "Select Label {}".format(i + 1), partial(self._labelControlUi.labelListView.selectRow, i), self._labelControlUi.labelListView, toolTipObject) mgr.register(str(i + 1), action_info) self._labelShortcuts.append(action_info) # Make sure that all shortcuts have an appropriate description for i in range(numRows): action_info = self._labelShortcuts[i] description = "Select " + self._labelControlUi.labelListModel[ i].name new_action_info = mgr.update_description(action_info, description) self._labelShortcuts[i] = new_action_info
def createDrawerControls(self): op = self.topLevelOperatorView def configure_update_handlers( qt_signal, op_slot ): qt_signal.connect( self.configure_operator_from_gui ) cleanup_fn = op_slot.notifyDirty( self.configure_gui_from_operator, defer=True ) self.__cleanup_fns.append( cleanup_fn ) # Controls feature_selection_button = QPushButton(text="Select Features", icon=QIcon(ilastikIcons.AddSel), toolTip="Select edge/superpixel features to use for classification.", clicked=self._open_feature_selection_dlg) self.train_from_gt_button = QPushButton(text="Auto-label", icon=QIcon(ilastikIcons.Segment), toolTip="Automatically label all edges according to your pre-loaded groundtruth volume.", clicked=self._handle_label_from_gt_clicked) self.clear_labels_button = QPushButton(text="Clear Labels", icon=QIcon(ilastikIcons.Clear), toolTip="Remove all edge labels. (Start over on this image.)", clicked=self._handle_clear_labels_clicked) self.live_update_button = QPushButton(text="Live Predict", checkable=True, icon=QIcon(ilastikIcons.Play), toolTip="Update the edge classifier predictions", clicked=self._handle_live_update_clicked) configure_update_handlers( self.live_update_button.toggled, op.FreezeCache ) # Layout label_layout = QHBoxLayout() label_layout.addWidget(self.clear_labels_button) label_layout.addWidget(self.train_from_gt_button) label_layout.setSpacing(1) layout = QVBoxLayout() layout.addWidget(feature_selection_button) layout.setSpacing(1) layout.addLayout(label_layout) layout.addWidget(self.live_update_button) layout.addSpacerItem( QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Expanding) ) # Finally, the whole drawer widget drawer = QWidget(parent=self) drawer.setLayout(layout) # Widget Shortcuts mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcut_group = "Edge Training" mgr.register( "l", ActionInfo( shortcut_group, "Live Predict", "Toggle live edge classifier update mode", self.live_update_button.toggle, self.live_update_button, self.live_update_button ) ) return drawer
def __initShortcuts(self): mgr = ShortcutManager() shortcutGroupName = "Labeling" if hasattr(self.labelingDrawerUi, "AddLabelButton"): addLabel = QShortcut(QKeySequence("a"), self, member=self.labelingDrawerUi.AddLabelButton.click) mgr.register(shortcutGroupName, "Add New Label Class", addLabel, self.labelingDrawerUi.AddLabelButton) navMode = QShortcut(QKeySequence("n"), self, member=self.labelingDrawerUi.arrowToolButton.click) mgr.register(shortcutGroupName, "Navigation Cursor", navMode, self.labelingDrawerUi.arrowToolButton) brushMode = QShortcut(QKeySequence("b"), self, member=self.labelingDrawerUi.paintToolButton.click) mgr.register(shortcutGroupName, "Brush Cursor", brushMode, self.labelingDrawerUi.paintToolButton) eraserMode = QShortcut(QKeySequence("e"), self, member=self.labelingDrawerUi.eraserToolButton.click) mgr.register(shortcutGroupName, "Eraser Cursor", eraserMode, self.labelingDrawerUi.eraserToolButton) """ changeBrushSize = QShortcut( QKeySequence("c"), self, member=self.labelingDrawerUi.brushSizeComboBox.showPopup ) mgr.register( shortcutGroupName, "Change Brush Size", changeBrushSize, self.labelingDrawerUi.brushSizeComboBox ) """ self._labelShortcuts = []
def __initShortcuts(self): mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcutGroupName = "Labeling" if hasattr(self.labelingDrawerUi, "AddLabelButton"): mgr.register("a", ActionInfo( shortcutGroupName, "New Label", "Add New Label Class", self.labelingDrawerUi.AddLabelButton.click, self.labelingDrawerUi.AddLabelButton, self.labelingDrawerUi.AddLabelButton ) ) mgr.register( "n", ActionInfo( shortcutGroupName, "Navigation Cursor", "Navigation Cursor", self.labelingDrawerUi.arrowToolButton.click, self.labelingDrawerUi.arrowToolButton, self.labelingDrawerUi.arrowToolButton ) ) mgr.register( "b", ActionInfo( shortcutGroupName, "Brush Cursor", "Brush Cursor", self.labelingDrawerUi.paintToolButton.click, self.labelingDrawerUi.paintToolButton, self.labelingDrawerUi.paintToolButton ) ) mgr.register( "e", ActionInfo( shortcutGroupName, "Eraser Cursor", "Eraser Cursor", self.labelingDrawerUi.eraserToolButton.click, self.labelingDrawerUi.eraserToolButton, self.labelingDrawerUi.eraserToolButton ) ) self._labelShortcuts = []
def setUpShortcuts(self): mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo selector = self.channelSelector def inc(): selector.setValue(selector.value() + selector.singleStep()) def dec(): selector.setValue(selector.value() - selector.singleStep()) # Can't pass channelSelector(QSpinBox) as tooltip widget # because it doesn't have # separate tooltips for arrows mgr.register(NEXT_CHANNEL_SEQ, ActionInfo("Navigation", "Next channel", "Next channel", inc, selector, None)) mgr.register(PREV_CHANNEL_SEQ, ActionInfo("Navigation", "Prev channel", "Prev channel", dec, selector, None))
def _initShortcuts(self): mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcutGroupName = "Predictions" mgr.register( "p", ActionInfo( shortcutGroupName, "Toggle Prediction", "Toggle Prediction Layer Visibility", self._viewerControlUi.checkShowPredictions.click, self._viewerControlUi.checkShowPredictions, self._viewerControlUi.checkShowPredictions ) ) mgr.register( "s", ActionInfo( shortcutGroupName, "Toggle Segmentaton", "Toggle Segmentaton Layer Visibility", self._viewerControlUi.checkShowSegmentation.click, self._viewerControlUi.checkShowSegmentation, self._viewerControlUi.checkShowSegmentation ) ) mgr.register( "l", ActionInfo( shortcutGroupName, "Live Prediction", "Toggle Live Prediction Mode", self.labelingDrawerUi.liveUpdateButton.toggle, self.labelingDrawerUi.liveUpdateButton, self.labelingDrawerUi.liveUpdateButton ) )
def _initShortcuts(self): mgr = ShortcutManager() shortcutGroupName = "Predictions" togglePredictions = QShortcut(QKeySequence("p"), self, member=self._viewerControlUi.checkShowPredictions.click) mgr.register( shortcutGroupName, "Toggle Prediction Layer Visibility", togglePredictions, self._viewerControlUi.checkShowPredictions, ) toggleSegmentation = QShortcut( QKeySequence("s"), self, member=self._viewerControlUi.checkShowSegmentation.click ) mgr.register( shortcutGroupName, "Toggle Segmentaton Layer Visibility", toggleSegmentation, self._viewerControlUi.checkShowSegmentation, ) toggleLivePredict = QShortcut(QKeySequence("l"), self, member=self.labelingDrawerUi.liveUpdateButton.toggle) mgr.register( shortcutGroupName, "Toggle Live Prediction Mode", toggleLivePredict, self.labelingDrawerUi.liveUpdateButton )
def __initShortcuts(self): mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcutGroupName = "Cropping" if hasattr(self.croppingDrawerUi, "AddCropButton"): mgr.register("n", ActionInfo( shortcutGroupName, "New Crop", "Add a new crop.", self.croppingDrawerUi.AddCropButton.click, self.croppingDrawerUi.AddCropButton, self.croppingDrawerUi.AddCropButton ) ) if hasattr(self.croppingDrawerUi, "SetCropButton"): mgr.register("s", ActionInfo( shortcutGroupName, "Save Crop", "Save the current crop.", self.croppingDrawerUi.SetCropButton.click, self.croppingDrawerUi.SetCropButton, self.croppingDrawerUi.SetCropButton ) ) self._cropShortcuts = []
def createDrawerControls(self): """ This is a separate function from initAppletDrawer() so that it can be called and used within another applet (this class is a mixin). """ op = self.__topLevelOperatorView def configure_update_handlers(qt_signal, op_slot): qt_signal.connect(self.configure_operator_from_gui) op_slot.notifyDirty(self.configure_gui_from_operator) self.__cleanup_fns.append( partial(op_slot.unregisterDirty, self.configure_gui_from_operator)) def control_layout(label_text, widget): row_layout = QHBoxLayout() row_layout.addWidget(QLabel(label_text)) row_layout.addSpacerItem(QSpacerItem(10, 0, QSizePolicy.Expanding)) row_layout.addWidget(widget) return row_layout drawer_layout = QVBoxLayout() drawer_layout.setSpacing(1) # Beta beta_box = QDoubleSpinBox( decimals=2, minimum=0.01, maximum=0.99, singleStep=0.1, toolTip="Bias parameter for the multicut optimization.", ) configure_update_handlers(beta_box.valueChanged, op.Beta) beta_layout = control_layout("Beta", beta_box) drawer_layout.addLayout(beta_layout) self.beta_box = beta_box # Solver solver_name_combo = QComboBox( toolTip= "Multicut optimization technique. Available solvers depend on which optimizer library you have installed." ) for solver_name in AVAILABLE_SOLVER_NAMES: solver_name_combo.addItem(solver_name) configure_update_handlers(solver_name_combo.currentIndexChanged, op.SolverName) drawer_layout.addLayout(control_layout("Solver", solver_name_combo)) self.solver_name_combo = solver_name_combo button_layout = QHBoxLayout() # Live Multicut Button live_multicut_button = QPushButton(text="Live Multicut", checkable=True, icon=QIcon(ilastikIcons.Play)) configure_update_handlers(live_multicut_button.toggled, op.FreezeCache) # Extra: Auto-show the multicut edges if necessary. def auto_show_multicut_layer(checked): if checked: self.getLayerByName("Multicut Edges").visible = True live_multicut_button.toggled.connect(auto_show_multicut_layer) button_layout.addWidget(live_multicut_button) self.live_multicut_button = live_multicut_button # Update Button update_button = QPushButton( text="Update Now", icon=QIcon(ilastikIcons.Play), clicked=self._handle_mulicut_update_clicked) button_layout.addWidget(update_button) self.update_button = update_button drawer_layout.addLayout(button_layout) # Layout drawer_layout.addSpacerItem( QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)) # Finally, the whole drawer widget drawer = QWidget(parent=self) drawer.setLayout(drawer_layout) # Widget Shortcuts mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcut_group = "Multicut" mgr.register( "u", ActionInfo( shortcut_group, "UpdateMulticut", "Run the multicut optimization using the current edge probabilities", update_button.click, update_button, update_button, ), ) return drawer
def __initShortcuts(self): mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcutGroupName = "Labeling" if hasattr(self.labelingDrawerUi, "AddLabelButton"): mgr.register("a", ActionInfo(shortcutGroupName, "New Label", "Add New Label Class", self.labelingDrawerUi.AddLabelButton.click, self.labelingDrawerUi.AddLabelButton, self.labelingDrawerUi.AddLabelButton)) mgr.register("n", ActionInfo(shortcutGroupName, "Navigation Cursor", "Navigation Cursor", self.labelingDrawerUi.arrowToolButton.click, self.labelingDrawerUi.arrowToolButton, self.labelingDrawerUi.arrowToolButton)) mgr.register("b", ActionInfo( shortcutGroupName, "Brush Cursor", "Brush Cursor", self.labelingDrawerUi.paintToolButton.click, self.labelingDrawerUi.paintToolButton, self.labelingDrawerUi.paintToolButton)) mgr.register("e", ActionInfo(shortcutGroupName, "Eraser Cursor", "Eraser Cursor", self.labelingDrawerUi.eraserToolButton.click, self.labelingDrawerUi.eraserToolButton, self.labelingDrawerUi.eraserToolButton)) mgr.register(",", ActionInfo( shortcutGroupName, "Decrease Brush Size", "Decrease Brush Size", partial(self._tweakBrushSize, False), self.labelingDrawerUi.brushSizeComboBox, self.labelingDrawerUi.brushSizeComboBox)) mgr.register(".", ActionInfo(shortcutGroupName, "Increase Brush Size", "Increase Brush Size", partial(self._tweakBrushSize, True), self.labelingDrawerUi.brushSizeComboBox, self.labelingDrawerUi.brushSizeComboBox)) if hasattr(self.labelingDrawerUi, "thresToolButton"): mgr.register("t", ActionInfo(shortcutGroupName, "Window Leveling", "<p>Window Leveling can be used to adjust the data range used for visualization. Pressing the left mouse button while moving the mouse back and forth changes the window width (data range). Moving the mouse in the left-right plane changes the window mean. Pressing the right mouse button resets the view back to the original data.", self.labelingDrawerUi.thresToolButton.click, self.labelingDrawerUi.thresToolButton, self.labelingDrawerUi.thresToolButton)) self._labelShortcuts = []
def __init__(self, parentApplet, topLevelOperatorView, drawerUiPath=None ): self.topLevelOperatorView = topLevelOperatorView self.isInitialized = False # Need this flag in carvingApplet where initialization is terminated with label selection #members self._doneSegmentationLayer = None self._showSegmentationIn3D = False #self._showUncertaintyLayer = False #end: members labelingSlots = LabelingGui.LabelingSlots() labelingSlots.labelInput = topLevelOperatorView.WriteSeeds labelingSlots.labelOutput = topLevelOperatorView.opLabelArray.Output labelingSlots.labelEraserValue = topLevelOperatorView.opLabelArray.EraserLabelValue labelingSlots.labelNames = topLevelOperatorView.LabelNames labelingSlots.labelDelete = topLevelOperatorView.opLabelArray.DeleteLabel labelingSlots.maxLabelValue = topLevelOperatorView.opLabelArray.MaxLabelValue # We provide our own UI file (which adds an extra control for interactive mode) directory = os.path.split(__file__)[0] if drawerUiPath is None: drawerUiPath = os.path.join(directory, 'carvingDrawer.ui') self.dialogdirCOM = os.path.join(directory, 'carvingObjectManagement.ui') self.dialogdirSAD = os.path.join(directory, 'saveAsDialog.ui') # Add 3DWidget only if the data is 3D is_3d = self._is_3d() super(CarvingGui, self).__init__(parentApplet, labelingSlots, topLevelOperatorView, drawerUiPath, is_3d_widget_visible=is_3d) self.parentApplet = parentApplet self.labelingDrawerUi.currentObjectLabel.setText("<not saved yet>") # Init special base class members self.minLabelNumber = 2 self.maxLabelNumber = 2 mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo #set up keyboard shortcuts mgr.register( "3", ActionInfo( "Carving", "Run interactive segmentation", "Run interactive segmentation", self.labelingDrawerUi.segment.click, self.labelingDrawerUi.segment, self.labelingDrawerUi.segment ) ) # Disable 3D view by default self.render = False if is_3d: try: self._renderMgr = RenderingManager( self.editor.view3d ) self._shownObjects3D = {} self.render = True except: self.render = False # Segmentation is toggled on by default in _after_init, below. # (We can't enable it until the layers are all present.) self._showSegmentationIn3D = False self._segmentation_3d_label = None self.labelingDrawerUi.segment.clicked.connect(self.onSegmentButton) self.labelingDrawerUi.segment.setEnabled(True) self.topLevelOperatorView.Segmentation.notifyDirty( bind( self._segmentation_dirty ) ) self.topLevelOperatorView.HasSegmentation.notifyValueChanged( bind( self._updateGui ) ) ## uncertainty #self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) #self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) #def onUncertaintyFGButton(): # logger.debug( "uncertFG button clicked" ) # pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=2) # self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) #self.labelingDrawerUi.pushButtonUncertaintyFG.clicked.connect(onUncertaintyFGButton) #def onUncertaintyBGButton(): # logger.debug( "uncertBG button clicked" ) # pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=1) # self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) #self.labelingDrawerUi.pushButtonUncertaintyBG.clicked.connect(onUncertaintyBGButton) #def onUncertaintyCombo(value): # if value == 0: # value = "none" # self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) # self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) # self._showUncertaintyLayer = False # else: # if value == 1: # value = "localMargin" # elif value == 2: # value = "exchangeCount" # elif value == 3: # value = "gabow" # else: # raise RuntimeError("unhandled case '%r'" % value) # self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(True) # self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(True) # self._showUncertaintyLayer = True # logger.debug( "uncertainty changed to %r" % value ) # self.topLevelOperatorView.UncertaintyType.setValue(value) # self.updateAllLayers() #make sure that an added/deleted uncertainty layer is recognized #self.labelingDrawerUi.uncertaintyCombo.currentIndexChanged.connect(onUncertaintyCombo) self.labelingDrawerUi.objPrefix.setText(self.objectPrefix) self.labelingDrawerUi.objPrefix.textChanged.connect(self.setObjectPrefix) ## save self.labelingDrawerUi.save.clicked.connect(self.onSaveButton) ## clear self.labelingDrawerUi.clear.clicked.connect(self._onClearAction) ## object names self.labelingDrawerUi.namesButton.clicked.connect(self.onShowObjectNames) if hasattr( self.labelingDrawerUi, 'exportAllMeshesButton' ): self.labelingDrawerUi.exportAllMeshesButton.clicked.connect(self._exportAllObjectMeshes) self.labelingDrawerUi.labelListView.allowDelete = False self._labelControlUi.labelListModel.allowRemove(False) def layerIndexForName(name): return self.layerstack.findMatchingIndex(lambda x: x.name == name) def addLayerToggleShortcut(layername, shortcut): def toggle(): row = layerIndexForName(layername) self.layerstack.selectRow(row) layer = self.layerstack[row] layer.visible = not layer.visible self.viewerControlWidget().layerWidget.setFocus() mgr.register(shortcut, ActionInfo( "Carving", "Toggle layer %s" % layername, "Toggle layer %s" % layername, toggle, self.viewerControlWidget(), None ) ) #TODO addLayerToggleShortcut("Completed segments (unicolor)", "d") addLayerToggleShortcut("Segmentation", "s") addLayerToggleShortcut("Input Data", "r") def makeColortable(): self._doneSegmentationColortable = [QColor(0,0,0,0).rgba()] for i in range(254): r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) # ensure colors have sufficient distance to pure red and pure green while (255 - r)+g+b<128 or r+(255-g)+b<128: r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) self._doneSegmentationColortable.append(QColor(r,g,b).rgba()) self._doneSegmentationColortable.append(QColor(0,255,0).rgba()) makeColortable() self._updateGui()
def _initViewMenu(self): self._viewMenu = QMenu("View", parent=self) self._viewMenu.setObjectName("view_menu") self._debugActions = [] ActionInfo = ShortcutManager.ActionInfo # This action is saved as a member so it can be triggered from tests self._viewMenu.actionFitToScreen = self._viewMenu.addAction( "&Zoom to &fit") self._viewMenu.actionFitToScreen.triggered.connect(self._fitToScreen) def toggleHud(): hide = not self.editor.imageViews[0]._hud.isVisible() for v in self.editor.imageViews: v.setHudVisible(hide) # This action is saved as a member so it can be triggered from tests self._viewMenu.actionToggleAllHuds = self._viewMenu.addAction( "Toggle huds") self._viewMenu.actionToggleAllHuds.triggered.connect(toggleHud) def resetAllAxes(): for s in self.editor.imageScenes: s.resetAxes() self._viewMenu.addAction("Reset all axes").triggered.connect( resetAllAxes) def centerAllImages(): for v in self.editor.imageViews: v.centerImage() self._viewMenu.addAction("Center images").triggered.connect( centerAllImages) def toggleDebugPatches(show): self.editor.showDebugPatches = show actionShowTiling = self._viewMenu.addAction("Show Tiling") actionShowTiling.setCheckable(True) actionShowTiling.toggled.connect(toggleDebugPatches) ShortcutManager().register( "Ctrl+D", ActionInfo("Navigation", "Show tiling", "Show tiling", actionShowTiling.toggle, self, None)) self._debugActions.append(actionShowTiling) def setCacheSize(cache_size): dlg = QDialog(self) layout = QHBoxLayout() layout.addWidget(QLabel("Cached Slices Per View:")) spinBox = QSpinBox(parent=dlg) spinBox.setRange(0, 1000) spinBox.setValue(self.editor.cacheSize) layout.addWidget(spinBox) okButton = QPushButton("OK", parent=dlg) okButton.clicked.connect(dlg.accept) layout.addWidget(okButton) dlg.setLayout(layout) dlg.setModal(True) if dlg.exec_() == QDialog.Accepted: self.editor.cacheSize = spinBox.value() self._viewMenu.addAction("Set layer cache size").triggered.connect( setCacheSize) def enablePrefetching(enable): # Enable for Z view only self.editor.imageScenes[2].setPrefetchingEnabled(enable) # for scene in self.editor.imageScenes: # scene.setPrefetchingEnabled( enable ) actionUsePrefetching = self._viewMenu.addAction("Use prefetching") actionUsePrefetching.setCheckable(True) actionUsePrefetching.toggled.connect(enablePrefetching) def blockGuiForRendering(): for v in self.editor.imageViews: v.scene().joinRenderingAllTiles() v.repaint() QApplication.processEvents() actionBlockGui = self._viewMenu.addAction("Block for rendering") actionBlockGui.triggered.connect(blockGuiForRendering) ShortcutManager().register( "Ctrl+B", ActionInfo("Navigation", "Block gui for rendering", "Block gui for rendering", actionBlockGui.trigger, self, None)) self._debugActions.append(actionBlockGui) def changeTileWidth(): '''Change tile width (tile block size) and reset image-scene''' dlg = QDialog(self) layout = QHBoxLayout() layout.addWidget(QLabel("Tile Width:")) spinBox = QSpinBox(parent=dlg) spinBox.setRange(128, 10 * 1024) spinBox.setValue(512) if self.editor.imageScenes[0].tileWidth: spinBox.setValue(self.editor.imageScenes[0].tileWidth) layout.addWidget(spinBox) okButton = QPushButton("OK", parent=dlg) okButton.clicked.connect(dlg.accept) layout.addWidget(okButton) dlg.setLayout(layout) dlg.setModal(True) if dlg.exec_() == QDialog.Accepted: for s in self.editor.imageScenes: if s.tileWidth != spinBox.value(): s.tileWidth = spinBox.value() s.reset() self._viewMenu.addAction("Set Tile Width...").triggered.connect( changeTileWidth) # ------ Separator ------ self._viewMenu.addAction("").setSeparator(True) # Text only actionOnlyForSelectedView = self._viewMenu.addAction( "Only for selected view") actionOnlyForSelectedView.setIconVisibleInMenu(True) font = actionOnlyForSelectedView.font() font.setItalic(True) font.setBold(True) actionOnlyForSelectedView.setFont(font) def setCurrentAxisIcon(): """Update the icon that shows the currently selected axis.""" actionOnlyForSelectedView.setIcon( QIcon(self.editor.imageViews[ self.editor._lastImageViewFocus]._hud.axisLabel.pixmap())) self.editor.newImageView2DFocus.connect(setCurrentAxisIcon) setCurrentAxisIcon() actionFitImage = self._viewMenu.addAction("Fit image") actionFitImage.triggered.connect(self._fitImage) ShortcutManager().register( "K", ActionInfo("Navigation", "Fit image on screen", "Fit image on screen", actionFitImage.trigger, self, None)) def toggleSelectedHud(): self.editor.imageViews[self.editor._lastImageViewFocus].toggleHud() actionToggleSelectedHud = self._viewMenu.addAction("Toggle hud") actionToggleSelectedHud.triggered.connect(toggleSelectedHud) def resetAxes(): self.editor.imageScenes[ self.editor._lastImageViewFocus].resetAxes() self._viewMenu.addAction("Reset axes").triggered.connect(resetAxes) def centerImage(): self.editor.imageViews[ self.editor._lastImageViewFocus].centerImage() actionCenterImage = self._viewMenu.addAction("Center image") actionCenterImage.triggered.connect(centerImage) ShortcutManager().register( "C", ActionInfo("Navigation", "Center image", "Center image", actionCenterImage.trigger, self, None)) def restoreImageToOriginalSize(): self.editor.imageViews[self.editor._lastImageViewFocus].doScaleTo() actionResetZoom = self._viewMenu.addAction("Reset zoom") actionResetZoom.triggered.connect(restoreImageToOriginalSize) ShortcutManager().register( "W", ActionInfo("Navigation", "Reset zoom", "Reset zoom", actionResetZoom.trigger, self, None)) def updateHudActions(): dataShape = self.editor.dataShape # if the image is 2D, do not show the HUD action (issue #190) is2D = numpy.sum(numpy.asarray(dataShape[1:4]) == 1) == 1 actionToggleSelectedHud.setVisible(not is2D) self._viewMenu.actionToggleAllHuds.setVisible(not is2D) self.editor.shapeChanged.connect(updateHudActions)
def updateAllLayers(self, slot=None): if self._stopped or not self._initialized: return if slot is not None and slot.ready() and slot.meta.axistags is None: # Don't update in response to value slots. return self._need_update = False # Ask for the updated layer list (usually provided by the subclass) newGuiLayers = self.setupLayers() # The order of the initial layerstack has to be static, where the "Raw Input" layer is at the stacks last position for i in range(len(newGuiLayers)): if newGuiLayers[i].name == "Raw Input": rlayer = newGuiLayers[i] newGuiLayers.remove(rlayer) newGuiLayers.append(rlayer) break for layer in newGuiLayers: assert not [l for l in self.layerstack if l is layer], \ "You are attempting to re-use a layer ({}). " \ "Your setupOutputs() function may not re-use layer objects. " \ "The layerstack retains ownership of the layers you provide and " \ "may choose to clean and delete them without your knowledge.".format( layer.name ) newNames = set(l.name for l in newGuiLayers) if len(newNames) != len(newGuiLayers): msg = "All layers must have unique names.\n" msg += "You're attempting to use these layer names:\n" msg += str([l.name for l in newGuiLayers]) raise RuntimeError(msg) # If the datashape changed, tell the editor # FIXME: This may not be necessary now that this gui doesn't handle the multi-image case... newDataShape = self.determineDatashape() if newDataShape is not None and self.editor.dataShape != newDataShape: self.editor.dataShape = newDataShape # Find the xyz midpoint midpos5d = [x // 2 for x in newDataShape] # center viewer there self.setViewerPos(midpos5d) # Old layers are deleted if # (1) They are not in the new set or # (2) Their data has changed for index, oldLayer in reversed(list(enumerate(self.layerstack))): if oldLayer.name not in newNames: needDelete = True else: newLayer = list( filter(lambda l: l.name == oldLayer.name, newGuiLayers))[0] needDelete = newLayer.isDifferentEnough(oldLayer) if needDelete: layer = self.layerstack[index] if hasattr(layer, 'shortcutRegistration'): action_info = layer.shortcutRegistration[1] ShortcutManager().unregister(action_info) self.layerstack.selectRow(index) self.layerstack.deleteSelected() # Insert all layers that aren't already in the layerstack # (Identified by the name attribute) existingNames = set(l.name for l in self.layerstack) for index, layer in enumerate(newGuiLayers): if layer.name not in existingNames: # Insert new self.layerstack.insert(index, layer) # If this layer has an associated shortcut, register it with the shortcut manager if hasattr(layer, 'shortcutRegistration'): ShortcutManager().register(*layer.shortcutRegistration) else: # Clean up the layer instance that the client just gave us. # We don't want to use it. layer.clean_up() # Move existing layer to the correct position stackIndex = self.layerstack.findMatchingIndex( lambda l: l.name == layer.name) self.layerstack.selectRow(stackIndex) while stackIndex > index: self.layerstack.moveSelectedUp() stackIndex -= 1 while stackIndex < index: self.layerstack.moveSelectedDown() stackIndex += 1 if len(self.layerstack) > 0: self.centralWidget().setEnabled(True)
def createDrawerControls(self): """ This is a separate function from initAppletDrawer() so that it can be called and used within another applet (this class is a mixin). """ op = self.__topLevelOperatorView def configure_update_handlers(qt_signal, op_slot): qt_signal.connect(self.configure_operator_from_gui) op_slot.notifyDirty(self.configure_gui_from_operator) self.__cleanup_fns.append(partial(op_slot.unregisterDirty, self.configure_gui_from_operator)) def control_layout(label_text, widget): row_layout = QHBoxLayout() row_layout.addWidget(QLabel(label_text)) row_layout.addSpacerItem(QSpacerItem(10, 0, QSizePolicy.Expanding)) row_layout.addWidget(widget) return row_layout drawer_layout = QVBoxLayout() drawer_layout.setSpacing(1) # Beta beta_box = QDoubleSpinBox( decimals=2, minimum=0.01, maximum=0.99, singleStep=0.1, toolTip="Bias parameter for the multicut optimization.", ) configure_update_handlers(beta_box.valueChanged, op.Beta) beta_layout = control_layout("Beta", beta_box) drawer_layout.addLayout(beta_layout) self.beta_box = beta_box # Solver solver_name_combo = QComboBox( toolTip="Multicut optimization technique. Available solvers depend on which optimizer library you have installed." ) for solver_name in AVAILABLE_SOLVER_NAMES: solver_name_combo.addItem(solver_name) configure_update_handlers(solver_name_combo.currentIndexChanged, op.SolverName) drawer_layout.addLayout(control_layout("Solver", solver_name_combo)) self.solver_name_combo = solver_name_combo # Update Button update_button = QPushButton( text="Update Multicut", icon=QIcon(ilastikIcons.Play), clicked=self.onUpdateMulticutButton ) drawer_layout.addWidget(update_button) # Layout drawer_layout.addSpacerItem(QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)) # Finally, the whole drawer widget drawer = QWidget(parent=self) drawer.setLayout(drawer_layout) # Widget Shortcuts mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcut_group = "Multicut" mgr.register( "u", ActionInfo( shortcut_group, "UpdateMulticut", "Run the multicut optimization using the current edge probabilities", update_button.click, update_button, update_button, ), ) return drawer
def __init__(self, parentApplet, topLevelOperatorView, drawerUiPath=None ): self.topLevelOperatorView = topLevelOperatorView #members self._doneSegmentationLayer = None self._showSegmentationIn3D = False self._showUncertaintyLayer = False #end: members labelingSlots = LabelingGui.LabelingSlots() labelingSlots.labelInput = topLevelOperatorView.WriteSeeds labelingSlots.labelOutput = topLevelOperatorView.opLabelArray.Output labelingSlots.labelEraserValue = topLevelOperatorView.opLabelArray.EraserLabelValue labelingSlots.labelNames = topLevelOperatorView.LabelNames labelingSlots.labelDelete = topLevelOperatorView.opLabelArray.DeleteLabel labelingSlots.maxLabelValue = topLevelOperatorView.opLabelArray.MaxLabelValue labelingSlots.labelsAllowed = topLevelOperatorView.LabelsAllowed # We provide our own UI file (which adds an extra control for interactive mode) directory = os.path.split(__file__)[0] if drawerUiPath is None: drawerUiPath = os.path.join(directory, 'carvingDrawer.ui') self.dialogdirCOM = os.path.join(directory, 'carvingObjectManagement.ui') self.dialogdirSAD = os.path.join(directory, 'saveAsDialog.ui') rawInputSlot = topLevelOperatorView.RawData super(CarvingGui, self).__init__(parentApplet, labelingSlots, topLevelOperatorView, drawerUiPath, rawInputSlot) self.labelingDrawerUi.currentObjectLabel.setText("<not saved yet>") # Init special base class members self.minLabelNumber = 2 self.maxLabelNumber = 2 mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo #set up keyboard shortcuts mgr.register( "3", ActionInfo( "Carving", "Run interactive segmentation", "Run interactive segmentation", self.labelingDrawerUi.segment.click, self.labelingDrawerUi.segment, self.labelingDrawerUi.segment ) ) try: self.render = True self._shownObjects3D = {} self._renderMgr = RenderingManager( self.editor.view3d ) except: self.render = False # Segmentation is toggled on by default in _after_init, below. # (We can't enable it until the layers are all present.) self._showSegmentationIn3D = False self._segmentation_3d_label = None self.labelingDrawerUi.segment.clicked.connect(self.onSegmentButton) self.labelingDrawerUi.segment.setEnabled(True) self.topLevelOperatorView.Segmentation.notifyDirty( bind( self._update_rendering ) ) self.topLevelOperatorView.HasSegmentation.notifyValueChanged( bind( self._updateGui ) ) ## uncertainty self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) def onUncertaintyFGButton(): logger.debug( "uncertFG button clicked" ) pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=2) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyFG.clicked.connect(onUncertaintyFGButton) def onUncertaintyBGButton(): logger.debug( "uncertBG button clicked" ) pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=1) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyBG.clicked.connect(onUncertaintyBGButton) def onUncertaintyCombo(value): if value == 0: value = "none" self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) self._showUncertaintyLayer = False else: if value == 1: value = "localMargin" elif value == 2: value = "exchangeCount" elif value == 3: value = "gabow" else: raise RuntimeError("unhandled case '%r'" % value) self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(True) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(True) self._showUncertaintyLayer = True logger.debug( "uncertainty changed to %r" % value ) self.topLevelOperatorView.UncertaintyType.setValue(value) self.updateAllLayers() #make sure that an added/deleted uncertainty layer is recognized self.labelingDrawerUi.uncertaintyCombo.currentIndexChanged.connect(onUncertaintyCombo) ## background priority def onBackgroundPrioritySpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.BackgroundPriority.setValue(value) self.labelingDrawerUi.backgroundPrioritySpin.valueChanged.connect(onBackgroundPrioritySpin) def onBackgroundPriorityDirty(slot, roi): oldValue = self.labelingDrawerUi.backgroundPrioritySpin.value() newValue = self.topLevelOperatorView.BackgroundPriority.value if newValue != oldValue: self.labelingDrawerUi.backgroundPrioritySpin.setValue(newValue) self.topLevelOperatorView.BackgroundPriority.notifyDirty(onBackgroundPriorityDirty) ## bias def onNoBiasBelowDirty(slot, roi): oldValue = self.labelingDrawerUi.noBiasBelowSpin.value() newValue = self.topLevelOperatorView.NoBiasBelow.value if newValue != oldValue: self.labelingDrawerUi.noBiasBelowSpin.setValue(newValue) self.topLevelOperatorView.NoBiasBelow.notifyDirty(onNoBiasBelowDirty) def onNoBiasBelowSpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.NoBiasBelow.setValue(value) self.labelingDrawerUi.noBiasBelowSpin.valueChanged.connect(onNoBiasBelowSpin) ## save self.labelingDrawerUi.save.clicked.connect(self.onSaveButton) ## clear self.labelingDrawerUi.clear.clicked.connect(self._onClearAction) ## object names self.labelingDrawerUi.namesButton.clicked.connect(self.onShowObjectNames) if hasattr( self.labelingDrawerUi, 'exportAllMeshesButton' ): self.labelingDrawerUi.exportAllMeshesButton.clicked.connect(self._exportAllObjectMeshes) def labelBackground(): self.selectLabel(0) def labelObject(): self.selectLabel(1) self._labelControlUi.labelListModel.allowRemove(False) bgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 0) mgr.register( "1", ActionInfo( "Carving", "Select background label", "Select background label", labelBackground, self.viewerControlWidget(), bgToolTipObject ) ) fgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 1) mgr.register( "2", ActionInfo( "Carving", "Select object label", "Select object label", labelObject, self.viewerControlWidget(), fgToolTipObject ) ) def layerIndexForName(name): return self.layerstack.findMatchingIndex(lambda x: x.name == name) def addLayerToggleShortcut(layername, shortcut): def toggle(): row = layerIndexForName(layername) self.layerstack.selectRow(row) layer = self.layerstack[row] layer.visible = not layer.visible self.viewerControlWidget().layerWidget.setFocus() mgr.register(shortcut, ActionInfo( "Carving", "Toggle layer %s" % layername, "Toggle layer %s" % layername, toggle, self.viewerControlWidget(), None ) ) #TODO addLayerToggleShortcut("Completed segments (unicolor)", "d") addLayerToggleShortcut("Segmentation", "s") addLayerToggleShortcut("Input Data", "r") ''' def updateLayerTimings(): s = "Layer timings:\n" for l in self.layerstack: s += "%s: %f sec.\n" % (l.name, l.averageTimePerTile) self.labelingDrawerUi.layerTimings.setText(s) t = QTimer(self) t.setInterval(1*1000) # 10 seconds t.start() t.timeout.connect(updateLayerTimings) ''' def makeColortable(): self._doneSegmentationColortable = [QColor(0,0,0,0).rgba()] for i in range(254): r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) # ensure colors have sufficient distance to pure red and pure green while (255 - r)+g+b<128 or r+(255-g)+b<128: r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) self._doneSegmentationColortable.append(QColor(r,g,b).rgba()) self._doneSegmentationColortable.append(QColor(0,255,0).rgba()) makeColortable() def onRandomizeColors(): if self._doneSegmentationLayer is not None: logger.debug( "randomizing colors ..." ) makeColortable() self._doneSegmentationLayer.colorTable = self._doneSegmentationColortable if self.render and self._renderMgr.ready: self._update_rendering() #self.labelingDrawerUi.randomizeColors.clicked.connect(onRandomizeColors) self._updateGui()
def __initShortcuts(self): mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcutGroupName = "Labeling" if hasattr(self.labelingDrawerUi, "AddLabelButton"): mgr.register("a", ActionInfo( shortcutGroupName, "New Label", "Add New Label Class", self.labelingDrawerUi.AddLabelButton.click, self.labelingDrawerUi.AddLabelButton, self.labelingDrawerUi.AddLabelButton ) ) mgr.register( "n", ActionInfo( shortcutGroupName, "Navigation Cursor", "Navigation Cursor", self.labelingDrawerUi.arrowToolButton.click, self.labelingDrawerUi.arrowToolButton, self.labelingDrawerUi.arrowToolButton ) ) mgr.register( "b", ActionInfo( shortcutGroupName, "Brush Cursor", "Brush Cursor", self.labelingDrawerUi.paintToolButton.click, self.labelingDrawerUi.paintToolButton, self.labelingDrawerUi.paintToolButton ) ) mgr.register( "e", ActionInfo( shortcutGroupName, "Eraser Cursor", "Eraser Cursor", self.labelingDrawerUi.eraserToolButton.click, self.labelingDrawerUi.eraserToolButton, self.labelingDrawerUi.eraserToolButton ) ) if hasattr(self.labelingDrawerUi, "thresToolButton"): mgr.register( "t", ActionInfo( shortcutGroupName, "Window Leveling", "<p>Window Leveling can be used to adjust the data range used for visualization. Pressing the left mouse button while moving the mouse back and forth changes the window width (data range). Moving the mouse in the left-right plane changes the window mean. Pressing the right mouse button leads to an automatic range adjustment.", self.labelingDrawerUi.thresToolButton.click, self.labelingDrawerUi.thresToolButton, self.labelingDrawerUi.thresToolButton ) ) self._labelShortcuts = []
def __init__(self, parentApplet, topLevelOperatorView, drawerUiPath=None ): self.topLevelOperatorView = topLevelOperatorView #members self._doneSegmentationLayer = None self._showSegmentationIn3D = False self._showUncertaintyLayer = False #end: members labelingSlots = LabelingGui.LabelingSlots() labelingSlots.labelInput = topLevelOperatorView.WriteSeeds labelingSlots.labelOutput = topLevelOperatorView.opLabelArray.Output labelingSlots.labelEraserValue = topLevelOperatorView.opLabelArray.EraserLabelValue labelingSlots.labelNames = topLevelOperatorView.LabelNames labelingSlots.labelDelete = topLevelOperatorView.opLabelArray.DeleteLabel labelingSlots.maxLabelValue = topLevelOperatorView.opLabelArray.MaxLabelValue labelingSlots.labelsAllowed = topLevelOperatorView.LabelsAllowed # We provide our own UI file (which adds an extra control for interactive mode) directory = os.path.split(__file__)[0] if drawerUiPath is None: drawerUiPath = os.path.join(directory, 'carvingDrawer.ui') self.dialogdirCOM = os.path.join(directory, 'carvingObjectManagement.ui') self.dialogdirSAD = os.path.join(directory, 'saveAsDialog.ui') rawInputSlot = topLevelOperatorView.RawData super(CarvingGui, self).__init__(parentApplet, labelingSlots, topLevelOperatorView, drawerUiPath, rawInputSlot) self.labelingDrawerUi.currentObjectLabel.setText("<not saved yet>") # Init special base class members self.minLabelNumber = 2 self.maxLabelNumber = 2 mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo #set up keyboard shortcuts mgr.register( "3", ActionInfo( "Carving", "Run interactive segmentation", "Run interactive segmentation", self.labelingDrawerUi.segment.click, self.labelingDrawerUi.segment, self.labelingDrawerUi.segment ) ) try: self.render = True self._shownObjects3D = {} self._renderMgr = RenderingManager( renderer=self.editor.view3d.qvtk.renderer, qvtk=self.editor.view3d.qvtk) except: self.render = False # Segmentation is toggled on by default in _after_init, below. # (We can't enable it until the layers are all present.) self._showSegmentationIn3D = False self._segmentation_3d_label = None self.labelingDrawerUi.segment.clicked.connect(self.onSegmentButton) self.labelingDrawerUi.segment.setEnabled(True) self.topLevelOperatorView.Segmentation.notifyDirty( bind( self._update_rendering ) ) self.topLevelOperatorView.HasSegmentation.notifyValueChanged( bind( self._updateGui ) ) ## uncertainty self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) def onUncertaintyFGButton(): logger.debug( "uncertFG button clicked" ) pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=2) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyFG.clicked.connect(onUncertaintyFGButton) def onUncertaintyBGButton(): logger.debug( "uncertBG button clicked" ) pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=1) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyBG.clicked.connect(onUncertaintyBGButton) def onUncertaintyCombo(value): if value == 0: value = "none" self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) self._showUncertaintyLayer = False else: if value == 1: value = "localMargin" elif value == 2: value = "exchangeCount" elif value == 3: value = "gabow" else: raise RuntimeError("unhandled case '%r'" % value) self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(True) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(True) self._showUncertaintyLayer = True logger.debug( "uncertainty changed to %r" % value ) self.topLevelOperatorView.UncertaintyType.setValue(value) self.updateAllLayers() #make sure that an added/deleted uncertainty layer is recognized self.labelingDrawerUi.uncertaintyCombo.currentIndexChanged.connect(onUncertaintyCombo) ## background priority def onBackgroundPrioritySpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.BackgroundPriority.setValue(value) self.labelingDrawerUi.backgroundPrioritySpin.valueChanged.connect(onBackgroundPrioritySpin) def onBackgroundPriorityDirty(slot, roi): oldValue = self.labelingDrawerUi.backgroundPrioritySpin.value() newValue = self.topLevelOperatorView.BackgroundPriority.value if newValue != oldValue: self.labelingDrawerUi.backgroundPrioritySpin.setValue(newValue) self.topLevelOperatorView.BackgroundPriority.notifyDirty(onBackgroundPriorityDirty) ## bias def onNoBiasBelowDirty(slot, roi): oldValue = self.labelingDrawerUi.noBiasBelowSpin.value() newValue = self.topLevelOperatorView.NoBiasBelow.value if newValue != oldValue: self.labelingDrawerUi.noBiasBelowSpin.setValue(newValue) self.topLevelOperatorView.NoBiasBelow.notifyDirty(onNoBiasBelowDirty) def onNoBiasBelowSpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.NoBiasBelow.setValue(value) self.labelingDrawerUi.noBiasBelowSpin.valueChanged.connect(onNoBiasBelowSpin) ## save self.labelingDrawerUi.save.clicked.connect(self.onSaveButton) ## clear self.labelingDrawerUi.clear.clicked.connect(self.topLevelOperatorView.clearCurrentLabeling) ## object names self.labelingDrawerUi.namesButton.clicked.connect(self.onShowObjectNames) def labelBackground(): self.selectLabel(0) def labelObject(): self.selectLabel(1) self._labelControlUi.labelListModel.allowRemove(False) bgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 0) mgr.register( "1", ActionInfo( "Carving", "Select background label", "Select background label", labelBackground, self.viewerControlWidget(), bgToolTipObject ) ) fgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 1) mgr.register( "2", ActionInfo( "Carving", "Select object label", "Select object label", labelObject, self.viewerControlWidget(), fgToolTipObject ) ) def layerIndexForName(name): return self.layerstack.findMatchingIndex(lambda x: x.name == name) def addLayerToggleShortcut(layername, shortcut): def toggle(): row = layerIndexForName(layername) self.layerstack.selectRow(row) layer = self.layerstack[row] layer.visible = not layer.visible self.viewerControlWidget().layerWidget.setFocus() mgr.register(shortcut, ActionInfo( "Carving", "Toggle layer %s" % layername, "Toggle layer %s" % layername, toggle, self.viewerControlWidget(), None ) ) #TODO addLayerToggleShortcut("Completed segments (unicolor)", "d") addLayerToggleShortcut("Segmentation", "s") addLayerToggleShortcut("Input Data", "r") ''' def updateLayerTimings(): s = "Layer timings:\n" for l in self.layerstack: s += "%s: %f sec.\n" % (l.name, l.averageTimePerTile) self.labelingDrawerUi.layerTimings.setText(s) t = QTimer(self) t.setInterval(1*1000) # 10 seconds t.start() t.timeout.connect(updateLayerTimings) ''' def makeColortable(): self._doneSegmentationColortable = [QColor(0,0,0,0).rgba()] for i in range(254): r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) # ensure colors have sufficient distance to pure red and pure green while (255 - r)+g+b<128 or r+(255-g)+b<128: r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) self._doneSegmentationColortable.append(QColor(r,g,b).rgba()) self._doneSegmentationColortable.append(QColor(0,255,0).rgba()) makeColortable() def onRandomizeColors(): if self._doneSegmentationLayer is not None: logger.debug( "randomizing colors ..." ) makeColortable() self._doneSegmentationLayer.colorTable = self._doneSegmentationColortable if self.render and self._renderMgr.ready: self._update_rendering() #self.labelingDrawerUi.randomizeColors.clicked.connect(onRandomizeColors) self._updateGui()
def createDrawerControls(self): op = self.topLevelOperatorView def configure_update_handlers(qt_signal, op_slot): qt_signal.connect(self.configure_operator_from_gui) cleanup_fn = op_slot.notifyDirty(self.configure_gui_from_operator, defer=True) self.__cleanup_fns.append(cleanup_fn) # Controls feature_selection_button = QPushButton( text="Select Features", icon=QIcon(ilastikIcons.AddSel), toolTip= "Select edge/superpixel features to use for classification.", clicked=self._open_feature_selection_dlg, ) self.train_from_gt_button = QPushButton( text="Auto-label", icon=QIcon(ilastikIcons.Segment), toolTip= "Automatically label all edges according to your pre-loaded groundtruth volume.", clicked=self._handle_label_from_gt_clicked, ) self.clear_labels_button = QPushButton( text="Clear Labels", icon=QIcon(ilastikIcons.Clear), toolTip="Remove all edge labels. (Start over on this image.)", clicked=self._handle_clear_labels_clicked, ) self.live_update_button = QPushButton( text="Live Predict", checkable=True, icon=QIcon(ilastikIcons.Play), toolTip="Update the edge classifier predictions", clicked=self._handle_live_update_clicked, enabled=False, ) configure_update_handlers(self.live_update_button.toggled, op.FreezeClassifier) configure_update_handlers(self.train_from_gt_button.toggled, op.TrainRandomForest) cleanup_fn = op.EdgeLabelsDict.notifyDirty( self.enable_live_update_on_edges_available) self.__cleanup_fns.append(cleanup_fn) # call once when instantiating with a saved project to make the live update button available # if there are annotations loaded from file. self.enable_live_update_on_edges_available() # Layout label_layout = QHBoxLayout() label_layout.addWidget(self.clear_labels_button) label_layout.addWidget(self.train_from_gt_button) label_layout.setSpacing(1) layout = QVBoxLayout() layout.addWidget(feature_selection_button) layout.setSpacing(1) layout.addLayout(label_layout) layout.addWidget(self.live_update_button) layout.addSpacerItem( QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)) # Finally, the whole drawer widget drawer = QWidget(parent=self) drawer.setLayout(layout) # Widget Shortcuts mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcut_group = "Edge Training" mgr.register( "l", ActionInfo( shortcut_group, "Live Predict", "Toggle live edge classifier update mode", self.live_update_button.toggle, self.live_update_button, self.live_update_button, ), ) return drawer
def _initShortcuts(self): # TODO: Fix this dependency on ImageView/HUD internals mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo mgr.register( "x", ActionInfo("Navigation", "Minimize/Maximize x-Window", "Minimize/Maximize x-Window", self.quadview.switchXMinMax, self.editor.imageViews[0].hud.buttons['maximize'], self.editor.imageViews[0].hud.buttons['maximize'])) mgr.register( "y", ActionInfo("Navigation", "Minimize/Maximize y-Window", "Minimize/Maximize y-Window", self.quadview.switchYMinMax, self.editor.imageViews[1].hud.buttons['maximize'], self.editor.imageViews[1].hud.buttons['maximize'])) mgr.register( "z", ActionInfo("Navigation", "Minimize/Maximize z-Window", "Minimize/Maximize z-Window", self.quadview.switchZMinMax, self.editor.imageViews[2].hud.buttons['maximize'], self.editor.imageViews[2].hud.buttons['maximize'])) for i, v in enumerate(self.editor.imageViews): mgr.register( "+", ActionInfo("Navigation", "Zoom in", "Zoom in", v.zoomIn, v, None)) mgr.register( "-", ActionInfo("Navigation", "Zoom out", "Zoom out", v.zoomOut, v, None)) mgr.register( "c", ActionInfo("Navigation", "Center image", "Center image", v.centerImage, v, None)) mgr.register( "h", ActionInfo("Navigation", "Toggle hud", "Toggle hud", v.toggleHud, v, None)) # FIXME: The nextChannel/previousChannel functions don't work right now. #self._shortcutHelper("q", "Navigation", "Switch to next channel", v, self.editor.nextChannel, Qt.WidgetShortcut)) #self._shortcutHelper("a", "Navigation", "Switch to previous channel", v, self.editor.previousChannel, Qt.WidgetShortcut)) def sliceDelta(axis, delta): newPos = copy.copy(self.editor.posModel.slicingPos) newPos[axis] += delta newPos[axis] = max(0, newPos[axis]) newPos[axis] = min(self.editor.posModel.shape[axis] - 1, newPos[axis]) self.editor.posModel.slicingPos = newPos def jumpToFirstSlice(axis): newPos = copy.copy(self.editor.posModel.slicingPos) newPos[axis] = 0 self.editor.posModel.slicingPos = newPos def jumpToLastSlice(axis): newPos = copy.copy(self.editor.posModel.slicingPos) newPos[axis] = self.editor.posModel.shape[axis] - 1 self.editor.posModel.slicingPos = newPos # TODO: Fix this dependency on ImageView/HUD internals mgr.register( "Ctrl+Up", ActionInfo("Navigation", "Slice up", "Slice up", partial(sliceDelta, i, 1), v, v.hud.buttons['slice'].upLabel)) mgr.register( "Ctrl+Down", ActionInfo("Navigation", "Slice up", "Slice up", partial(sliceDelta, i, -1), v, v.hud.buttons['slice'].downLabel)) # self._shortcutHelper("p", "Navigation", "Slice up (alternate shortcut)", v, partial(sliceDelta, i, 1), Qt.WidgetShortcut) # self._shortcutHelper("o", "Navigation", "Slice down (alternate shortcut)", v, partial(sliceDelta, i, -1), Qt.WidgetShortcut) mgr.register( "Ctrl+Shift+Up", ActionInfo("Navigation", "10 slices up", "10 slices up", partial(sliceDelta, i, 10), v, None)) mgr.register( "Ctrl+Shift+Down", ActionInfo("Navigation", "10 slices down", "10 slices down", partial(sliceDelta, i, -10), v, None)) mgr.register( "Shift+Up", ActionInfo("Navigation", "Jump to first slice", "Jump to first slice", partial(jumpToFirstSlice, i), v, None)) mgr.register( "Shift+Down", ActionInfo("Navigation", "Jump to last slice", "Jump to last slice", partial(jumpToLastSlice, i), v, None))
def _initShortcuts(self): # TODO: Fix this dependency on ImageView/HUD internals mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo mgr.register( "x", ActionInfo( "Navigation", "Minimize/Maximize x-Window", "Minimize/Maximize x-Window", self.quadview.switchXMinMax, self.editor.imageViews[0].hud.buttons["maximize"], self.editor.imageViews[0].hud.buttons["maximize"], ), ) mgr.register( "y", ActionInfo( "Navigation", "Minimize/Maximize y-Window", "Minimize/Maximize y-Window", self.quadview.switchYMinMax, self.editor.imageViews[1].hud.buttons["maximize"], self.editor.imageViews[1].hud.buttons["maximize"], ), ) mgr.register( "z", ActionInfo( "Navigation", "Minimize/Maximize z-Window", "Minimize/Maximize z-Window", self.quadview.switchZMinMax, self.editor.imageViews[2].hud.buttons["maximize"], self.editor.imageViews[2].hud.buttons["maximize"], ), ) for i, v in enumerate(self.editor.imageViews): mgr.register("+", ActionInfo("Navigation", "Zoom in", "Zoom in", v.zoomIn, v, None)) mgr.register("-", ActionInfo("Navigation", "Zoom out", "Zoom out", v.zoomOut, v, None)) mgr.register("c", ActionInfo("Navigation", "Center image", "Center image", v.centerImage, v, None)) mgr.register("h", ActionInfo("Navigation", "Toggle hud", "Toggle hud", v.toggleHud, v, None)) # FIXME: The nextChannel/previousChannel functions don't work right now. # self._shortcutHelper("q", "Navigation", "Switch to next channel", v, self.editor.nextChannel, Qt.WidgetShortcut)) # self._shortcutHelper("a", "Navigation", "Switch to previous channel", v, self.editor.previousChannel, Qt.WidgetShortcut)) def sliceDelta(axis, delta): newPos = copy.copy(self.editor.posModel.slicingPos) newPos[axis] += delta newPos[axis] = max(0, newPos[axis]) newPos[axis] = min(self.editor.posModel.shape[axis] - 1, newPos[axis]) self.editor.posModel.slicingPos = newPos def jumpToFirstSlice(axis): newPos = copy.copy(self.editor.posModel.slicingPos) newPos[axis] = 0 self.editor.posModel.slicingPos = newPos def jumpToLastSlice(axis): newPos = copy.copy(self.editor.posModel.slicingPos) newPos[axis] = self.editor.posModel.shape[axis] - 1 self.editor.posModel.slicingPos = newPos # TODO: Fix this dependency on ImageView/HUD internals mgr.register( "Ctrl+Up", ActionInfo( "Navigation", "Slice up", "Slice up", partial(sliceDelta, i, 1), v, v.hud.buttons["slice"].upLabel ), ) mgr.register( "Ctrl+Down", ActionInfo( "Navigation", "Slice up", "Slice up", partial(sliceDelta, i, -1), v, v.hud.buttons["slice"].downLabel, ), ) # self._shortcutHelper("p", "Navigation", "Slice up (alternate shortcut)", v, partial(sliceDelta, i, 1), Qt.WidgetShortcut) # self._shortcutHelper("o", "Navigation", "Slice down (alternate shortcut)", v, partial(sliceDelta, i, -1), Qt.WidgetShortcut) mgr.register( "Ctrl+Shift+Up", ActionInfo("Navigation", "10 slices up", "10 slices up", partial(sliceDelta, i, 10), v, None), ) mgr.register( "Ctrl+Shift+Down", ActionInfo("Navigation", "10 slices down", "10 slices down", partial(sliceDelta, i, -10), v, None), ) mgr.register( "Shift+Up", ActionInfo( "Navigation", "Jump to first slice", "Jump to first slice", partial(jumpToFirstSlice, i), v, None ), ) mgr.register( "Shift+Down", ActionInfo( "Navigation", "Jump to last slice", "Jump to last slice", partial(jumpToLastSlice, i), v, None ), )
def __init__(self, parentApplet, topLevelOperatorView, drawerUiPath=None ): self.topLevelOperatorView = topLevelOperatorView #members self._doneSegmentationLayer = None self._showSegmentationIn3D = False #self._showUncertaintyLayer = False #end: members labelingSlots = LabelingGui.LabelingSlots() labelingSlots.labelInput = topLevelOperatorView.WriteSeeds labelingSlots.labelOutput = topLevelOperatorView.opLabelArray.Output labelingSlots.labelEraserValue = topLevelOperatorView.opLabelArray.EraserLabelValue labelingSlots.labelNames = topLevelOperatorView.LabelNames labelingSlots.labelDelete = topLevelOperatorView.opLabelArray.DeleteLabel labelingSlots.maxLabelValue = topLevelOperatorView.opLabelArray.MaxLabelValue # We provide our own UI file (which adds an extra control for interactive mode) directory = os.path.split(__file__)[0] if drawerUiPath is None: drawerUiPath = os.path.join(directory, 'carvingDrawer.ui') self.dialogdirCOM = os.path.join(directory, 'carvingObjectManagement.ui') self.dialogdirSAD = os.path.join(directory, 'saveAsDialog.ui') super(CarvingGui, self).__init__(parentApplet, labelingSlots, topLevelOperatorView, drawerUiPath) self.labelingDrawerUi.currentObjectLabel.setText("<not saved yet>") # Init special base class members self.minLabelNumber = 2 self.maxLabelNumber = 2 mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo #set up keyboard shortcuts mgr.register( "3", ActionInfo( "Carving", "Run interactive segmentation", "Run interactive segmentation", self.labelingDrawerUi.segment.click, self.labelingDrawerUi.segment, self.labelingDrawerUi.segment ) ) # Disable 3D view by default self.render = False tagged_shape = defaultdict(lambda: 1) tagged_shape.update( topLevelOperatorView.InputData.meta.getTaggedShape() ) is_3d = (tagged_shape['x'] > 1 and tagged_shape['y'] > 1 and tagged_shape['z'] > 1) if is_3d: try: self._renderMgr = RenderingManager( self.editor.view3d ) self._shownObjects3D = {} self.render = True except: self.render = False # Segmentation is toggled on by default in _after_init, below. # (We can't enable it until the layers are all present.) self._showSegmentationIn3D = False self._segmentation_3d_label = None self.labelingDrawerUi.segment.clicked.connect(self.onSegmentButton) self.labelingDrawerUi.segment.setEnabled(True) self.topLevelOperatorView.Segmentation.notifyDirty( bind( self._update_rendering ) ) self.topLevelOperatorView.HasSegmentation.notifyValueChanged( bind( self._updateGui ) ) ## uncertainty #self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) #self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) #def onUncertaintyFGButton(): # logger.debug( "uncertFG button clicked" ) # pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=2) # self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) #self.labelingDrawerUi.pushButtonUncertaintyFG.clicked.connect(onUncertaintyFGButton) #def onUncertaintyBGButton(): # logger.debug( "uncertBG button clicked" ) # pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=1) # self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) #self.labelingDrawerUi.pushButtonUncertaintyBG.clicked.connect(onUncertaintyBGButton) #def onUncertaintyCombo(value): # if value == 0: # value = "none" # self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) # self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) # self._showUncertaintyLayer = False # else: # if value == 1: # value = "localMargin" # elif value == 2: # value = "exchangeCount" # elif value == 3: # value = "gabow" # else: # raise RuntimeError("unhandled case '%r'" % value) # self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(True) # self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(True) # self._showUncertaintyLayer = True # logger.debug( "uncertainty changed to %r" % value ) # self.topLevelOperatorView.UncertaintyType.setValue(value) # self.updateAllLayers() #make sure that an added/deleted uncertainty layer is recognized #self.labelingDrawerUi.uncertaintyCombo.currentIndexChanged.connect(onUncertaintyCombo) ## background priority def onBackgroundPrioritySpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.BackgroundPriority.setValue(value) self.labelingDrawerUi.backgroundPrioritySpin.valueChanged.connect(onBackgroundPrioritySpin) def onBackgroundPriorityDirty(slot, roi): oldValue = self.labelingDrawerUi.backgroundPrioritySpin.value() newValue = self.topLevelOperatorView.BackgroundPriority.value if newValue != oldValue: self.labelingDrawerUi.backgroundPrioritySpin.setValue(newValue) self.topLevelOperatorView.BackgroundPriority.notifyDirty(onBackgroundPriorityDirty) ## bias def onNoBiasBelowDirty(slot, roi): oldValue = self.labelingDrawerUi.noBiasBelowSpin.value() newValue = self.topLevelOperatorView.NoBiasBelow.value if newValue != oldValue: self.labelingDrawerUi.noBiasBelowSpin.setValue(newValue) self.topLevelOperatorView.NoBiasBelow.notifyDirty(onNoBiasBelowDirty) def onNoBiasBelowSpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.NoBiasBelow.setValue(value) self.labelingDrawerUi.noBiasBelowSpin.valueChanged.connect(onNoBiasBelowSpin) ## save self.labelingDrawerUi.save.clicked.connect(self.onSaveButton) ## clear self.labelingDrawerUi.clear.clicked.connect(self._onClearAction) ## object names self.labelingDrawerUi.namesButton.clicked.connect(self.onShowObjectNames) if hasattr( self.labelingDrawerUi, 'exportAllMeshesButton' ): self.labelingDrawerUi.exportAllMeshesButton.clicked.connect(self._exportAllObjectMeshes) self.labelingDrawerUi.labelListView.allowDelete = False self._labelControlUi.labelListModel.allowRemove(False) def layerIndexForName(name): return self.layerstack.findMatchingIndex(lambda x: x.name == name) def addLayerToggleShortcut(layername, shortcut): def toggle(): row = layerIndexForName(layername) self.layerstack.selectRow(row) layer = self.layerstack[row] layer.visible = not layer.visible self.viewerControlWidget().layerWidget.setFocus() mgr.register(shortcut, ActionInfo( "Carving", "Toggle layer %s" % layername, "Toggle layer %s" % layername, toggle, self.viewerControlWidget(), None ) ) #TODO addLayerToggleShortcut("Completed segments (unicolor)", "d") addLayerToggleShortcut("Segmentation", "s") addLayerToggleShortcut("Input Data", "r") def makeColortable(): self._doneSegmentationColortable = [QColor(0,0,0,0).rgba()] for i in range(254): r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) # ensure colors have sufficient distance to pure red and pure green while (255 - r)+g+b<128 or r+(255-g)+b<128: r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) self._doneSegmentationColortable.append(QColor(r,g,b).rgba()) self._doneSegmentationColortable.append(QColor(0,255,0).rgba()) makeColortable() def onRandomizeColors(): if self._doneSegmentationLayer is not None: logger.debug( "randomizing colors ..." ) makeColortable() self._doneSegmentationLayer.colorTable = self._doneSegmentationColortable if self.render and self._renderMgr.ready: self._update_rendering() #self.labelingDrawerUi.randomizeColors.clicked.connect(onRandomizeColors) self._updateGui()
def __init__(self, topLevelOperatorView, drawerUiPath=None ): self.topLevelOperatorView = topLevelOperatorView labelingSlots = LabelingGui.LabelingSlots() labelingSlots.labelInput = topLevelOperatorView.WriteSeeds labelingSlots.labelOutput = topLevelOperatorView.opLabelArray.Output labelingSlots.labelEraserValue = topLevelOperatorView.opLabelArray.EraserLabelValue labelingSlots.labelDelete = topLevelOperatorView.opLabelArray.DeleteLabel labelingSlots.maxLabelValue = topLevelOperatorView.opLabelArray.MaxLabelValue labelingSlots.labelsAllowed = topLevelOperatorView.LabelsAllowed # We provide our own UI file (which adds an extra control for interactive mode) directory = os.path.split(__file__)[0] if drawerUiPath is None: drawerUiPath = os.path.join(directory, 'carvingDrawer.ui') self.dialogdirCOM = os.path.join(directory, 'carvingObjectManagement.ui') self.dialogdirSAD = os.path.join(directory, 'saveAsDialog.ui') rawInputSlot = topLevelOperatorView.RawData super(CarvingGui, self).__init__(labelingSlots, topLevelOperatorView, drawerUiPath, rawInputSlot) # Init special base class members self.minLabelNumber = 2 self.maxLabelNumber = 2 mgr = ShortcutManager() #set up keyboard shortcuts segmentShortcut = QShortcut(QKeySequence("3"), self, member=self.labelingDrawerUi.segment.click, ambiguousMember=self.labelingDrawerUi.segment.click) mgr.register("Carving", "Run interactive segmentation", segmentShortcut, self.labelingDrawerUi.segment) self._doneSegmentationLayer = None self._showSegmentationIn3D = False #volume rendering try: self.render = True self._shownObjects3D = {} self._renderMgr = RenderingManager( renderer=self.editor.view3d.qvtk.renderer, qvtk=self.editor.view3d.qvtk) except: self.render = False self.labelingDrawerUi.segment.clicked.connect(self.onSegmentButton) self.labelingDrawerUi.segment.setEnabled(True) self.topLevelOperatorView.Segmentation.notifyDirty( bind( self._update_rendering ) ) def onUncertaintyFGButton(): print "uncertFG button clicked" pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=2) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyFG.clicked.connect(onUncertaintyFGButton) self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(True) def onUncertaintyBGButton(): print "uncertBG button clicked" pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=1) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyBG.clicked.connect(onUncertaintyBGButton) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(True) def onBackgroundPrioritySpin(value): print "background priority changed to %f" % value self.topLevelOperatorView.BackgroundPriority.setValue(value) self.labelingDrawerUi.backgroundPrioritySpin.valueChanged.connect(onBackgroundPrioritySpin) def onuncertaintyCombo(value): if value == 0: value = "none" if value == 1: value = "localMargin" if value == 2: value = "exchangeCount" if value == 3: value = "gabow" print "uncertainty changed to %r" % value self.topLevelOperatorView.UncertaintyType.setValue(value) self.labelingDrawerUi.uncertaintyCombo.currentIndexChanged.connect(onuncertaintyCombo) def onBackgroundPriorityDirty(slot, roi): oldValue = self.labelingDrawerUi.backgroundPrioritySpin.value() newValue = self.topLevelOperatorView.BackgroundPriority.value if newValue != oldValue: self.labelingDrawerUi.backgroundPrioritySpin.setValue(newValue) self.topLevelOperatorView.BackgroundPriority.notifyDirty(onBackgroundPriorityDirty) def onNoBiasBelowDirty(slot, roi): oldValue = self.labelingDrawerUi.noBiasBelowSpin.value() newValue = self.topLevelOperatorView.NoBiasBelow.value if newValue != oldValue: self.labelingDrawerUi.noBiasBelowSpin.setValue(newValue) self.topLevelOperatorView.NoBiasBelow.notifyDirty(onNoBiasBelowDirty) def onNoBiasBelowSpin(value): print "background priority changed to %f" % value self.topLevelOperatorView.NoBiasBelow.setValue(value) self.labelingDrawerUi.noBiasBelowSpin.valueChanged.connect(onNoBiasBelowSpin) self.labelingDrawerUi.saveAs.clicked.connect(self.onSaveAsButton) self.labelingDrawerUi.save.clicked.connect(self.onSaveButton) self.labelingDrawerUi.save.setEnabled(False) #initially, the user need to use "Save As" self.labelingDrawerUi.clear.clicked.connect(self.topLevelOperatorView.clearCurrentLabeling) self.labelingDrawerUi.clear.setEnabled(True) self.labelingDrawerUi.namesButton.clicked.connect(self.onShowObjectNames) def labelBackground(): self.selectLabel(0) def labelObject(): self.selectLabel(1) self._labelControlUi.labelListModel.allowRemove(False) bg = QShortcut(QKeySequence("1"), self, member=labelBackground, ambiguousMember=labelBackground) bgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 0) mgr.register("Carving", "Select background label", bg, bgToolTipObject) fg = QShortcut(QKeySequence("2"), self, member=labelObject, ambiguousMember=labelObject) fgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 1) mgr.register("Carving", "Select object label", fg, fgToolTipObject) def layerIndexForName(name): return self.layerstack.findMatchingIndex(lambda x: x.name == name) def addLayerToggleShortcut(layername, shortcut): def toggle(): row = layerIndexForName(layername) self.layerstack.selectRow(row) layer = self.layerstack[row] layer.visible = not layer.visible self.viewerControlWidget().layerWidget.setFocus() shortcut = QShortcut(QKeySequence(shortcut), self, member=toggle, ambiguousMember=toggle) mgr.register("Carving", "Toggle layer %s" % layername, shortcut) addLayerToggleShortcut("done", "d") addLayerToggleShortcut("segmentation", "s") addLayerToggleShortcut("raw", "r") addLayerToggleShortcut("pmap", "v") addLayerToggleShortcut("hints","t") ''' def updateLayerTimings(): s = "Layer timings:\n" for l in self.layerstack: s += "%s: %f sec.\n" % (l.name, l.averageTimePerTile) self.labelingDrawerUi.layerTimings.setText(s) t = QTimer(self) t.setInterval(1*1000) # 10 seconds t.start() t.timeout.connect(updateLayerTimings) ''' def makeColortable(): self._doneSegmentationColortable = [QColor(0,0,0,0).rgba()] for i in range(254): r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) self._doneSegmentationColortable.append(QColor(r,g,b).rgba()) self._doneSegmentationColortable[1:17] = colortables.default16 self._doneSegmentationColortable.append(QColor(0,255,0).rgba()) makeColortable() self._doneSegmentationLayer = None def onRandomizeColors(): if self._doneSegmentationLayer is not None: print "randomizing colors ..." makeColortable() self._doneSegmentationLayer.colorTable = self._doneSegmentationColortable if self.render and self._renderMgr.ready: self._update_rendering()
def __init__(self, labelingSlots, topLevelOperatorView, drawerUiPath=None, rawInputSlot=None ): self.topLevelOperatorView = topLevelOperatorView # We provide our own UI file (which adds an extra control for interactive mode) directory = os.path.split(__file__)[0] carvingDrawerUiPath = os.path.join(directory, 'carvingDrawer.ui') super(CarvingGui, self).__init__(labelingSlots, topLevelOperatorView, carvingDrawerUiPath, rawInputSlot) mgr = ShortcutManager() #set up keyboard shortcuts segmentShortcut = QShortcut(QKeySequence("3"), self, member=self.labelingDrawerUi.segment.click, ambiguousMember=self.labelingDrawerUi.segment.click) mgr.register("Carving", "Run interactive segmentation", segmentShortcut, self.labelingDrawerUi.segment) self._doneSegmentationLayer = None #volume rendering try: self.render = True self._shownObjects3D = {} self._renderMgr = RenderingManager( renderer=self.editor.view3d.qvtk.renderer, qvtk=self.editor.view3d.qvtk) except: self.render = False def onSegmentButton(): print "segment button clicked" self.topLevelOperatorView.opCarving.Trigger.setDirty(slice(None)) self.labelingDrawerUi.segment.clicked.connect(onSegmentButton) self.labelingDrawerUi.segment.setEnabled(True) def onUncertaintyFGButton(): print "uncertFG button clicked" pos = self.topLevelOperatorView.opCarving.getMaxUncertaintyPos(label=2) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyFG.clicked.connect(onUncertaintyFGButton) self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(True) def onUncertaintyBGButton(): print "uncertBG button clicked" pos = self.topLevelOperatorView.opCarving.getMaxUncertaintyPos(label=1) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyBG.clicked.connect(onUncertaintyBGButton) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(True) def onBackgroundPrioritySpin(value): print "background priority changed to %f" % value self.topLevelOperatorView.opCarving.BackgroundPriority.setValue(value) self.labelingDrawerUi.backgroundPrioritySpin.valueChanged.connect(onBackgroundPrioritySpin) def onuncertaintyCombo(value): if value == 0: value = "none" if value == 1: value = "localMargin" if value == 2: value = "exchangeCount" if value == 3: value = "gabow" print "uncertainty changed to %r" % value self.topLevelOperatorView.opCarving.UncertaintyType.setValue(value) self.labelingDrawerUi.uncertaintyCombo.currentIndexChanged.connect(onuncertaintyCombo) def onBackgroundPriorityDirty(slot, roi): oldValue = self.labelingDrawerUi.backgroundPrioritySpin.value() newValue = self.topLevelOperatorView.opCarving.BackgroundPriority.value if newValue != oldValue: self.labelingDrawerUi.backgroundPrioritySpin.setValue(newValue) self.topLevelOperatorView.opCarving.BackgroundPriority.notifyDirty(onBackgroundPriorityDirty) def onNoBiasBelowDirty(slot, roi): oldValue = self.labelingDrawerUi.noBiasBelowSpin.value() newValue = self.topLevelOperatorView.opCarving.NoBiasBelow.value if newValue != oldValue: self.labelingDrawerUi.noBiasBelowSpin.setValue(newValue) self.topLevelOperatorView.opCarving.NoBiasBelow.notifyDirty(onNoBiasBelowDirty) def onNoBiasBelowSpin(value): print "background priority changed to %f" % value self.topLevelOperatorView.opCarving.NoBiasBelow.setValue(value) self.labelingDrawerUi.noBiasBelowSpin.valueChanged.connect(onNoBiasBelowSpin) def onSaveAsButton(): print "save object as?" if self.topLevelOperatorView.opCarving.dataIsStorable(): name, ok = QInputDialog.getText(self, 'Save Object As', 'object name') name = str(name) if not ok: return objects = self.topLevelOperatorView.opCarving.AllObjectNames[:].wait() if name in objects: QMessageBox.critical(self, "Save Object As", "An object with name '%s' already exists.\nPlease choose a different name." % name) return self.topLevelOperatorView.opCarving.saveObjectAs(name) print "save object as %s" % name else: msgBox = QMessageBox(self) msgBox.setText("The data does not seem fit to be stored.") msgBox.setWindowTitle("Problem with Data") msgBox.setIcon(2) msgBox.exec_() print "object not saved due to faulty data." self.labelingDrawerUi.saveAs.clicked.connect(onSaveAsButton) def onSaveButton(): if self.topLevelOperatorView.opCarving.dataIsStorable(): if self.topLevelOperatorView.opCarving.hasCurrentObject(): name = self.topLevelOperatorView.opCarving.currentObjectName() self.topLevelOperatorView.opCarving.saveObjectAs( name ) else: onSaveAsButton() else: msgBox = QMessageBox(self) msgBox.setText("The data does no seem fit to be stored.") msgBox.setWindowTitle("Lousy Data") msgBox.setIcon(2) msgBox.exec_() print "object not saved due to faulty data." self.labelingDrawerUi.save.clicked.connect(onSaveButton) self.labelingDrawerUi.save.setEnabled(False) #initially, the user need to use "Save As" def onClearButton(): self.topLevelOperatorView.opCarving._clear() self.topLevelOperatorView.opCarving.clearCurrentLabeling() # trigger a re-computation self.topLevelOperatorView.opCarving.Trigger.setDirty(slice(None)) self.labelingDrawerUi.clear.clicked.connect(onClearButton) self.labelingDrawerUi.clear.setEnabled(True) def onShowObjectNames(): '''show object names and allow user to load/delete them''' dialog = uic.loadUi(os.path.join(directory, 'carvingObjectManagement.ui')) listOfItems = self.topLevelOperatorView.opCarving.AllObjectNames[:].wait() dialog.objectNames.addItems(sorted(listOfItems)) def loadSelection(): for name in dialog.objectNames.selectedItems(): objectname = str(name.text()) self.topLevelOperatorView.opCarving.loadObject(objectname) def deleteSelection(): for name in dialog.objectNames.selectedItems(): objectname = str(name.text()) self.topLevelOperatorView.opCarving.deleteObject(objectname) name.setHidden(True) dialog.loadButton.clicked.connect(loadSelection) dialog.deleteButton.clicked.connect(deleteSelection) dialog.cancelButton.clicked.connect(dialog.close) dialog.exec_() self.labelingDrawerUi.namesButton.clicked.connect(onShowObjectNames) def labelBackground(): self.selectLabel(0) def labelObject(): self.selectLabel(1) self._labelControlUi.labelListModel.allowRemove(False) bg = QShortcut(QKeySequence("1"), self, member=labelBackground, ambiguousMember=labelBackground) mgr.register("Carving", "Select background label", bg) fg = QShortcut(QKeySequence("2"), self, member=labelObject, ambiguousMember=labelObject) mgr.register("Carving", "Select object label", fg) def layerIndexForName(name): return self.layerstack.findMatchingIndex(lambda x: x.name == name) def addLayerToggleShortcut(layername, shortcut): def toggle(): row = layerIndexForName(layername) self.layerstack.selectRow(row) layer = self.layerstack[row] layer.visible = not layer.visible self.viewerControlWidget().layerWidget.setFocus() shortcut = QShortcut(QKeySequence(shortcut), self, member=toggle, ambiguousMember=toggle) mgr.register("Carving", "Toggle layer %s" % layername, shortcut) addLayerToggleShortcut("done", "d") addLayerToggleShortcut("segmentation", "s") addLayerToggleShortcut("raw", "r") addLayerToggleShortcut("pmap", "v") addLayerToggleShortcut("hints","h") ''' def updateLayerTimings(): s = "Layer timings:\n" for l in self.layerstack: s += "%s: %f sec.\n" % (l.name, l.averageTimePerTile) self.labelingDrawerUi.layerTimings.setText(s) t = QTimer(self) t.setInterval(1*1000) # 10 seconds t.start() t.timeout.connect(updateLayerTimings) ''' def makeColortable(): self._doneSegmentationColortable = [QColor(0,0,0,0).rgba()] for i in range(254): r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) self._doneSegmentationColortable.append(QColor(r,g,b).rgba()) self._doneSegmentationColortable[1:17] = colortables.default16 makeColortable() self._doneSegmentationLayer = None def onRandomizeColors(): if self._doneSegmentationLayer is not None: print "randomizing colors ..." makeColortable() self._doneSegmentationLayer.colorTable = self._doneSegmentationColortable if self.render and self._renderMgr.ready: self._update_rendering()
def _initViewMenu(self): self._viewMenu = QMenu("View", parent=self) self._viewMenu.setObjectName("view_menu") self._debugActions = [] # This action is saved as a member so it can be triggered from tests self._viewMenu.actionFitToScreen = self._viewMenu.addAction( "&Zoom to &fit") self._viewMenu.actionFitToScreen.triggered.connect(self._fitToScreen) def toggleHud(): hide = not self.editor.imageViews[0]._hud.isVisible() for v in self.editor.imageViews: v.setHudVisible(hide) # This action is saved as a member so it can be triggered from tests self._viewMenu.actionToggleAllHuds = self._viewMenu.addAction( "Toggle huds") self._viewMenu.actionToggleAllHuds.triggered.connect(toggleHud) def resetAllAxes(): for s in self.editor.imageScenes: s.resetAxes() self._viewMenu.addAction("Reset all axes").triggered.connect( resetAllAxes) def centerAllImages(): for v in self.editor.imageViews: v.centerImage() self._viewMenu.addAction("Center images").triggered.connect( centerAllImages) def toggleDebugPatches(show): self.editor.showDebugPatches = show actionShowTiling = self._viewMenu.addAction("Show Tiling") actionShowTiling.setCheckable(True) actionShowTiling.toggled.connect(toggleDebugPatches) qsd = QShortcut(QKeySequence("Ctrl+D"), self, member=actionShowTiling.toggle, context=Qt.WidgetShortcut) ShortcutManager().register("Navigation", "Show tiling", qsd) self._debugActions.append(actionShowTiling) def setCacheSize(cache_size): dlg = QDialog(self) layout = QHBoxLayout() layout.addWidget(QLabel("Cached Slices Per View:")) cache_size = [self.editor.cacheSize] def parseCacheSize(strSize): # TODO: Use a QValidator to make sure the user always gives a number try: cache_size[0] = int(strSize) except: pass edit = QLineEdit(str(cache_size[0]), parent=dlg) edit.textChanged.connect(parseCacheSize) layout.addWidget(edit) okButton = QPushButton("OK", parent=dlg) okButton.clicked.connect(dlg.accept) layout.addWidget(okButton) dlg.setLayout(layout) dlg.setModal(True) dlg.exec_() self.editor.cacheSize = cache_size[0] self._viewMenu.addAction("Set layer cache size").triggered.connect( setCacheSize) def enablePrefetching(enable): for scene in self.editor.imageScenes: scene.setPrefetchingEnabled(enable) actionUsePrefetching = self._viewMenu.addAction("Use prefetching") actionUsePrefetching.setCheckable(True) actionUsePrefetching.toggled.connect(enablePrefetching) def blockGuiForRendering(): for v in self.editor.imageViews: v.scene().joinRenderingAllTiles() v.repaint() QApplication.processEvents() actionBlockGui = self._viewMenu.addAction("Block for rendering") actionBlockGui.triggered.connect(blockGuiForRendering) qsw = QShortcut(QKeySequence("Ctrl+B"), self, member=actionBlockGui.trigger, context=Qt.WidgetShortcut) ShortcutManager().register("Navigation", "Block gui for rendering", qsw) self._debugActions.append(actionBlockGui) # ------ Separator ------ self._viewMenu.addAction("").setSeparator(True) # Text only actionOnlyForSelectedView = self._viewMenu.addAction( "Only for selected view") actionOnlyForSelectedView.setIconVisibleInMenu(True) font = actionOnlyForSelectedView.font() font.setItalic(True) font.setBold(True) actionOnlyForSelectedView.setFont(font) def setCurrentAxisIcon(): """Update the icon that shows the currently selected axis.""" actionOnlyForSelectedView.setIcon( QIcon(self.editor.imageViews[ self.editor._lastImageViewFocus]._hud.axisLabel.pixmap())) self.editor.newImageView2DFocus.connect(setCurrentAxisIcon) setCurrentAxisIcon() actionFitImage = self._viewMenu.addAction("Fit image") actionFitImage.triggered.connect(self._fitImage) qsa = QShortcut(QKeySequence("K"), self, member=actionFitImage.trigger, context=Qt.WidgetShortcut) ShortcutManager().register("Navigation", "Fit image on screen", qsa) def toggleSelectedHud(): self.editor.imageViews[self.editor._lastImageViewFocus].toggleHud() actionToggleSelectedHud = self._viewMenu.addAction("Toggle hud") actionToggleSelectedHud.triggered.connect(toggleSelectedHud) def resetAxes(): self.editor.imageScenes[ self.editor._lastImageViewFocus].resetAxes() self._viewMenu.addAction("Reset axes").triggered.connect(resetAxes) def centerImage(): self.editor.imageViews[ self.editor._lastImageViewFocus].centerImage() actionCenterImage = self._viewMenu.addAction("Center image") actionCenterImage.triggered.connect(centerImage) qsc = QShortcut(QKeySequence("C"), self, member=actionCenterImage.trigger, context=Qt.WidgetShortcut) ShortcutManager().register("Navigation", "Center image", qsc) def restoreImageToOriginalSize(): self.editor.imageViews[self.editor._lastImageViewFocus].doScaleTo() actionResetZoom = self._viewMenu.addAction("Reset zoom") actionResetZoom.triggered.connect(restoreImageToOriginalSize) qsw = QShortcut(QKeySequence("W"), self, member=actionResetZoom.trigger, context=Qt.WidgetShortcut) ShortcutManager().register("Navigation", "Reset zoom", qsw) def updateHudActions(): dataShape = self.editor.dataShape # if the image is 2D, do not show the HUD action (issue #190) is2D = numpy.sum(numpy.asarray(dataShape[1:4]) == 1) == 1 actionToggleSelectedHud.setVisible(not is2D) self._viewMenu.actionToggleAllHuds.setVisible(not is2D) self.editor.shapeChanged.connect(updateHudActions)
def _initShortcuts(self): mgr = ShortcutManager() shortcutGroupName = "Manual Tracking" divisionEvent = QtGui.QShortcut( QtGui.QKeySequence("d"), self, member=self._drawer.divEvent.click ) mgr.register( shortcutGroupName, "Mark Division Event (Click on parent object first, then on the two children.)", divisionEvent, self._drawer.divEvent ) newTrack = QtGui.QShortcut( QtGui.QKeySequence("s"), self, member=self._drawer.newTrack.click ) mgr.register( shortcutGroupName, "Start New Track", newTrack, self._drawer.newTrack ) markMisdet = QtGui.QShortcut( QtGui.QKeySequence("f"), self, member=self._drawer.markMisdetection.click ) mgr.register( shortcutGroupName, "Mark False Detection", markMisdet, self._drawer.markMisdetection ) activeTrackUp = QtGui.QShortcut( QtGui.QKeySequence("q"), self, member=self._incrementActiveTrack ) mgr.register( shortcutGroupName, "Increment Active Track ID", activeTrackUp,) activeTrackDown = QtGui.QShortcut( QtGui.QKeySequence("a"), self, member=self._decrementActiveTrack ) mgr.register( shortcutGroupName, "Decrement Active Track ID", activeTrackDown,) goToNext = QtGui.QShortcut( QtGui.QKeySequence("g"), self, member=self._onNextUnlabeledPressed ) mgr.register( shortcutGroupName, "Go To Next Unlabeled Object", goToNext,)
def createDrawerControls(self): """ This is a separate function from initAppletDrawer() so that it can be called and used within another applet (this class is a mixin). """ op = self.__topLevelOperatorView def configure_update_handlers(qt_signal, op_slot): qt_signal.connect(self.configure_operator_from_gui) op_slot.notifyDirty(self.configure_gui_from_operator) self.__cleanup_fns.append(partial(op_slot.unregisterDirty, self.configure_gui_from_operator)) def control_layout(label_text, widget): row_layout = QHBoxLayout() row_layout.addWidget(QLabel(label_text)) row_layout.addSpacerItem(QSpacerItem(10, 0, QSizePolicy.Expanding)) row_layout.addWidget(widget) return row_layout drawer_layout = QVBoxLayout() drawer_layout.setSpacing(1) # Beta beta_box = QDoubleSpinBox( decimals=2, minimum=0.01, maximum=0.99, singleStep=0.1, toolTip="Bias parameter for the multicut optimization.", ) configure_update_handlers(beta_box.valueChanged, op.Beta) beta_layout = control_layout("Beta", beta_box) self.beta_box = beta_box # Beta parameter only modifiable in debug mode dbg = ilastik_config.getboolean("ilastik", "debug") if dbg: drawer_layout.addLayout(beta_layout) # Probability Threshold - above which an edge is 'on' probability_threshold_box = QDoubleSpinBox( decimals=2, minimum=0.01, maximum=0.99, singleStep=0.1, toolTip="Probability threshold for an edge to be 'ON'", ) configure_update_handlers(probability_threshold_box.valueChanged, op.ProbabilityThreshold) probability_threshold_layout = control_layout("Threshold", probability_threshold_box) drawer_layout.addLayout(probability_threshold_layout) drawer_layout.addSpacerItem(QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.probability_threshold_box = probability_threshold_box # Solver solver_name_combo = QComboBox( toolTip="Multicut optimization technique. Available solvers depend on which optimizer library you have installed." ) for solver_name in AVAILABLE_SOLVER_NAMES: solver_name_combo.addItem(solver_name) configure_update_handlers(solver_name_combo.currentIndexChanged, op.SolverName) # Only add the solver checkbox in debug mode if dbg: drawer_layout.addLayout(control_layout("Solver", solver_name_combo)) self.solver_name_combo = solver_name_combo button_layout = QHBoxLayout() # Update Button update_button = QPushButton( text="Update Now", icon=QIcon(ilastikIcons.Play), clicked=self._handle_multicut_update_clicked ) button_layout.addWidget(update_button) self.update_button = update_button drawer_layout.addLayout(button_layout) # Layout drawer_layout.addSpacerItem(QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)) # Finally, the whole drawer widget drawer = QWidget(parent=self) drawer.setLayout(drawer_layout) # Widget Shortcuts mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo shortcut_group = "Multicut" mgr.register( "u", ActionInfo( shortcut_group, "UpdateMulticut", "Run the multicut optimization using the current edge probabilities", update_button.click, update_button, update_button, ), ) return drawer