def __init__(self, topLevelOperator, projectFileGroupName): super(DataSelectionSerializer, self).__init__(projectFileGroupName) self.topLevelOperator = topLevelOperator self._dirty = False self._projectFilePath = None self.version = "0.2" def handleDirty(): if not self.ignoreDirty: self._dirty = True self.topLevelOperator.ProjectFile.notifyDirty(bind(handleDirty)) self.topLevelOperator.ProjectDataGroup.notifyDirty(bind(handleDirty)) self.topLevelOperator.WorkingDirectory.notifyDirty(bind(handleDirty)) def handleNewDataset(slot, roleIndex): slot[roleIndex].notifyDirty(bind(handleDirty)) slot[roleIndex].notifyDisconnect(bind(handleDirty)) def handleNewLane(multislot, laneIndex): assert multislot == self.topLevelOperator.DatasetGroup multislot[laneIndex].notifyInserted(bind(handleNewDataset)) for roleIndex in range(len(multislot[laneIndex])): handleNewDataset(multislot[laneIndex], roleIndex) self.topLevelOperator.DatasetGroup.notifyInserted(bind(handleNewLane)) # If a dataset was removed, we need to be reserialized. self.topLevelOperator.DatasetGroup.notifyRemoved(bind(handleDirty))
def initAppletDrawerUi(self): # Load the ui file (find it in our own directory) localDir = os.path.split(__file__)[0] self._drawer = uic.loadUi(localDir+"/drawer.ui") layout = QVBoxLayout() layout.setSpacing(0) self._drawer.setLayout( layout ) thresholdWidget = ThresholdingWidget(self) thresholdWidget.valueChanged.connect( self.handleThresholdGuiValuesChanged ) self._drawer.layout().addWidget( thresholdWidget ) self._drawer.layout().addSpacerItem( QSpacerItem(0,0,vPolicy=QSizePolicy.Expanding) ) def updateDrawerFromOperator(): minValue, maxValue = (0,255) if self.topLevelOperatorView.MinValue.ready(): minValue = self.topLevelOperatorView.MinValue.value if self.topLevelOperatorView.MaxValue.ready(): maxValue = self.topLevelOperatorView.MaxValue.value thresholdWidget.setValue(minValue, maxValue) self.topLevelOperatorView.MinValue.notifyDirty( bind(updateDrawerFromOperator) ) self.topLevelOperatorView.MaxValue.notifyDirty( bind(updateDrawerFromOperator) ) updateDrawerFromOperator()
def __init__(self, parent=None, graph=None): self._solver = "ILP" super(OpStructuredTracking, self).__init__(parent=parent, graph=graph) self.labels = {} self.divisions = {} self.Annotations.setValue({}) self._ndim = 3 self._parent = parent self.DivisionWeight.setValue(0.6) self.DetectionWeight.setValue(0.6) self.TransitionWeight.setValue(0.01) self.AppearanceWeight.setValue(0.3) self.DisappearanceWeight.setValue(0.2) self.MaxNumObjOut.setValue(1) self.transition_parameter = 5 self.detectionWeight = 1 self.divisionWeight = 1 self.transitionWeight = 1 self.appearanceWeight = 1 self.disappearanceWeight = 1 self.Crops.notifyReady(bind(self._updateCropsFromOperator) ) self.Labels.notifyReady( bind(self._updateLabelsFromOperator) ) self.Divisions.notifyReady( bind(self._updateDivisionsFromOperator) ) self._solver = self.parent.parent._solver
def __init__(self, mainOperator, projectFileGroupName): with Tracer(traceLogger): super(AutocontextClassificationSerializer, self).__init__(projectFileGroupName) self.mainOperator = mainOperator self._initDirtyFlags() # Set up handlers for dirty detection def handleDirty(section): if not self.ignoreDirty: self._dirtyFlags[section] = True def handleNewClassifier(slot, index): slot[index].notifyDirty(bind(handleDirty, 1)) #self.mainOperator.Classifiers.notifyDirty( bind(handleDirty, Section.Classifiers) ) self.mainOperator.Classifiers.notifyInserted( bind(handleNewClassifier)) def handleNewImage(section, slot, index): slot[index].notifyDirty(bind(handleDirty, section)) # New label images need to be 'serialized' as an empty group. if section == Section.Labels: handleDirty(Section.Labels) # These are multi-slots, so subscribe to dirty callbacks on each of their subslots as they are created self.mainOperator.LabelImages.notifyInserted( bind(handleNewImage, Section.Labels)) self.mainOperator.PredictionProbabilities.notifyInserted( bind(handleNewImage, Section.Predictions)) #self.mainOperator.PixelOnlyPredictions.notifyInserted( bind(handleNewImage, Section.PixelPredictions) ) self._predictionStorageEnabled = False self._predictionStorageRequest = None self._predictionsPresent = False
def initAppletDrawerUi(self): with Tracer(traceLogger): # Load the ui file (find it in our own directory) localDir = os.path.split(__file__)[0] self._drawer = uic.loadUi(localDir+"/drawer.ui") layout = QVBoxLayout( self ) layout.setSpacing(0) self._drawer.setLayout( layout ) thresholdWidget = ThresholdingWidget(self) thresholdWidget.valueChanged.connect( self.handleThresholdGuiValuesChanged ) layout.addWidget( thresholdWidget ) def updateDrawerFromOperator(): minValue, maxValue = (0,255) if self.mainOperator.MinValue.ready(): minValue = self.mainOperator.MinValue.value if self.mainOperator.MaxValue.ready(): maxValue = self.mainOperator.MaxValue.value thresholdWidget.setValue(minValue, maxValue) self.mainOperator.MinValue.notifyDirty( bind(updateDrawerFromOperator) ) self.mainOperator.MaxValue.notifyDirty( bind(updateDrawerFromOperator) )
def __init__(self, mainOperator, projectFileGroupName): with Tracer(traceLogger): super(PixelClassificationSerializer, self).__init__(projectFileGroupName, self.SerializerVersion) self.mainOperator = mainOperator self._initDirtyFlags() # Set up handlers for dirty detection def handleDirty(section): self._dirtyFlags[section] = True self.mainOperator.Classifier.notifyDirty( bind(handleDirty, Section.Classifier)) def handleNewImage(section, slot, index): slot[index].notifyDirty(bind(handleDirty, section)) # These are multi-slots, so subscribe to dirty callbacks on each of their subslots as they are created self.mainOperator.LabelImages.notifyInserted( bind(handleNewImage, Section.Labels)) self.mainOperator.PredictionProbabilities.notifyInserted( bind(handleNewImage, Section.Predictions)) self._predictionStorageEnabled = False self._predictionStorageRequest = None self._predictionsPresent = False
def __init__(self, dataSelectionOperator, serializer, guiControlSignal, guiMode=GuiMode.Normal): with Tracer(traceLogger): super(DataSelectionGui, self).__init__() self.drawer = None self.mainOperator = dataSelectionOperator self.guiMode = guiMode self.serializer = serializer self.guiControlSignal = guiControlSignal self.threadRouter = ThreadRouter(self) self.initAppletDrawerUic() self.initCentralUic() def handleNewDataset( multislot, index ): with Tracer(traceLogger): assert multislot == self.mainOperator.Dataset # Make room in the table self.fileInfoTableWidget.insertRow( index ) # Update the table row data when this slot has new data # We can't bind in the row here because the row may change in the meantime. self.mainOperator.Dataset[index].notifyDirty( self.updateTableForSlot ) self.mainOperator.Dataset.notifyInserted( bind( handleNewDataset ) ) def handleDatasetRemoved( multislot, index ): with Tracer(traceLogger): assert multislot == self.mainOperator.Dataset # Simply remove the row we don't need any more self.fileInfoTableWidget.removeRow( index ) self.mainOperator.Dataset.notifyRemove( bind( handleDatasetRemoved ) )
def setImageNameListSlot(self, multiSlot): assert multiSlot.level == 1 self.imageNamesSlot = multiSlot def insertImageName(index, slot): self.imageSelectionCombo.setItemText(index, slot.value) if self.currentImageIndex == -1: self.changeCurrentInputImageIndex(index) def handleImageNameSlotInsertion(multislot, index): assert multislot == self.imageNamesSlot self.populatingImageSelectionCombo = True self.imageSelectionCombo.insertItem(index, "uninitialized") self.populatingImageSelectionCombo = False multislot[index].notifyDirty(bind(insertImageName, index)) multiSlot.notifyInserted(bind(handleImageNameSlotInsertion)) def handleImageNameSlotRemoval(multislot, index): # Simply remove the combo entry, which causes the currentIndexChanged signal to fire if necessary. self.imageSelectionCombo.removeItem(index) if len(multislot) == 0: self.changeCurrentInputImageIndex(-1) multiSlot.notifyRemove(bind(handleImageNameSlotRemoval))
def __init__(self, parent=None, graph=None): super(OpStructuredTracking, self).__init__(parent=parent, graph=graph) self.labels = {} self.divisions = {} self.Annotations.setValue({}) self._ndim = 3 self._parent = parent self.DivisionWeight.setValue(0.6) self.DetectionWeight.setValue(0.6) self.TransitionWeight.setValue(0.01) self.AppearanceWeight.setValue(0.3) self.DisappearanceWeight.setValue(0.2) self.MaxNumObjOut.setValue(1) self.transition_parameter = 5 self.detectionWeight = 1 self.divisionWeight = 1 self.transitionWeight = 1 self.appearanceWeight = 1 self.disappearanceWeight = 1 self.Crops.notifyReady(bind(self._updateCropsFromOperator) ) self.Labels.notifyReady( bind(self._updateLabelsFromOperator) ) self.Divisions.notifyReady( bind(self._updateDivisionsFromOperator) )
def __init__(self, op, shellRequestSignal, guiControlSignal): # Tell our base class which slots to monitor labelSlots = LabelingGui.LabelingSlots() labelSlots.labelInput = op.LabelInputs labelSlots.labelOutput = op.LabelImages labelSlots.labelEraserValue = op.Eraser labelSlots.labelDelete = op.DeleteLabel labelSlots.maxLabelValue = op.NumLabels labelSlots.labelsAllowed = op.LabelsAllowedFlags # We provide our own UI file (which adds an extra control for # interactive mode) This UI file is copied from # pixelClassification pipeline # labelingDrawerUiPath = os.path.split(__file__)[0] + '/labelingDrawer.ui' # Base class init super(ObjectClassificationGui, self).__init__(labelSlots, op, labelingDrawerUiPath, crosshair=False) self.op = op self.guiControlSignal = guiControlSignal self.shellRequestSignal = shellRequestSignal topLevelOp = self.topLevelOperatorView.viewed_operator() self.threadRouter = ThreadRouter(self) op.Warnings.notifyDirty(self.handleWarnings) # unused self.labelingDrawerUi.savePredictionsButton.setEnabled(False) self.labelingDrawerUi.savePredictionsButton.setVisible(False) self.labelingDrawerUi.brushSizeComboBox.setEnabled(False) self.labelingDrawerUi.brushSizeComboBox.setVisible(False) self.labelingDrawerUi.brushSizeCaption.setVisible(False) self._colorTable16_forpmaps = self._createDefault16ColorColorTable() self._colorTable16_forpmaps[15] = QColor(Qt.black).rgba() #for objects with NaNs in features # button handlers self._interactiveMode = False self._showPredictions = False self._labelMode = True self.labelingDrawerUi.subsetFeaturesButton.clicked.connect( self.handleSubsetFeaturesClicked) self.labelingDrawerUi.checkInteractive.toggled.connect( self.handleInteractiveModeClicked) self.labelingDrawerUi.checkShowPredictions.toggled.connect( self.handleShowPredictionsClicked) # enable/disable buttons logic self.op.ObjectFeatures.notifyDirty(bind(self.checkEnableButtons)) self.op.NumLabels.notifyDirty(bind(self.checkEnableButtons)) self.op.SelectedFeatures.notifyDirty(bind(self.checkEnableButtons)) self.checkEnableButtons()
def __init__(self, parentApplet, croppingSlots, topLevelOperatorView, drawerUiPath=None, rawInputSlot=None, crosshair=True): """ Constructor. :param croppingSlots: Provides the slots needed for sourcing/sinking crop data. See CroppingGui.CroppingSlots class source for details. :param topLevelOperatorView: is provided to the LayerViewerGui (the base class) :param drawerUiPath: can be given if you provide an extended drawer UI file. Otherwise a default one is used. :param rawInputSlot: Data from the rawInputSlot parameter will be displayed directly underneath the elements (if provided). """ # Do we have all the slots we need? assert isinstance(croppingSlots, CroppingGui.CroppingSlots) assert croppingSlots.cropInput is not None, "Missing a required slot." assert croppingSlots.cropOutput is not None, "Missing a required slot." assert croppingSlots.cropEraserValue is not None, "Missing a required slot." assert croppingSlots.cropDelete is not None, "Missing a required slot." assert croppingSlots.cropNames is not None, "Missing a required slot." assert croppingSlots.cropsAllowed is not None, "Missing a required slot." self.__cleanup_fns = [] self._croppingSlots = croppingSlots self._minCropNumber = 0 self._maxCropNumber = 99 #100 or 255 is reserved for eraser self._rawInputSlot = rawInputSlot self.topLevelOperatorView.Crops.notifyDirty(bind(self._updateCropList)) self.topLevelOperatorView.Crops.notifyDirty(bind(self._updateCropList)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.Crops.unregisterDirty, bind(self._updateCropList))) self._colorTable16 = self._createDefault16ColorColorTable() self._programmaticallyRemovingCrops = False self._initCropUic(drawerUiPath) self._maxCropNumUsed = 0 self._allowDeleteLastCropOnly = False self.__initShortcuts() # Init base class super(CroppingGui, self).__init__( parentApplet, topLevelOperatorView, [croppingSlots.cropInput, croppingSlots.cropOutput], crosshair=crosshair) self._croppingSlots.cropEraserValue.setValue( self.editor.brushingModel.erasingNumber) # Register for thunk events (easy UI calls from non-GUI threads) self.thunkEventHandler = ThunkEventHandler(self)
def __init__(self, mainOperator, projectFileGroupName): with Tracer(traceLogger): super( AutocontextClassificationSerializer, self ).__init__( projectFileGroupName ) self.mainOperator = mainOperator self._initDirtyFlags() # Set up handlers for dirty detection def handleDirty(section): if not self.ignoreDirty: self._dirtyFlags[section] = True def handleNewClassifier(slot, index): slot[index].notifyDirty( bind(handleDirty, 1)) #self.mainOperator.Classifiers.notifyDirty( bind(handleDirty, Section.Classifiers) ) self.mainOperator.Classifiers.notifyInserted( bind(handleNewClassifier)) def handleNewImage(section, slot, index): slot[index].notifyDirty( bind(handleDirty, section) ) # New label images need to be 'serialized' as an empty group. if section == Section.Labels: handleDirty(Section.Labels) # These are multi-slots, so subscribe to dirty callbacks on each of their subslots as they are created self.mainOperator.LabelImages.notifyInserted( bind(handleNewImage, Section.Labels) ) self.mainOperator.PredictionProbabilities.notifyInserted( bind(handleNewImage, Section.Predictions) ) #self.mainOperator.PixelOnlyPredictions.notifyInserted( bind(handleNewImage, Section.PixelPredictions) ) self._predictionStorageEnabled = False self._predictionStorageRequest = None self._predictionsPresent = False
def __init__(self, topLevelOperator, projectFileGroupName): super( DataSelectionSerializer, self ).__init__(projectFileGroupName) self.topLevelOperator = topLevelOperator self._dirty = False self.caresOfHeadless = True self._projectFilePath = None self.version = '0.2' def handleDirty(): if not self.ignoreDirty: self._dirty = True self.topLevelOperator.ProjectFile.notifyDirty( bind(handleDirty) ) self.topLevelOperator.ProjectDataGroup.notifyDirty( bind(handleDirty) ) self.topLevelOperator.WorkingDirectory.notifyDirty( bind(handleDirty) ) def handleNewDataset(slot, roleIndex): slot[roleIndex].notifyDirty( bind(handleDirty) ) slot[roleIndex].notifyDisconnect( bind(handleDirty) ) def handleNewLane(multislot, laneIndex): assert multislot == self.topLevelOperator.DatasetGroup multislot[laneIndex].notifyInserted( bind(handleNewDataset) ) for roleIndex in range( len(multislot[laneIndex]) ): handleNewDataset(multislot[laneIndex], roleIndex) self.topLevelOperator.DatasetGroup.notifyInserted( bind(handleNewLane) ) # If a dataset was removed, we need to be reserialized. self.topLevelOperator.DatasetGroup.notifyRemoved( bind(handleDirty) )
def initAppletDrawerUi(self): """ Reimplemented from LayerViewerGui base class. """ # Load the ui file (find it in our own directory) localDir = os.path.split(__file__)[0] self._drawer = uic.loadUi(localDir+"/drawer.ui") self._drawer.applyButton.clicked.connect( self._onApplyButtonClicked ) self._drawer.tabWidget.currentChanged.connect( self._onTabCurrentChanged ) self._sigmaSpinBoxes = { 'x' : self._drawer.sigmaSpinBox_X, 'y' : self._drawer.sigmaSpinBox_Y, 'z' : self._drawer.sigmaSpinBox_Z } self._allWatchedWidgets = self._sigmaSpinBoxes.values() + \ [ self._drawer.inputChannelSpinBox, self._drawer.lowThresholdSpinBox, self._drawer.highThresholdSpinBox, self._drawer.thresholdSpinBox, self._drawer.minSizeSpinBox, self._drawer.maxSizeSpinBox ] for widget in self._allWatchedWidgets: # If the user pressed enter inside a spinbox, auto-click "Apply" widget.installEventFilter( self ) self._updateGuiFromOperator() self.topLevelOperatorView.InputImage.notifyReady( bind(self._updateGuiFromOperator) ) self.topLevelOperatorView.InputImage.notifyMetaChanged( bind(self._updateGuiFromOperator) )
def __init__(self, parentApplet, topLevelOperatorView): """ """ self.topLevelOperatorView = topLevelOperatorView super(FeatureSelectionGui, self).__init__(parentApplet, topLevelOperatorView, crosshair=False) self.parentApplet = parentApplet self.__cleanup_fns = [] self.topLevelOperatorView.SelectionMatrix.notifyDirty( bind(self.onFeaturesSelectionsChanged)) self.topLevelOperatorView.FeatureListFilename.notifyDirty( bind(self.onFeaturesSelectionsChanged)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.SelectionMatrix.unregisterDirty, bind(self.onFeaturesSelectionsChanged))) self.__cleanup_fns.append( partial( self.topLevelOperatorView.FeatureListFilename.unregisterDirty, bind(self.onFeaturesSelectionsChanged))) self.onFeaturesSelectionsChanged() # Init feature dialog self.initFeatureDlg()
def initAppletDrawerUi(self): # Load the ui file (find it in our own directory) localDir = os.path.split(__file__)[0] self._drawer = uic.loadUi(localDir+"/drawer.ui") # If the user changes a setting the GUI, update the appropriate operator slot. self._drawer.scalingFactorSpinBox.valueChanged.connect(self.updateOperatorScalingFactor) self._drawer.offsetSpinBox.valueChanged.connect(self.updateOperatorOffset) def updateDrawerFromOperator(): scalingFactor, offset = (0,0) if self.topLevelOperatorView.ScalingFactor.ready(): scalingFactor = self.topLevelOperatorView.ScalingFactor.value if self.topLevelOperatorView.Offset.ready(): offset = self.topLevelOperatorView.Offset.value self._drawer.scalingFactorSpinBox.setValue(scalingFactor) self._drawer.offsetSpinBox.setValue(offset) # If the operator is changed *outside* the GUI (e.g. the project is loaded), # then update the GUI to match the new operator slot values. self.topLevelOperatorView.ScalingFactor.notifyDirty( bind(updateDrawerFromOperator) ) self.topLevelOperatorView.Offset.notifyDirty( bind(updateDrawerFromOperator) ) # Initialize the GUI with the operator's initial state. updateDrawerFromOperator() # Provide defaults if the operator isn't already configured. # (e.g. if it's a blank project, then the operator won't have any setup yet.) if not self.topLevelOperatorView.ScalingFactor.ready(): self.updateOperatorScalingFactor(1) if not self.topLevelOperatorView.Offset.ready(): self.updateOperatorOffset(0)
def __init__(self, dataSelectionOperator, guiControlSignal, progressSignal, title): with Tracer(traceLogger): super(BatchIoGui, self).__init__() self.title = title self.drawer = None self.mainOperator = dataSelectionOperator self.initAppletDrawerUic() self.initCentralUic() self.chosenExportDirectory = '/' self.guiControlSignal = guiControlSignal self.progressSignal = progressSignal def handleNewDataset( multislot, index ): # Make room in the GUI table self.tableWidget.insertRow( index ) # Update the table row data when this slot has new data # We can't bind in the row here because the row may change in the meantime. multislot[index].notifyDirty( bind( self.updateTableForSlot ) ) self.mainOperator.OutputDataPath.notifyInserted( bind( handleNewDataset ) ) def handleDatasetRemoved( multislot, index ): # Simply remove the row we don't need any more self.tableWidget.removeRow( index ) self.mainOperator.OutputDataPath.notifyRemove( bind( handleDatasetRemoved ) ) self.mainOperator.Suffix.notifyDirty( self.updateDrawerGuiFromOperatorSettings ) self.mainOperator.ExportDirectory.notifyDirty( self.updateDrawerGuiFromOperatorSettings ) self.mainOperator.Format.notifyDirty( self.updateDrawerGuiFromOperatorSettings ) self.updateDrawerGuiFromOperatorSettings()
def initAppletDrawerUi(self): # Load the ui file (find it in our own directory) localDir = os.path.split(__file__)[0] self._drawer = uic.loadUi(localDir+"/drawer.ui") # If the user changes a setting the GUI, update the appropriate operator slot. self._drawer.SuperPixelSizeSpinBox.valueChanged.connect(self.updateOperatorSuperPixelSize) self._drawer.CubenessSpinBox.valueChanged.connect(self.updateOperatorCubeness) self._drawer.MaxIterSpinBox.valueChanged.connect(self.updateOperatorMaxIter) def updateDrawerFromOperator(): SuperPixelSize, Cubeness, MaxIter = (15,10, 6) if self.topLevelOperatorView.SuperPixelSize.ready(): SuperPixelSize = self.topLevelOperatorView.SuperPixelSize.value if self.topLevelOperatorView.Cubeness.ready(): Cubeness = self.topLevelOperatorView.Cubeness.value if self.topLevelOperatorView.MaxIter.ready(): MaxIter = self.topLevelOperatorView.MaxIter.value self._drawer.SuperPixelSizeSpinBox.setValue(SuperPixelSize) self._drawer.CubenessSpinBox.setValue(Cubeness) self._drawer.MaxIterSpinBox.setValue(MaxIter) # If the operator is changed *outside* the GUI (e.g. the project is loaded), # then update the GUI to match the new operator slot values. self.topLevelOperatorView.SuperPixelSize.notifyDirty( bind(updateDrawerFromOperator)) self.topLevelOperatorView.Cubeness.notifyDirty( bind(updateDrawerFromOperator)) self.topLevelOperatorView.MaxIter.notifyDirty( bind(updateDrawerFromOperator)) # Initialize the GUI with the operator's initial state. updateDrawerFromOperator()
def initAppletDrawerUi(self): localDir = os.path.split(__file__)[0] self._drawer = self._cropControlUi data_has_z_axis = True if self.topLevelOperatorView.InputImage.ready(): tShape = self.topLevelOperatorView.InputImage.meta.getTaggedShape() if not 'z' in tShape or tShape['z']==1: data_has_z_axis = False self._cropControlUi._minSliderZ.setVisible(data_has_z_axis) self._cropControlUi._minSliderZ.setVisible(data_has_z_axis) self._cropControlUi._maxSliderZ.setVisible(data_has_z_axis) self._cropControlUi._minSpinZ.setVisible(data_has_z_axis) self._cropControlUi._maxSpinZ.setVisible(data_has_z_axis) self._cropControlUi.labelMinZ.setVisible(data_has_z_axis) self._cropControlUi.labelMaxZ.setVisible(data_has_z_axis) self._cropControlUi.AddCropButton.clicked.connect( bind (self.newCrop) ) self._cropControlUi.SetCropButton.setVisible(False) self.editor.cropModel.mouseRelease.connect(bind(self.setCrop)) self.topLevelOperatorView.MinValueT.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueT.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MinValueX.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueX.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MinValueY.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueY.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MinValueZ.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueZ.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.InputImage.notifyDirty(self.setDefaultValues) self.topLevelOperatorView.PredictionImage.notifyDirty(self.setDefaultValues) layout = QVBoxLayout() layout.setSpacing(0) layout.addWidget( self._cropControlUi ) layout.addSpacerItem( QSpacerItem(0,0,vPolicy=QSizePolicy.Expanding) ) self.setDefaultValues() self.apply_operator_settings_to_gui() self.editor.showCropLines(True) self.editor.cropModel.setEditable (True) self.editor.cropModel.changed.connect(self.onCropModelChanged) self.editor.posModel.timeChanged.connect(self.updateTime) self._cropControlUi._minSliderT.valueChanged.connect(self._onMinSliderTMoved) self._cropControlUi._maxSliderT.valueChanged.connect(self._onMaxSliderTMoved) self._cropControlUi._minSliderX.valueChanged.connect(self._onMinSliderXMoved) self._cropControlUi._maxSliderX.valueChanged.connect(self._onMaxSliderXMoved) self._cropControlUi._minSliderY.valueChanged.connect(self._onMinSliderYMoved) self._cropControlUi._maxSliderY.valueChanged.connect(self._onMaxSliderYMoved) self._cropControlUi._minSliderZ.valueChanged.connect(self._onMinSliderZMoved) self._cropControlUi._maxSliderZ.valueChanged.connect(self._onMaxSliderZMoved) self._cropControlUi.cropListView.deleteCrop.connect(self.onDeleteCrop) self._cropControlUi.cropListView.colorsChanged.connect(self.onColorsChanged) self._initCropListView()
def __init__(self, parentApplet, topLevelOperatorView): self.parentApplet = parentApplet # Tell our base class which slots to monitor labelSlots = LabelingGui.LabelingSlots() labelSlots.labelInput = topLevelOperatorView.LabelInputs labelSlots.labelOutput = topLevelOperatorView.LabelImages labelSlots.labelEraserValue = topLevelOperatorView.opLabelPipeline.opLabelArray.eraser labelSlots.labelDelete = topLevelOperatorView.opLabelPipeline.DeleteLabel labelSlots.labelNames = topLevelOperatorView.LabelNames labelSlots.labelsAllowed = topLevelOperatorView.LabelsAllowedFlags self.__cleanup_fns = [] # We provide our own UI file (which adds an extra control for interactive mode) labelingDrawerUiPath = os.path.split(__file__)[0] + "/labelingDrawer.ui" # Base class init super(PixelClassificationGui, self).__init__( parentApplet, labelSlots, topLevelOperatorView, labelingDrawerUiPath ) self.topLevelOperatorView = topLevelOperatorView self.interactiveModeActive = False # Immediately update our interactive state self.toggleInteractive(not self.topLevelOperatorView.FreezePredictions.value) self._currentlySavingPredictions = False self.labelingDrawerUi.liveUpdateButton.setEnabled(False) self.labelingDrawerUi.liveUpdateButton.setIcon(QIcon(ilastikIcons.Play)) self.labelingDrawerUi.liveUpdateButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.labelingDrawerUi.liveUpdateButton.toggled.connect(self.toggleInteractive) self.topLevelOperatorView.LabelNames.notifyDirty(bind(self.handleLabelSelectionChange)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.LabelNames.unregisterDirty, bind(self.handleLabelSelectionChange)) ) self._initShortcuts() try: self.render = True self._renderedLayers = {} # (layer name, label number) self._renderMgr = RenderingManager(renderer=self.editor.view3d.qvtk.renderer, qvtk=self.editor.view3d.qvtk) except: self.render = False # toggle interactive mode according to freezePredictions.value self.toggleInteractive(not self.topLevelOperatorView.FreezePredictions.value) def FreezePredDirty(): self.toggleInteractive(not self.topLevelOperatorView.FreezePredictions.value) # listen to freezePrediction changes self.topLevelOperatorView.FreezePredictions.notifyDirty(bind(FreezePredDirty)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.FreezePredictions.unregisterDirty, bind(FreezePredDirty)) )
def _handleLayerInsertion(self, slot, slotIndex): """ The multislot providing our layers has a new item. Make room for it in the layer GUI and subscribe to updates. """ # When the slot is ready, we'll replace the blank layer with real data slot[slotIndex].notifyReady( bind(self.updateAllLayers) ) slot[slotIndex].notifyUnready( bind(self.updateAllLayers) )
def __init__(self, *args, **kwargs): super(CountingResultsViewer, self).__init__(*args, **kwargs) self.topLevelOperatorView.PmapColors.notifyDirty( bind(self.updateAllLayers)) self.topLevelOperatorView.LabelNames.notifyDirty( bind(self.updateAllLayers)) self.topLevelOperatorView.UpperBound.notifyDirty( bind(self.updateAllLayers))
def initAppletDrawerUi(self): localDir = os.path.split(__file__)[0] self._drawer = self._cropControlUi data_has_z_axis = True if self.topLevelOperatorView.InputImage.ready(): tShape = self.topLevelOperatorView.InputImage.meta.getTaggedShape() if not 'z' in tShape or tShape['z']==1: data_has_z_axis = False self._cropControlUi._minSliderZ.setVisible(data_has_z_axis) self._cropControlUi._minSliderZ.setVisible(data_has_z_axis) self._cropControlUi._maxSliderZ.setVisible(data_has_z_axis) self._cropControlUi._minSpinZ.setVisible(data_has_z_axis) self._cropControlUi._maxSpinZ.setVisible(data_has_z_axis) self._cropControlUi.labelMinZ.setVisible(data_has_z_axis) self._cropControlUi.labelMaxZ.setVisible(data_has_z_axis) self._cropControlUi.AddCropButton.clicked.connect( bind (self.newCrop) ) self._cropControlUi.SetCropButton.clicked.connect( bind (self.setCrop) ) self.topLevelOperatorView.MinValueT.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueT.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MinValueX.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueX.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MinValueY.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueY.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MinValueZ.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.MaxValueZ.notifyDirty(self.apply_operator_settings_to_gui) self.topLevelOperatorView.InputImage.notifyDirty(self.setDefaultValues) self.topLevelOperatorView.PredictionImage.notifyDirty(self.setDefaultValues) layout = QVBoxLayout() layout.setSpacing(0) layout.addWidget( self._cropControlUi ) layout.addSpacerItem( QSpacerItem(0,0,vPolicy=QSizePolicy.Expanding) ) self.setDefaultValues() self.apply_operator_settings_to_gui() self.editor.showCropLines(True) self.editor.cropModel.setEditable (True) self.editor.cropModel.changed.connect(self.onCropModelChanged) self.editor.posModel.timeChanged.connect(self.updateTime) self._cropControlUi._minSliderT.valueChanged.connect(self._onMinSliderTMoved) self._cropControlUi._maxSliderT.valueChanged.connect(self._onMaxSliderTMoved) self._cropControlUi._minSliderX.valueChanged.connect(self._onMinSliderXMoved) self._cropControlUi._maxSliderX.valueChanged.connect(self._onMaxSliderXMoved) self._cropControlUi._minSliderY.valueChanged.connect(self._onMinSliderYMoved) self._cropControlUi._maxSliderY.valueChanged.connect(self._onMaxSliderYMoved) self._cropControlUi._minSliderZ.valueChanged.connect(self._onMinSliderZMoved) self._cropControlUi._maxSliderZ.valueChanged.connect(self._onMaxSliderZMoved) self._cropControlUi.cropListView.deleteCrop.connect(self.onDeleteCrop) self._cropControlUi.cropListView.colorsChanged.connect(self.onColorsChanged) self._initCropListView()
def __init__(self, parentApplet, topLevelOperator): super(DataExportGui, self).__init__() self.drawer = None self.topLevelOperator = topLevelOperator self.threadRouter = ThreadRouter(self) self._thunkEventHandler = ThunkEventHandler(self) self._initAppletDrawerUic() self.initCentralUic() self.initViewerControls() self.parentApplet = parentApplet self.progressSignal = parentApplet.progressSignal self.overwrite = False @threadRoutedWithRouter(self.threadRouter) def handleNewDataset(multislot, index): # Make room in the GUI table self.batchOutputTableWidget.insertRow(index) # Update the table row data when this slot has new data # We can't bind in the row here because the row may change in the meantime. multislot[index].notifyReady(bind(self.updateTableForSlot)) if multislot[index].ready(): self.updateTableForSlot(multislot[index]) multislot[index].notifyUnready(self._updateExportButtons) multislot[index].notifyReady(self._updateExportButtons) self.topLevelOperator.ExportPath.notifyInserted(bind(handleNewDataset)) # For each dataset that already exists, update the GUI for i, subslot in enumerate(self.topLevelOperator.ExportPath): handleNewDataset(self.topLevelOperator.ExportPath, i) if subslot.ready(): self.updateTableForSlot(subslot) @threadRoutedWithRouter(self.threadRouter) def handleLaneRemoved(multislot, index, finalLength): if self.batchOutputTableWidget.rowCount() <= finalLength: return # Remove the row we don't need any more self.batchOutputTableWidget.removeRow(index) # Remove the viewer for this dataset imageMultiSlot = self.topLevelOperator.Inputs[index] if imageMultiSlot in self.layerViewerGuis.keys(): layerViewerGui = self.layerViewerGuis[imageMultiSlot] self.viewerStack.removeWidget(layerViewerGui) self._viewerControlWidgetStack.removeWidget( layerViewerGui.viewerControlWidget()) layerViewerGui.stopAndCleanUp() self.topLevelOperator.Inputs.notifyRemove(bind(handleLaneRemoved))
def __init__(self, topLevelOperatorView, additionalMonitoredSlots=[], centralWidgetOnly=False, crosshair=True): """ Constructor. **All** slots of the provided *topLevelOperatorView* will be monitored for changes. Changes include slot resize events, and slot ready/unready status changes. When a change is detected, the `setupLayers()` function is called, and the result is used to update the list of layers shown in the central widget. :param topLevelOperatorView: The top-level operator for the applet this GUI belongs to. :param additionalMonitoredSlots: Optional. Can be used to add additional slots to the set of viewable layers (all slots from the top-level operator are already monitored). :param centralWidgetOnly: If True, provide only a central widget without drawer or viewer controls. """ super(LayerViewerGui, self).__init__() self._stopped = False self._initialized = False self.threadRouter = ThreadRouter(self) # For using @threadRouted self.topLevelOperatorView = topLevelOperatorView observedSlots = [] for slot in topLevelOperatorView.inputs.values() + topLevelOperatorView.outputs.values(): if slot.level == 0 or slot.level == 1: observedSlots.append(slot) observedSlots += additionalMonitoredSlots self._orphanOperators = [] # Operators that are owned by this GUI directly (not owned by the top-level operator) self.observedSlots = [] for slot in observedSlots: if slot.level == 0: if not isinstance(slot.stype, ArrayLike): # We don't support visualization of non-Array slots. continue # To be monitored and updated correctly by this GUI, slots must have level=1, but this slot is of level 0. # Pass it through a trivial "up-leveling" operator so it will have level 1 for our purposes. opPromoteInput = Op1ToMulti(graph=slot.operator.graph) opPromoteInput.Input.connect(slot) slot = opPromoteInput.Outputs self._orphanOperators.append( opPromoteInput ) # Each slot should now be indexed as slot[layer_index] assert slot.level == 1 self.observedSlots.append( slot ) slot.notifyInserted( bind(self._handleLayerInsertion) ) slot.notifyRemoved( bind(self._handleLayerRemoval) ) for i in range(len(slot)): self._handleLayerInsertion(slot, i) self.layerstack = LayerStackModel() self._initCentralUic() self._initEditor(crosshair=crosshair) self.__viewerControlWidget = None if not centralWidgetOnly: self.initViewerControlUi() # Might be overridden in a subclass. Default implementation loads a standard layer widget. #self._drawer = QWidget( self ) self.initAppletDrawerUi() # Default implementation loads a blank drawer from drawer.ui.
def __init__(self, parentApplet, topLevelOperator): super(DataExportGui, self).__init__() self.drawer = None self.topLevelOperator = topLevelOperator self.threadRouter = ThreadRouter(self) self._thunkEventHandler = ThunkEventHandler(self) self._initAppletDrawerUic() self.initCentralUic() self.initViewerControls() self.parentApplet = parentApplet self.progressSignal = parentApplet.progressSignal self.overwrite = False @threadRoutedWithRouter(self.threadRouter) def handleNewDataset( multislot, index ): # Make room in the GUI table self.batchOutputTableWidget.insertRow( index ) # Update the table row data when this slot has new data # We can't bind in the row here because the row may change in the meantime. multislot[index].notifyReady( bind( self.updateTableForSlot ) ) if multislot[index].ready(): self.updateTableForSlot( multislot[index] ) multislot[index].notifyUnready( self._updateExportButtons ) multislot[index].notifyReady( self._updateExportButtons ) self.topLevelOperator.ExportPath.notifyInserted( bind( handleNewDataset ) ) # For each dataset that already exists, update the GUI for i, subslot in enumerate(self.topLevelOperator.ExportPath): handleNewDataset( self.topLevelOperator.ExportPath, i ) if subslot.ready(): self.updateTableForSlot(subslot) @threadRoutedWithRouter(self.threadRouter) def handleLaneRemoved( multislot, index, finalLength ): if self.batchOutputTableWidget.rowCount() <= finalLength: return # Remove the row we don't need any more self.batchOutputTableWidget.removeRow( index ) # Remove the viewer for this dataset imageMultiSlot = self.topLevelOperator.Inputs[index] if imageMultiSlot in list(self.layerViewerGuis.keys()): layerViewerGui = self.layerViewerGuis[imageMultiSlot] self.viewerStack.removeWidget( layerViewerGui ) self._viewerControlWidgetStack.removeWidget( layerViewerGui.viewerControlWidget() ) layerViewerGui.stopAndCleanUp() self.topLevelOperator.Inputs.notifyRemove( bind( handleLaneRemoved ) )
def __init__(self, parentApplet, topLevelOperatorView, labelingDrawerUiPath=None): labelSlots = LabelingGui.LabelingSlots() labelSlots.labelInput = topLevelOperatorView.LabelInputs labelSlots.labelOutput = topLevelOperatorView.LabelImages labelSlots.labelEraserValue = topLevelOperatorView.opLabelPipeline.opLabelArray.eraser labelSlots.labelDelete = topLevelOperatorView.opLabelPipeline.DeleteLabel labelSlots.labelNames = topLevelOperatorView.LabelNames self.parentApplet = parentApplet if labelingDrawerUiPath is None: localDir = os.path.split(__file__)[0] labelingDrawerUiPath = os.path.join(localDir, "nnClass.ui") super(NNClassGui, self).__init__(parentApplet, labelSlots, topLevelOperatorView, labelingDrawerUiPath) self._initCheckpointActions() self.classifiers = OrderedDict() self.liveTraining = False self.livePrediction = False self.__cleanup_fns = [] self.labelingDrawerUi.liveTraining.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.labelingDrawerUi.liveTraining.toggled.connect(self.toggleLiveTraining) self.labelingDrawerUi.livePrediction.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.set_live_predict_icon(self.livePrediction) self.labelingDrawerUi.livePrediction.toggled.connect(self.toggleLivePrediction) self.labelingDrawerUi.addModel.clicked.connect(self.addModelClicked) self.labelingDrawerUi.closeModel.setIcon(QIcon(ilastikIcons.ProcessStop)) self.labelingDrawerUi.closeModel.clicked.connect(self.closeModelClicked) self.labelingDrawerUi.uploadModel.setIcon(QIcon(ilastikIcons.Upload)) self.labelingDrawerUi.uploadModel.clicked.connect(self.uploadModelClicked) self.initViewerControls() self.initViewerControlUi() self.labelingDrawerUi.labelListView.support_merges = True self.batch_size = self.topLevelOperatorView.Batch_Size.value self.labelingDrawerUi.labelListView.allowDelete = False self.labelingDrawerUi.AddLabelButton.setEnabled(False) self.labelingDrawerUi.AddLabelButton.hide() self.topLevelOperatorView.LabelNames.notifyDirty(bind(self.handleLabelSelectionChange)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.LabelNames.unregisterDirty, bind(self.handleLabelSelectionChange)) ) self.__cleanup_fns.append(self.topLevelOperatorView.cleanUp) self.setLabelingUIEnabled(ALLOW_TRAINING) self.invalidatePredictionsTimer = QTimer() self.invalidatePredictionsTimer.timeout.connect(self.updatePredictions) self.tiktorchModel.registerListener(self._onModelStateChanged)
def handleLayerInsertion(self, slot, slotIndex): """ The multislot providing our layers has a new item. Make room for it in the layer GUI and subscribe to updates. """ with Tracer(traceLogger): # When the slot is ready, we'll replace the blank layer with real data slot[slotIndex].notifyReady(bind(self.updateAllLayers)) slot[slotIndex].notifyUnready(bind(self.updateAllLayers))
def __init__(self, topLevelOperator, guiControlSignal, progressSignal, title): with Tracer(traceLogger): super(BatchIoGui, self).__init__() self.title = title self.drawer = None self.topLevelOperator = topLevelOperator self.threadRouter = ThreadRouter(self) self.initAppletDrawerUic() self.initCentralUic() self.chosenExportDirectory = '/' self.initViewerControls() self.guiControlSignal = guiControlSignal self.progressSignal = progressSignal def handleNewDataset( multislot, index ): # Make room in the GUI table self.batchOutputTableWidget.insertRow( index ) # Update the table row data when this slot has new data # We can't bind in the row here because the row may change in the meantime. multislot[index].notifyReady( bind( self.updateTableForSlot ) ) if multislot[index].ready(): self.updateTableForSlot( multislot[index] ) self.topLevelOperator.OutputDataPath.notifyInserted( bind( handleNewDataset ) ) # For each dataset that already exists, update the GUI for i, subslot in enumerate(self.topLevelOperator.OutputDataPath): handleNewDataset( self.topLevelOperator.OutputDataPath, i ) if subslot.ready(): self.updateTableForSlot(subslot) def handleImageRemoved( multislot, index, finalLength ): if self.batchOutputTableWidget.rowCount() <= finalLength: return # Remove the row we don't need any more self.batchOutputTableWidget.removeRow( index ) # Remove the viewer for this dataset imageSlot = self.topLevelOperator.ImageToExport[index] if imageSlot in self.layerViewerGuis.keys(): layerViewerGui = self.layerViewerGuis[imageSlot] self.viewerStack.removeWidget( layerViewerGui ) self._viewerControlWidgetStack.removeWidget( layerViewerGui.viewerControlWidget() ) layerViewerGui.stopAndCleanUp() self.topLevelOperator.ImageToExport.notifyRemove( bind( handleImageRemoved ) ) self.topLevelOperator.Suffix.notifyDirty( self.updateDrawerGuiFromOperatorSettings ) self.topLevelOperator.ExportDirectory.notifyDirty( self.updateDrawerGuiFromOperatorSettings ) self.topLevelOperator.Format.notifyDirty( self.updateDrawerGuiFromOperatorSettings ) self.updateDrawerGuiFromOperatorSettings()
def addApplet(self, index, app): # Subscribe to progress updates from this applet, # and include the applet index in the signal parameters. app.progressSignal.connect( bind(self.handleAppletProgress, index) ) # Also subscribe to this applet's serializer progress updates. # (Progress will always come from either the serializer or the applet itself; not both at once.) for serializer in app.dataSerializers: serializer.progressSignal.connect( bind( self.handleAppletProgress, index ) )
def __init__(self, topLevelOperator, projectFileGroupName): super( FeatureSelectionSerializer, self ).__init__( projectFileGroupName) self.topLevelOperator = topLevelOperator self._dirty = False def handleDirty(): self._dirty = True self.topLevelOperator.Scales.notifyDirty( bind(handleDirty) ) self.topLevelOperator.FeatureIds.notifyDirty( bind(handleDirty) ) self.topLevelOperator.SelectionMatrix.notifyDirty( bind(handleDirty) )
def addApplet(self, index, app): # Subscribe to progress updates from this applet, # and include the applet index in the signal parameters. app.progressSignal.connect(bind(self.handleAppletProgress, index)) # Also subscribe to this applet's serializer progress updates. # (Progress will always come from either the serializer or the applet itself; not both at once.) for serializer in app.dataSerializers: serializer.progressSignal.connect( bind(self.handleAppletProgress, index))
def _handleLayerInsertion(self, slot, slotIndex): """ The multislot providing our layers has a new item. Make room for it in the layer GUI and subscribe to updates. """ # When the slot is ready, we'll replace the blank layer with real data slot[slotIndex].notifyReady( bind(self.setNeedUpdate) ) slot[slotIndex].notifyUnready( bind(self.setNeedUpdate) ) self.__cleanup_fns.append( partial( slot[slotIndex].unregisterReady, bind(self.setNeedUpdate) ) ) self.__cleanup_fns.append( partial( slot[slotIndex].unregisterUnready, bind(self.setNeedUpdate) ) )
def __init__(self, parent, topLevelOperator, roleIndex): """ :param topLevelOperator: An instance of OpMultiLaneDataSelectionGroup """ # super does not work here in Python 2.x, decorated class confuses it QAbstractItemModel.__init__(self, parent) self._op = topLevelOperator self._roleIndex = roleIndex def handleNewLane(multislot, laneIndex): assert multislot is self._op.DatasetGroup self.beginInsertRows(QModelIndex(), laneIndex, laneIndex) self.endInsertRows() def handleDatasetInfoChanged(slot): # Get the row of this slot laneSlot = slot.operator if laneSlot is None or laneSlot.operator is None: # This can happen during disconnect return try: laneIndex = laneSlot.operator.index(laneSlot) except ValueError: # If the slot doesn't exist in the lane, # then this dataset is in the process of being removed. return firstIndex = self.createIndex(laneIndex, 0) lastIndex = self.createIndex(laneIndex, self.columnCount() - 1) self.dataChanged.emit(firstIndex, lastIndex) def handleNewDatasetInserted(slot, index): if index == self._roleIndex: datasetMultiSlot[self._roleIndex].notifyDirty( bind(handleDatasetInfoChanged)) datasetMultiSlot[self._roleIndex].notifyDisconnect( bind(handleDatasetInfoChanged)) for laneIndex, datasetMultiSlot in enumerate( self._op.DatasetGroup): datasetMultiSlot.notifyInserted(bind(handleNewDatasetInserted)) if self._roleIndex < len(datasetMultiSlot): handleNewDatasetInserted(datasetMultiSlot, self._roleIndex) self._op.DatasetGroup.notifyInserted(bind(handleNewLane)) def handleLaneRemoved(multislot, laneIndex): assert multislot is self._op.DatasetGroup self.beginRemoveRows(QModelIndex(), laneIndex, laneIndex) self.endRemoveRows() self._op.DatasetGroup.notifyRemoved(bind(handleLaneRemoved)) # Any lanes that already exist must be added now. for laneIndex, slot in enumerate(self._op.DatasetGroup): handleNewLane(self._op.DatasetGroup, laneIndex)
def initAppletDrawerUi(self): """ Reimplemented from LayerViewerGui base class. """ # Load the ui file (find it in our own directory) localDir = os.path.split(__file__)[0] self._drawer = uic.loadUi(localDir + "/drawer.ui") self._drawer.applyButton.clicked.connect(self._onApplyButtonClicked) self._drawer.tabWidget.currentChanged.connect( self._onTabCurrentChanged) self._sigmaSpinBoxes = { 'x': self._drawer.sigmaSpinBox_X, 'y': self._drawer.sigmaSpinBox_Y, 'z': self._drawer.sigmaSpinBox_Z } self._allWatchedWidgets = self._sigmaSpinBoxes.values() + \ [ self._drawer.inputChannelSpinBox, self._drawer.lowThresholdSpinBox, self._drawer.highThresholdSpinBox, self._drawer.thresholdSpinBox, self._drawer.minSizeSpinBox, self._drawer.maxSizeSpinBox ] for widget in self._allWatchedWidgets: # If the user pressed enter inside a spinbox, auto-click "Apply" widget.installEventFilter(self) self._drawer.showDebugCheckbox.stateChanged.connect( self._onShowDebugChanged) self._showDebug = False self._updateGuiFromOperator() self.topLevelOperatorView.InputImage.notifyReady( bind(self._updateGuiFromOperator)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.InputImage.unregisterUnready, bind(self._updateGuiFromOperator))) self.topLevelOperatorView.InputImage.notifyMetaChanged( bind(self._updateGuiFromOperator)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.InputImage.unregisterMetaChanged, bind(self._updateGuiFromOperator))) # check if the data is 2D. If so, hide the z-sigma if self.topLevelOperatorView.InputImage.ready(): tShape = self.topLevelOperatorView.InputImage.meta.getTaggedShape() if not 'z' in tShape or tShape['z'] == 1: self._drawer.sigmaSpinBox_Z.setVisible(False)
def __init__(self, topLevelOperator, projectFileGroupName): super( FeatureSelectionSerializer, self ).__init__( projectFileGroupName) self.topLevelOperator = topLevelOperator self._dirty = False def handleDirty(): if not self.ignoreDirty: self._dirty = True self.topLevelOperator.Scales.notifyDirty( bind(handleDirty) ) self.topLevelOperator.FeatureIds.notifyDirty( bind(handleDirty) ) self.topLevelOperator.SelectionMatrix.notifyDirty( bind(handleDirty) )
def __init__(self, mainOperator, projectFileGroupName): super(FeatureSelectionSerializer, self).__init__(projectFileGroupName, self.SerializerVersion) self.mainOperator = mainOperator self._dirty = False def handleDirty(): self._dirty = True self.mainOperator.Scales.notifyDirty(bind(handleDirty)) self.mainOperator.FeatureIds.notifyDirty(bind(handleDirty)) self.mainOperator.SelectionMatrix.notifyDirty(bind(handleDirty))
def __init__(self, dataSelectionOperator, serializer, guiControlSignal, guiMode=GuiMode.Normal, title="Input Selection"): with Tracer(traceLogger): super(DataSelectionGui, self).__init__() self.title = title self.drawer = None self.topLevelOperator = dataSelectionOperator self.guiMode = guiMode self.serializer = serializer self.guiControlSignal = guiControlSignal self.threadRouter = ThreadRouter(self) self.initAppletDrawerUic() self.initCentralUic() def handleNewDataset( multislot, index, finalSize): # Subtlety here: This if statement is needed due to the fact that # This code is hit twice on startup: Once in response to a ImageName resize # (during construction) and once for Dataset resize. if self.fileInfoTableWidget.rowCount() < finalSize: assert multislot == self.topLevelOperator.Dataset # Make room in the table self.fileInfoTableWidget.insertRow( index ) # Update the table row data when this slot has new data # We can't bind in the row here because the row may change in the meantime. self.topLevelOperator.Dataset[index].notifyDirty( self.updateTableForSlot ) self.topLevelOperator.Dataset.notifyInserted( bind( handleNewDataset ) ) # For each dataset that already exists, update the GUI for i, subslot in enumerate(self.topLevelOperator.Dataset): handleNewDataset( self.topLevelOperator.Dataset, i, len(self.topLevelOperator.Dataset) ) if subslot.ready(): self.updateTableForSlot(subslot) def handleDatasetRemoved( multislot, index, finalLength ): assert multislot == self.topLevelOperator.Dataset if self.fileInfoTableWidget.rowCount() > finalLength: # Remove the row we don't need any more self.fileInfoTableWidget.removeRow( index ) def handleImageRemoved(multislot, index, finalLength): # Remove the viewer for this dataset imageSlot = self.topLevelOperator.Image[index] if imageSlot in self.volumeEditors.keys(): editor = self.volumeEditors[imageSlot] self.viewerStack.removeWidget( editor ) editor.stopAndCleanUp() self.topLevelOperator.Dataset.notifyRemove( bind( handleDatasetRemoved ) ) self.topLevelOperator.Image.notifyRemove( bind( handleImageRemoved ) )
def __init__(self, topLevelOperatorView, applet): """ """ self.topLevelOperatorView = topLevelOperatorView super(FeatureSelectionGui, self).__init__(topLevelOperatorView, crosshair=False) self.applet = applet self.topLevelOperatorView.SelectionMatrix.notifyDirty( bind(self.onFeaturesSelectionsChanged) ) self.topLevelOperatorView.FeatureListFilename.notifyDirty( bind(self.onFeaturesSelectionsChanged) ) self.onFeaturesSelectionsChanged() # Init feature dialog self.initFeatureDlg()
def initAppletDrawerUi(self): """ Reimplemented from LayerViewerGui base class. """ # Load the ui file (find it in our own directory) localDir = os.path.split(__file__)[0] self._drawer = uic.loadUi(localDir + "/drawer.ui") self._drawer.methodComboBox.addItem("Simple") self._drawer.methodComboBox.addItem("Hysteresis") if _has_graphcut: self._drawer.methodComboBox.addItem("Graph Cut") self._sigmaSpinBoxes = { 'x': self._drawer.sigmaSpinBox_X, 'y': self._drawer.sigmaSpinBox_Y, 'z': self._drawer.sigmaSpinBox_Z } self._allWatchedWidgets = list(self._sigmaSpinBoxes.values()) + \ [ self._drawer.inputChannelComboBox, self._drawer.coreChannelComboBox, self._drawer.lowThresholdSpinBox, self._drawer.highThresholdSpinBox, self._drawer.minSizeSpinBox, self._drawer.maxSizeSpinBox, self._drawer.lambdaSpinBoxGC ] for widget in self._allWatchedWidgets: # If the user pressed enter inside a spinbox, auto-click "Apply" widget.installEventFilter(self) self._drawer.showDebugCheckbox.stateChanged.connect( self._onShowDebugChanged) self._showDebug = False self._updateGuiFromOperator() self.topLevelOperatorView.InputChannelColors.notifyReady( bind(self._updateGuiFromOperator)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.InputImage.unregisterUnready, bind(self._updateGuiFromOperator))) self.topLevelOperatorView.InputChannelColors.notifyMetaChanged( bind(self._updateGuiFromOperator)) self.__cleanup_fns.append( partial(self.topLevelOperatorView.InputImage.unregisterMetaChanged, bind(self._updateGuiFromOperator)))
def __init__(self, parent, topLevelOperator, roleIndex): """ :param topLevelOperator: An instance of OpMultiLaneDataSelectionGroup """ # super does not work here in Python 2.x, decorated class confuses it QAbstractItemModel.__init__(self, parent) self._op = topLevelOperator self._roleIndex = roleIndex def handleNewLane( multislot, laneIndex): assert multislot is self._op.DatasetGroup self.beginInsertRows( QModelIndex(), laneIndex, laneIndex ) self.endInsertRows() def handleDatasetInfoChanged(slot): # Get the row of this slot laneSlot = slot.operator if laneSlot is None or laneSlot.operator is None: # This can happen during disconnect return try: laneIndex = laneSlot.operator.index( laneSlot ) except ValueError: # If the slot doesn't exist in the lane, # then this dataset is in the process of being removed. return firstIndex = self.createIndex(laneIndex, 0) lastIndex = self.createIndex(laneIndex, self.columnCount()-1) self.dataChanged.emit(firstIndex, lastIndex) def handleNewDatasetInserted(slot, index): if index == self._roleIndex: datasetMultiSlot[self._roleIndex].notifyDirty( bind(handleDatasetInfoChanged) ) datasetMultiSlot[self._roleIndex].notifyDisconnect( bind(handleDatasetInfoChanged) ) for laneIndex, datasetMultiSlot in enumerate( self._op.DatasetGroup ): datasetMultiSlot.notifyInserted( bind(handleNewDatasetInserted) ) if self._roleIndex < len(datasetMultiSlot): handleNewDatasetInserted(datasetMultiSlot, self._roleIndex) self._op.DatasetGroup.notifyInserted( bind(handleNewLane) ) def handleLaneRemoved( multislot, laneIndex ): assert multislot is self._op.DatasetGroup self.beginRemoveRows( QModelIndex(), laneIndex, laneIndex ) self.endRemoveRows() self._op.DatasetGroup.notifyRemoved( bind(handleLaneRemoved) ) # Any lanes that already exist must be added now. for laneIndex, slot in enumerate(self._op.DatasetGroup): handleNewLane( self._op.DatasetGroup, laneIndex )
def __init__(self, parentApplet, croppingSlots, topLevelOperatorView, drawerUiPath=None, rawInputSlot=None, crosshair=True): """ Constructor. :param croppingSlots: Provides the slots needed for sourcing/sinking crop data. See CroppingGui.CroppingSlots class source for details. :param topLevelOperatorView: is provided to the LayerViewerGui (the base class) :param drawerUiPath: can be given if you provide an extended drawer UI file. Otherwise a default one is used. :param rawInputSlot: Data from the rawInputSlot parameter will be displayed directly underneath the elements (if provided). """ # Do we have all the slots we need? assert isinstance(croppingSlots, CroppingGui.CroppingSlots) assert croppingSlots.cropInput is not None, "Missing a required slot." assert croppingSlots.cropOutput is not None, "Missing a required slot." assert croppingSlots.cropEraserValue is not None, "Missing a required slot." assert croppingSlots.cropDelete is not None, "Missing a required slot." assert croppingSlots.cropNames is not None, "Missing a required slot." assert croppingSlots.cropsAllowed is not None, "Missing a required slot." self.__cleanup_fns = [] self._croppingSlots = croppingSlots self._minCropNumber = 0 self._maxCropNumber = 99 #100 or 255 is reserved for eraser self._rawInputSlot = rawInputSlot self.topLevelOperatorView.Crops.notifyDirty( bind(self._updateCropList) ) self.topLevelOperatorView.Crops.notifyDirty( bind(self._updateCropList) ) self.__cleanup_fns.append( partial( self.topLevelOperatorView.Crops.unregisterDirty, bind(self._updateCropList) ) ) self._colorTable16 = colortables.default16_new self._programmaticallyRemovingCrops = False self._initCropUic(drawerUiPath) self._maxCropNumUsed = 0 self._allowDeleteLastCropOnly = False self.__initShortcuts() # Init base class super(CroppingGui, self).__init__(parentApplet, topLevelOperatorView, [croppingSlots.cropInput, croppingSlots.cropOutput], crosshair=crosshair) self._croppingSlots.cropEraserValue.setValue(self.editor.brushingModel.erasingNumber) # Register for thunk events (easy UI calls from non-GUI threads) self.thunkEventHandler = ThunkEventHandler(self)
def __init__(self, labelingSlots, topLevelOperatorView, drawerUiPath=None, rawInputSlot=None, crosshair=True): """ Constructor. :param labelingSlots: Provides the slots needed for sourcing/sinking label data. See LabelingGui.LabelingSlots class source for details. :param topLevelOperatorView: is provided to the LayerViewerGui (the base class) :param drawerUiPath: can be given if you provide an extended drawer UI file. Otherwise a default one is used. :param rawInputSlot: Data from the rawInputSlot parameter will be displayed directly underneath the elements (if provided). """ # Do have have all the slots we need? assert isinstance(labelingSlots, LabelingGui.LabelingSlots) assert all( [v is not None for v in labelingSlots.__dict__.values()] ) self.__cleanup_fns = [] self._labelingSlots = labelingSlots self._minLabelNumber = 0 self._maxLabelNumber = 99 #100 or 255 is reserved for eraser self._rawInputSlot = rawInputSlot self._labelingSlots.maxLabelValue.notifyDirty( bind(self._updateLabelList) ) self.__cleanup_fns.append( partial( self._labelingSlots.maxLabelValue.unregisterDirty, bind(self._updateLabelList) ) ) if self._labelingSlots.LabelNames is not None: self._labelingSlots.LabelNames.notifyDirty( bind(self._updateLabelList) ) self.__cleanup_fns.append( partial( self._labelingSlots.LabelNames.unregisterDirty, bind(self._updateLabelList) ) ) self._colorTable16 = self._createDefault16ColorColorTable() self._programmaticallyRemovingLabels = False if drawerUiPath is None: # Default ui file drawerUiPath = os.path.split(__file__)[0] + '/labelingDrawer.ui' self._initLabelUic(drawerUiPath) # Init base class super(LabelingGui, self).__init__(topLevelOperatorView, [labelingSlots.labelInput, labelingSlots.labelOutput], crosshair=crosshair) self.__initShortcuts() self._labelingSlots.labelEraserValue.setValue(self.editor.brushingModel.erasingNumber) # Register for thunk events (easy UI calls from non-GUI threads) self.thunkEventHandler = ThunkEventHandler(self) self._changeInteractionMode(Tool.Navigation)
def __init__(self, parent, topLevelOperator, roleIndex): """ :param topLevelOperator: An instance of OpMultiLaneDataSelectionGroup """ super(DatasetDetailedInfoTableModel, self).__init__(parent) self._op = topLevelOperator self._roleIndex = roleIndex def handleNewLane(multislot, laneIndex): assert multislot is self._op.DatasetGroup self.beginInsertRows(QModelIndex(), laneIndex, laneIndex) self.endInsertRows() def handleDatasetInfoChanged(slot): # Get the row of this slot laneSlot = slot.operator if laneSlot is None or laneSlot.operator is None: # This can happen during disconnect return laneIndex = laneSlot.operator.index(laneSlot) firstIndex = self.createIndex(laneIndex, 0) lastIndex = self.createIndex(laneIndex, self.columnCount() - 1) self.dataChanged.emit(firstIndex, lastIndex) def handleNewDatasetInserted(slot, index): if index == self._roleIndex: datasetMultiSlot[self._roleIndex].notifyDirty( bind(handleDatasetInfoChanged)) datasetMultiSlot[self._roleIndex].notifyDisconnect( bind(handleDatasetInfoChanged)) for laneIndex, datasetMultiSlot in enumerate( self._op.DatasetGroup): datasetMultiSlot.notifyInserted(bind(handleNewDatasetInserted)) if self._roleIndex < len(datasetMultiSlot): handleNewDatasetInserted(datasetMultiSlot, self._roleIndex) self._op.DatasetGroup.notifyInserted(bind(handleNewLane)) def handleLaneRemoved(multislot, laneIndex): assert multislot is self._op.DatasetGroup self.beginRemoveRows(QModelIndex(), laneIndex, laneIndex) self.endRemoveRows() self._op.DatasetGroup.notifyRemoved(bind(handleLaneRemoved)) # Any lanes that already exist must be added now. for laneIndex, slot in enumerate(self._op.DatasetGroup): handleNewLane(self._op.DatasetGroup, laneIndex)
def updateTableForSlot(self, slot): """ Update the table row that corresponds to the given slot of the top-level operator (could be either input slot) """ row = self.getSlotIndex( self.topLevelOperator.ExportPath, slot ) assert row != -1, "Unknown input slot!" if not self.topLevelOperator.ExportPath[row].ready() or\ not self.topLevelOperator.RawDatasetInfo[row].ready(): return try: nickname = self.topLevelOperator.RawDatasetInfo[row].value.nickname exportPath = self.topLevelOperator.ExportPath[row].value except Slot.SlotNotReadyError: # Sadly, it is possible to get here even though we checked for .ready() immediately beforehand. # That's because the graph has a diamond-shaped DAG of connections, but the graph has no transaction mechanism # (It's therefore possible for RawDatasetInfo[row] to be ready() even though it's upstream partner is NOT ready. return self.batchOutputTableWidget.setItem( row, Column.Dataset, QTableWidgetItem(nickname) ) self.batchOutputTableWidget.setItem( row, Column.ExportLocation, QTableWidgetItem( exportPath ) ) exportNowButton = QPushButton("Export") exportNowButton.setToolTip("Generate individual batch output dataset.") exportNowButton.clicked.connect( bind(self.exportResultsForSlot, self.topLevelOperator[row] ) ) self.batchOutputTableWidget.setCellWidget( row, Column.Action, exportNowButton ) # Select a row if there isn't one already selected. selectedRanges = self.batchOutputTableWidget.selectedRanges() if len(selectedRanges) == 0: self.batchOutputTableWidget.selectRow(0)
def handleNewLane(multislot, laneIndex): assert multislot is self._op.DatasetGroup self.beginInsertRows(QModelIndex(), laneIndex, laneIndex) self.endInsertRows() def handleDatasetInfoChanged(slot): # Get the row of this slot laneSlot = slot.operator if laneSlot is None or laneSlot.operator is None: # This can happen during disconnect return laneIndex = laneSlot.operator.index(laneSlot) firstIndex = self.createIndex(laneIndex, 0) lastIndex = self.createIndex(laneIndex, self.columnCount() - 1) self.dataChanged.emit(firstIndex, lastIndex) def handleNewDatasetInserted(slot, index): if index == self._roleIndex: datasetMultiSlot[self._roleIndex].notifyDirty( bind(handleDatasetInfoChanged)) datasetMultiSlot[self._roleIndex].notifyDisconnect( bind(handleDatasetInfoChanged)) for laneIndex, datasetMultiSlot in enumerate( self._op.DatasetGroup): datasetMultiSlot.notifyInserted(bind(handleNewDatasetInserted)) if self._roleIndex < len(datasetMultiSlot): handleNewDatasetInserted(datasetMultiSlot, self._roleIndex)
def __init__(self, mainOperator, projectFileGroupName): super( BatchIoSerializer, self ).__init__( projectFileGroupName, self.SerializerVersion ) self.mainOperator = mainOperator self._dirty = False def handleDirty(): self._dirty = True self.mainOperator.ExportDirectory.notifyDirty( bind(handleDirty) ) self.mainOperator.Format.notifyDirty( bind(handleDirty) ) self.mainOperator.Suffix.notifyDirty( bind(handleDirty) ) def handleNewDataset(slot, index): slot[index].notifyDirty( bind(handleDirty) ) # DatasetPath is a multi-slot, so subscribe to dirty callbacks on each slot as it is added self.mainOperator.DatasetPath.notifyInserted( bind(handleNewDataset) )
def updateTableForSlot(self, slot): """ Update the table row that corresponds to the given slot of the top-level operator (could be either input slot) """ row = self.getSlotIndex( self.topLevelOperator.ExportPath, slot ) assert row != -1, "Unknown input slot!" if not self.topLevelOperator.ExportPath[row].ready() or\ not self.topLevelOperator.RawDatasetInfo[row].ready(): return try: nickname = self.topLevelOperator.RawDatasetInfo[row].value.nickname exportPath = self.topLevelOperator.ExportPath[row].value except Slot.SlotNotReadyError: # Sadly, it is possible to get here even though we checked for .ready() immediately beforehand. # That's because the graph has a diamond-shaped DAG of connections, but the graph has no transaction mechanism # (It's therefore possible for RawDatasetInfo[row] to be ready() even though it's upstream partner is NOT ready. return self.batchOutputTableWidget.setItem( row, Column.Dataset, QTableWidgetItem( decode_to_qstring(nickname, 'utf-8') ) ) self.batchOutputTableWidget.setItem( row, Column.ExportLocation, QTableWidgetItem( decode_to_qstring(exportPath) ) ) exportNowButton = QPushButton("Export") exportNowButton.setToolTip("Generate individual batch output dataset.") exportNowButton.clicked.connect( bind(self.exportResultsForSlot, self.topLevelOperator[row] ) ) self.batchOutputTableWidget.setCellWidget( row, Column.Action, exportNowButton ) # Select a row if there isn't one already selected. selectedRanges = self.batchOutputTableWidget.selectedRanges() if len(selectedRanges) == 0: self.batchOutputTableWidget.selectRow(0)
def exportResultsForSlot(self, slot, progressSlot): with Tracer(traceLogger): # Do this in a separate thread so the UI remains responsive exportThread = threading.Thread(target=bind( self.exportSlots, [slot], [progressSlot]), name="BatchIOExportThread") exportThread.start()
def handleNewDataset(multislot, index): # Make room in the GUI table self.tableWidget.insertRow(index) # Update the table row data when this slot has new data # We can't bind in the row here because the row may change in the meantime. multislot[index].notifyDirty(bind(self.updateTableForSlot))
def _ensurePipelineExists(self, block_start): if block_start in self._blockPipelines: return with self._lock: if block_start in self._blockPipelines: return logger.debug("Creating pipeline for block: {}".format(block_start)) block_shape = self._getFullShape(self._block_shape_dict) halo_padding = self._getFullShape(self._halo_padding_dict) input_shape = self.RawImage.meta.shape block_stop = getBlockBounds(input_shape, block_shape, block_start)[1] block_roi = (block_start, block_stop) # Instantiate pipeline opBlockPipeline = OpSingleBlockObjectPrediction(block_roi, halo_padding, parent=self) opBlockPipeline.RawImage.connect(self.RawImage) opBlockPipeline.BinaryImage.connect(self.BinaryImage) opBlockPipeline.Classifier.connect(self.Classifier) opBlockPipeline.LabelsCount.connect(self.LabelsCount) opBlockPipeline.SelectedFeatures.connect(self.SelectedFeatures) # Forward dirtyness opBlockPipeline.PredictionImage.notifyDirty( bind(self._handleDirtyBlock, block_start)) self._blockPipelines[block_start] = opBlockPipeline
def exportAllResults(self): # Do this in a separate thread so the UI remains responsive exportThread = threading.Thread(target=bind( self.exportSlots, self.topLevelOperator.ExportResult, self.topLevelOperator.ProgressSignal), name="BatchIOExportThread") exportThread.start()
def __init__(self, topLevelOperatorView, shellRequestSignal, predictionSerializer): # Tell our base class which slots to monitor labelSlots = LabelingGui.LabelingSlots() labelSlots.labelInput = topLevelOperatorView.LabelInputs labelSlots.labelOutput = topLevelOperatorView.LabelImages labelSlots.labelEraserValue = topLevelOperatorView.opLabelArray.eraser labelSlots.labelDelete = topLevelOperatorView.opLabelArray.deleteLabel labelSlots.maxLabelValue = topLevelOperatorView.MaxLabelValue # We provide our own UI file (which adds an extra control for interactive mode) labelingDrawerUiPath = os.path.split( __file__)[0] + '/labelingDrawer.ui' # Base class init super(AutocontextClassificationGui, self).__init__(labelSlots, topLevelOperatorView, labelingDrawerUiPath) self.topLevelOperatorView = topLevelOperatorView self.shellRequestSignal = shellRequestSignal self.predictionSerializer = predictionSerializer self.interactiveModeActive = False self._currentlySavingPredictions = False self.labelingDrawerUi.savePredictionsButton.clicked.connect( self.onSavePredictionsButtonClicked) self.labelingDrawerUi.savePredictionsButton.setIcon( QIcon(ilastikIcons.Save)) self.topLevelOperatorView.MaxLabelValue.notifyDirty( bind(self.handleLabelSelectionChange))
def updateInternalPathComboBox( self, row, externalPath, internalPath ): with Tracer(traceLogger): combo = QComboBox() datasetNames = [] # Make sure we're dealing with the absolute path (to make this simple) absPath, relPath = getPathVariants(externalPath, self.mainOperator.WorkingDirectory.value) ext = os.path.splitext(absPath)[1] h5Exts = ['.ilp', '.h5', '.hdf5'] if ext in h5Exts: datasetNames = self.getPossibleInternalPaths(absPath) # Add each dataset option to the combo for path in datasetNames: combo.addItem( path ) # If the internal path we used previously is in the combo list, select it. prevSelection = combo.findText( internalPath ) if prevSelection != -1: combo.setCurrentIndex( prevSelection ) # Define response to changes and add it to the GUI. # Pass in the corresponding the table item so we can figure out which row this came from combo.currentIndexChanged.connect( bind(self.handleComboSelectionChanged, combo) ) self.fileInfoTableWidget.setCellWidget( row, Column.InternalID, combo )
def _ensurePipelineExists(self, block_start): if block_start in self._blockPipelines: return with self._lock: if block_start in self._blockPipelines: return logger.debug( "Creating pipeline for block: {}".format( block_start ) ) block_shape = self._getFullShape( self._block_shape_dict ) halo_padding = self._getFullShape( self._halo_padding_dict ) input_shape = self.RawImage.meta.shape block_stop = getBlockBounds( input_shape, block_shape, block_start )[1] block_roi = (block_start, block_stop) # Instantiate pipeline opBlockPipeline = OpSingleBlockObjectPrediction( block_roi, halo_padding, parent=self ) opBlockPipeline.RawImage.connect( self.RawImage ) opBlockPipeline.BinaryImage.connect( self.BinaryImage ) opBlockPipeline.Classifier.connect( self.Classifier ) opBlockPipeline.LabelsCount.connect( self.LabelsCount ) # Forward dirtyness opBlockPipeline.PredictionImage.notifyDirty( bind(self._handleDirtyBlock, block_start ) ) self._blockPipelines[block_start] = opBlockPipeline
def __init__(self, dataSelectionOperator, serializer, guiControlSignal, guiMode=GuiMode.Normal, title="Input Selection"): with Tracer(traceLogger): super(DataSelectionGui, self).__init__() self.title = title self._viewerControls = QWidget() self.topLevelOperator = dataSelectionOperator self.guiMode = guiMode self.serializer = serializer self.guiControlSignal = guiControlSignal self.threadRouter = ThreadRouter(self) self._initCentralUic() self._initAppletDrawerUic() self._viewerControlWidgetStack = QStackedWidget(self) def handleImageRemoved(multislot, index, finalLength): # Remove the viewer for this dataset imageSlot = self.topLevelOperator.Image[index] if imageSlot in self.volumeEditors.keys(): editor = self.volumeEditors[imageSlot] self.viewerStack.removeWidget( editor ) self._viewerControlWidgetStack.removeWidget( editor.viewerControlWidget() ) editor.stopAndCleanUp() self.topLevelOperator.Image.notifyRemove( bind( handleImageRemoved ) )