def setupLayers(self): mainOperator = self.topLevelOperatorView layers = [] if mainOperator.ObjectCenterImage.ready(): self.centerimagesrc = LazyflowSource(mainOperator.ObjectCenterImage) redct = [0, QColor(255, 0, 0).rgba()] layer = ColortableLayer(self.centerimagesrc, redct) layer.name = "Object centers" layer.setToolTip("Object center positions, marked with a little red cross") layer.visible = False layers.append(layer) ct = colortables.create_default_16bit() if mainOperator.LabelImage.ready(): self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Objects (connected components)" layer.setToolTip("Segmented objects, shown in different colors") layer.visible = False layer.opacity = 0.5 layers.append(layer) # white foreground on transparent background, even for labeled images binct = [QColor(255, 255, 255, 255).rgba()]*65536 binct[0] = 0 if mainOperator.BinaryImage.ready(): self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, binct) layer.name = "Binary image" layer.setToolTip("Segmented objects, binary mask") layers.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" layers.insert(len(layers), layerraw) mainOperator.RawImage.notifyReady(self._onReady) self.__cleanup_fns.append( partial( mainOperator.RawImage.unregisterReady, self._onReady ) ) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial( mainOperator.RawImage.unregisterMetaChanged, self._onMetaChanged ) ) if mainOperator.BinaryImage.meta.shape: self.editor.dataShape = mainOperator.BinaryImage.meta.shape mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial( mainOperator.BinaryImage.unregisterMetaChanged, self._onMetaChanged ) ) return layers
def addCCOperator(self): self.opCC = OpConnectedComponents(self.g) self.opCC.inputs["Input"].connect(self.opThreshold.outputs["Output"]) #we shouldn't have to define these. But just in case... self.opCC.inputs["Neighborhood"].setValue(6) self.opCC.inputs["Background"].setValue(0) ccsrc = LazyflowSource(self.opCC.outputs["Output"][0]) ccsrc.setObjectName("Connected Components") ctb = colortables.create_default_16bit() ctb.insert(0, QColor(0, 0, 0, 0).rgba()) # make background transparent ccLayer = ColortableLayer(ccsrc, ctb) ccLayer.name = "Connected Components" self.layerstack.insert(1, ccLayer)
def setupLayers(self): mainOperator = self.topLevelOperatorView layers = [] if mainOperator.ObjectCenterImage.ready(): self.centerimagesrc = LazyflowSource(mainOperator.ObjectCenterImage) #layer = RGBALayer(red=ConstantSource(255), alpha=self.centerimagesrc) redct = [0, QColor(255, 0, 0).rgba()] layer = ColortableLayer(self.centerimagesrc, redct) layer.name = "Object Centers" layer.visible = False layers.append(layer) ct = colortables.create_default_16bit() if mainOperator.LabelImage.ready(): self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Label Image" layer.visible = False layer.opacity = 0.5 layers.append(layer) # white foreground on transparent background binct = [QColor(0, 0, 0, 0).rgba(), QColor(255, 255, 255, 255).rgba()] if mainOperator.BinaryImage.ready(): self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, binct) layer.name = "Binary Image" layers.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" layers.insert(len(layers), layerraw) mainOperator.RawImage.notifyReady(self._onReady) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) if mainOperator.BinaryImage.meta.shape: self.editor.dataShape = mainOperator.BinaryImage.meta.shape mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) return layers
def _onReady(self, slot): if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" self.layerstack.append(layerraw)
def _onMetaChanged(self, slot): if slot is self.mainOperator.BinaryImage: if slot.meta.shape: self.editor.dataShape = slot.meta.shape if slot is self.mainOperator.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.mainOperator.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.append(layerraw)
def addThresholdOperator(self): if self.opThreshold is None: self.opThreshold = OpThreshold(self.g) self.opThreshold.inputs["Input"].connect(self.pCache.outputs["Output"]) #channel, value = ThresholdDlg(self.labelListModel._labels) channel = 0 value = 0.5 ref_label = self.labelListModel._labels[channel] self.opThreshold.inputs["Channel"].setValue(channel) self.opThreshold.inputs["Threshold"].setValue(value) threshsrc = LazyflowSource(self.opThreshold.outputs["Output"][0]) threshsrc.setObjectName("Threshold for %s" % ref_label.name) transparent = QColor(0,0,0,0) white = QColor(255,255,255) colorTable = [transparent.rgba(), white.rgba()] threshLayer = ColortableLayer(threshsrc, colorTable = colorTable ) threshLayer.name = "Threshold for %s" % ref_label.name self.layerstack.insert(1, threshLayer) self.CCButton.setEnabled(True)
def _onMetaChanged(self, slot): #FiXME: why do we need that? if slot is self.topLevelOperatorView.BinaryImage: if slot.meta.shape: self.editor.dataShape = slot.meta.shape if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" self.layerstack.append(layerraw)
class ObjectExtractionGui(QWidget): ########################################### ### AppletGuiInterface Concrete Methods ### ########################################### def centralWidget(self): """ Return the widget that will be displayed in the main viewer area. """ return self.volumeEditorWidget def appletDrawer(self): return self._drawer def menus(self): return [] def viewerControlWidget(self): return self._viewerControlWidget def stopAndCleanUp(self): pass ########################################### ########################################### def __init__(self, topLevelOperatorView): super(ObjectExtractionGui, self).__init__() self.mainOperator = topLevelOperatorView self.layerstack = LayerStackModel() self._viewerControlWidget = None self._initViewerControlUi() self.editor = None self._initEditor() self._initAppletDrawerUi() assert(self.appletDrawer() is not None) self._initViewer() def _onMetaChanged(self, slot): if slot is self.mainOperator.BinaryImage: if slot.meta.shape: self.editor.dataShape = slot.meta.shape if slot is self.mainOperator.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.mainOperator.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.append(layerraw) def _onReady(self, slot): if slot is self.mainOperator.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.mainOperator.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.append(layerraw) def _initViewer(self): mainOperator = self.mainOperator # white foreground on transparent background ct = [QColor(0, 0, 0, 0).rgba(), QColor(255, 255, 255, 255).rgba()] self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, ct) layer.name = "Binary Image" self.layerstack.append(layer) ct = colortables.create_default_16bit() self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Label Image" layer.visible = False layer.opacity = 0.5 self.layerstack.append(layer) self.centerimagesrc = LazyflowSource(mainOperator.ObjectCenterImage) layer = RGBALayer(red=ConstantSource(255), alpha=self.centerimagesrc) layer.name = "Object Centers" layer.visible = False self.layerstack.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(self.mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.insert(len(self.layerstack), layerraw) mainOperator.RawImage.notifyReady(self._onReady) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) if mainOperator.BinaryImage.meta.shape: self.editor.dataShape = mainOperator.BinaryImage.meta.shape mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) def _initEditor(self): """Initialize the Volume Editor GUI.""" self.editor = VolumeEditor(self.layerstack, crosshair=False) self.volumeEditorWidget = VolumeEditorWidget() self.volumeEditorWidget.init(self.editor) # The editor's layerstack is in charge of which layer movement buttons are enabled model = self.editor.layerStack model.canMoveSelectedUp.connect(self._viewerControlWidget.UpButton.setEnabled) model.canMoveSelectedDown.connect(self._viewerControlWidget.DownButton.setEnabled) model.canDeleteSelected.connect(self._viewerControlWidget.DeleteButton.setEnabled) # Connect our layer movement buttons to the appropriate layerstack actions self._viewerControlWidget.layerWidget.init(model) self._viewerControlWidget.UpButton.clicked.connect(model.moveSelectedUp) self._viewerControlWidget.DownButton.clicked.connect(model.moveSelectedDown) self._viewerControlWidget.DeleteButton.clicked.connect(model.deleteSelected) self.editor._lastImageViewFocus = 0 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") self._drawer.calculateFeaturesButton.pressed.connect(self._calculateFeaturesButtonPressed) def _initViewerControlUi(self): p = os.path.split(__file__)[0]+'/' if p == "/": p = "."+p self._viewerControlWidget = uic.loadUi(p+"viewerControls.ui") def _calculateFeaturesButtonPressed(self): maxt = self.mainOperator.LabelImage.meta.shape[0] progress = QProgressDialog("Calculating featuers...", "Stop", 0, maxt) progress.setWindowModality(Qt.ApplicationModal) progress.setMinimumDuration(0) progress.setCancelButtonText(QString()) reqs = [] self.mainOperator._opRegFeats.fixed = False for t in range(maxt): reqs.append(self.mainOperator.RegionFeatures([t])) reqs[-1].submit() for i, req in enumerate(reqs): progress.setValue(i) if progress.wasCanceled(): req.cancel() else: req.wait() self.mainOperator._opRegFeats.fixed = True progress.setValue(maxt) self.mainOperator.ObjectCenterImage.setDirty(SubRegion(self.mainOperator.ObjectCenterImage)) print 'Object Extraction: done.'
class ObjectExtractionGui(LayerViewerGui): def setupLayers(self): mainOperator = self.topLevelOperatorView layers = [] if mainOperator.ObjectCenterImage.ready(): self.centerimagesrc = LazyflowSource(mainOperator.ObjectCenterImage) #layer = RGBALayer(red=ConstantSource(255), alpha=self.centerimagesrc) redct = [0, QColor(255, 0, 0).rgba()] layer = ColortableLayer(self.centerimagesrc, redct) layer.name = "Object Centers" layer.visible = False layers.append(layer) ct = colortables.create_default_16bit() if mainOperator.LabelImage.ready(): self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Label Image" layer.visible = False layer.opacity = 0.5 layers.append(layer) # white foreground on transparent background binct = [QColor(0, 0, 0, 0).rgba(), QColor(255, 255, 255, 255).rgba()] if mainOperator.BinaryImage.ready(): self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, binct) layer.name = "Binary Image" layers.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" layers.insert(len(layers), layerraw) mainOperator.RawImage.notifyReady(self._onReady) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) if mainOperator.BinaryImage.meta.shape: self.editor.dataShape = mainOperator.BinaryImage.meta.shape mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) return layers def _onMetaChanged(self, slot): #FiXME: why do we need that? if slot is self.topLevelOperatorView.BinaryImage: if slot.meta.shape: self.editor.dataShape = slot.meta.shape if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.append(layerraw) def _onReady(self, slot): if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.append(layerraw) 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") self._drawer.selectFeaturesButton.pressed.connect(self._selectFeaturesButtonPressed) def _selectFeaturesButtonPressed(self): featureDict = {} mainOperator = self.topLevelOperatorView slot = mainOperator.Features if slot.ready(): selectedFeatures = mainOperator.Features([]).wait() else: selectedFeatures = None plugins = pluginManager.getPluginsOfCategory('ObjectFeatures') imgshape = list(mainOperator.RawImage.meta.shape) axistags = mainOperator.RawImage.meta.axistags imgshape.pop(axistags.index('t')) fakeimg = np.empty(imgshape, dtype=np.float32) labelshape = list(mainOperator.BinaryImage.meta.shape) axistags = mainOperator.BinaryImage.meta.axistags labelshape.pop(axistags.index('t')) labelshape.pop(axistags.index('c') - 1) fakelabels = np.empty(labelshape, dtype=np.uint32) ndim = 3 zIndex = axistags.index('z') if len(labelshape)==2 or (zIndex<len(mainOperator.RawImage.meta.shape) and mainOperator.RawImage.meta.shape[zIndex]==1): ndim=2 for pluginInfo in plugins: featureDict[pluginInfo.name] = pluginInfo.plugin_object.availableFeatures(fakeimg, fakelabels) dlg = FeatureSelectionDialog(featureDict=featureDict, selectedFeatures=selectedFeatures, ndim=ndim) dlg.exec_() if dlg.result() == QDialog.Accepted: mainOperator.Features.setValue(dlg.selectedFeatures) self._calculateFeatures() def _calculateFeatures(self): mainOperator = self.topLevelOperatorView mainOperator.ObjectCenterImage.setDirty(SubRegion(mainOperator.ObjectCenterImage)) maxt = mainOperator.LabelImage.meta.shape[0] progress = QProgressDialog("Calculating features...", "Cancel", 0, maxt) progress.setWindowModality(Qt.ApplicationModal) progress.setMinimumDuration(0) progress.setValue(0) # We will use notify_finished() to update the progress bar. # However, the callback will be called from a non-gui thread, # which cannot access gui elements directly. Therefore we use # this callback object to send signals back to this thread. # FIXME: this could probably be done much more easily with threadRouted class Callback(QObject): ndone = 0 timestep_done = pyqtSignal(int) all_finished = pyqtSignal() def __call__(self, *args, **kwargs): self.ndone += 1 self.timestep_done.emit(self.ndone) if self.ndone == len(reqs): self.all_finished.emit() callback = Callback() def updateProgress(progress, n): progress.setValue(n) callback.timestep_done.connect(partial(updateProgress, progress)) def finished(): self.topLevelOperatorView._opRegFeats.fixed = True logger.info('Object Extraction: done.') callback.all_finished.connect(finished) mainOperator._opRegFeats.fixed = False reqs = [] for t in range(maxt): req = mainOperator.RegionFeatures([t]) req.submit() reqs.append(req) for i, req in enumerate(reqs): req.notify_finished(callback) # handle cancel button def cancel(): for req in reqs: req.cancel() progress.canceled.connect(cancel)
def setupLayers(self): layers = [] if "MergerOutput" in self.topLevelOperatorView.outputs: ct = colortables.create_default_8bit() for i in range(7): ct[i] = self.mergerColors[i].rgba() if self.topLevelOperatorView.MergerCachedOutput.ready(): self.mergersrc = LazyflowSource( self.topLevelOperatorView.MergerCachedOutput) else: self.mergersrc = LazyflowSource( self.topLevelOperatorView.ZeroOutput) mergerLayer = ColortableLayer(self.mergersrc, ct) mergerLayer.name = "Merger" mergerLayer.visible = True layers.append(mergerLayer) ct = colortables.create_random_16bit() ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent ct[1] = QColor(128, 128, 128, 255).rgba( ) # misdetections have id 1 and will be indicated by grey if self.topLevelOperatorView.CachedOutput.ready(): self.trackingsrc = LazyflowSource( self.topLevelOperatorView.CachedOutput) trackingLayer = ColortableLayer(self.trackingsrc, ct) trackingLayer.name = "Tracking" trackingLayer.visible = True trackingLayer.opacity = 1.0 layers.append(trackingLayer) elif self.topLevelOperatorView.zeroProvider.Output.ready(): # provide zeros while waiting for the tracking result self.trackingsrc = LazyflowSource( self.topLevelOperatorView.zeroProvider.Output) trackingLayer = ColortableLayer(self.trackingsrc, ct) trackingLayer.name = "Tracking" trackingLayer.visible = True trackingLayer.opacity = 1.0 layers.append(trackingLayer) if self.topLevelOperatorView.LabelImage.ready(): self.objectssrc = LazyflowSource( self.topLevelOperatorView.LabelImage) ct = colortables.create_random_16bit() ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent objLayer = ColortableLayer(self.objectssrc, ct) objLayer.name = "Objects" objLayer.opacity = 1.0 objLayer.visible = True layers.append(objLayer) if self.mainOperator.RawImage.ready(): rawLayer = self.createStandardLayerFromSlot( self.mainOperator.RawImage) rawLayer.name = "Raw" layers.insert(len(layers), rawLayer) if self.topLevelOperatorView.LabelImage.meta.shape: self.editor.dataShape = self.topLevelOperatorView.LabelImage.meta.shape maxt = self.topLevelOperatorView.LabelImage.meta.shape[0] - 1 maxx = self.topLevelOperatorView.LabelImage.meta.shape[1] - 1 maxy = self.topLevelOperatorView.LabelImage.meta.shape[2] - 1 maxz = self.topLevelOperatorView.LabelImage.meta.shape[3] - 1 if not self.mainOperator.Parameters.ready(): raise Exception("Parameter slot is not ready") parameters = self.mainOperator.Parameters.value self._setRanges() if 'size_range' in parameters: self._drawer.to_size.setValue(parameters['size_range'][1] - 1) self._drawer.from_size.setValue(parameters['size_range'][0]) else: self._drawer.from_size.setValue(0) self._drawer.to_size.setValue(10000) if 'x_range' in parameters: self._drawer.to_x.setValue(parameters['x_range'][1] - 1) self._drawer.from_x.setValue(parameters['x_range'][0]) else: self._drawer.from_x.setValue(0) self._drawer.to_x.setValue(maxx) if 'y_range' in parameters: self._drawer.to_y.setValue(parameters['y_range'][1] - 1) self._drawer.from_y.setValue(parameters['y_range'][0]) else: self._drawer.from_y.setValue(0) self._drawer.to_y.setValue(maxy) if 'z_range' in parameters: self._drawer.to_z.setValue(parameters['z_range'][1] - 1) self._drawer.from_z.setValue(parameters['z_range'][0]) else: self._drawer.from_z.setValue(0) self._drawer.to_z.setValue(maxz) if 'time_range' in parameters: self._drawer.to_time.setValue(parameters['time_range'][1]) self._drawer.from_time.setValue(parameters['time_range'][0]) else: self._drawer.from_time.setValue(0) self._drawer.to_time.setValue(maxt) if 'scales' in parameters: self._drawer.x_scale.setValue(parameters['scales'][0]) self._drawer.y_scale.setValue(parameters['scales'][1]) self._drawer.z_scale.setValue(parameters['scales'][2]) else: self._drawer.x_scale.setValue(1) self._drawer.y_scale.setValue(1) self._drawer.z_scale.setValue(1) return layers
def _create_rgba_layer_from_slot(cls, slot, numChannels, lastChannelIsAlpha): bindex = aindex = None rindex, gindex = 0, 1 if numChannels > 3 or (numChannels == 3 and not lastChannelIsAlpha): bindex = 2 if lastChannelIsAlpha: aindex = numChannels - 1 if numChannels >= 2: gindex = 1 if numChannels >= 3: bindex = 2 if numChannels >= 4: aindex = numChannels - 1 redSource = None if rindex is not None: redProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) redProvider.Input.connect(slot) redProvider.Index.setValue(rindex) redSource = LazyflowSource(redProvider.Output) redSource.additional_owned_ops.append(redProvider) greenSource = None if gindex is not None: greenProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) greenProvider.Input.connect(slot) greenProvider.Index.setValue(gindex) greenSource = LazyflowSource(greenProvider.Output) greenSource.additional_owned_ops.append(greenProvider) blueSource = None if bindex is not None: blueProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) blueProvider.Input.connect(slot) blueProvider.Index.setValue(bindex) blueSource = LazyflowSource(blueProvider.Output) blueSource.additional_owned_ops.append(blueProvider) alphaSource = None if aindex is not None: alphaProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) alphaProvider.Input.connect(slot) alphaProvider.Index.setValue(aindex) alphaSource = LazyflowSource(alphaProvider.Output) alphaSource.additional_owned_ops.append(alphaProvider) layer = RGBALayer(red=redSource, green=greenSource, blue=blueSource, alpha=alphaSource) normalize = cls._should_normalize_display(slot) for i in range(4): if [redSource, greenSource, blueSource, alphaSource][i]: layer.set_range(i, slot.meta.drange) layer.set_normalize(i, normalize) return layer
def initGraph(self): shape = self.inputProvider.outputs["Output"].shape srcs = [] minMax = [] print "* Data has shape=%r" % (shape,) #create a layer for each channel of the input: slicer=OpMultiArraySlicer2(self.g) slicer.inputs["Input"].connect(self.inputProvider.outputs["Output"]) slicer.inputs["AxisFlag"].setValue('c') nchannels = shape[-1] for ich in xrange(nchannels): if self._normalize_data: data=slicer.outputs['Slices'][ich][:].allocate().wait() #find the minimum and maximum value for normalization mm = (numpy.min(data), numpy.max(data)) print " - channel %d: min=%r, max=%r" % (ich, mm[0], mm[1]) minMax.append(mm) else: minMax.append(None) layersrc = LazyflowSource(slicer.outputs['Slices'][ich], priority = 100) layersrc.setObjectName("raw data channel=%d" % ich) srcs.append(layersrc) #FIXME: we shouldn't merge channels automatically, but for now it's prettier layer1 = None if nchannels == 1: layer1 = GrayscaleLayer(srcs[0], normalize=minMax[0]) layer1.set_range(0,minMax[0]) print " - showing raw data as grayscale" elif nchannels==2: layer1 = RGBALayer(red = srcs[0], normalizeR=minMax[0], green = srcs[1], normalizeG=minMax[1]) layer1.set_range(0, minMax[0]) layer1.set_range(1, minMax[1]) print " - showing channel 1 as red, channel 2 as green" elif nchannels==3: layer1 = RGBALayer(red = srcs[0], normalizeR=minMax[0], green = srcs[1], normalizeG=minMax[1], blue = srcs[2], normalizeB=minMax[2]) layer1.set_range(0, minMax[0]) layer1.set_range(1, minMax[1]) layer1.set_range(2, minMax[2]) print " - showing channel 1 as red, channel 2 as green, channel 3 as blue" else: print "only 1,2 or 3 channels supported so far" return print layer1.name = "Input data" layer1.ref_object = None self.layerstack.append(layer1) self.workflow = PixelClassificationLazyflow( self.g, self.featScalesList, self.inputProvider.outputs["Output"]) self.initLabels() self.startClassification() self.dataReadyToView.emit()
def setupLayers(self): """ Called by our base class when one of our data slots has changed. This function creates a layer for each slot we want displayed in the volume editor. """ # Base class provides the label layer. layers = super(PixelClassificationGui, self).setupLayers() ActionInfo = ShortcutManager.ActionInfo if ilastik_config.getboolean('ilastik', 'debug'): # Add the label projection layer. labelProjectionSlot = self.topLevelOperatorView.opLabelPipeline.opLabelArray.Projection2D if labelProjectionSlot.ready(): projectionSrc = LazyflowSource(labelProjectionSlot) try: # This colortable requires matplotlib from volumina.colortables import jet projectionLayer = ColortableLayer( projectionSrc, colorTable=[QColor(0, 0, 0, 128).rgba()] + jet(N=255), normalize=(0.0, 1.0)) except (ImportError, RuntimeError): pass else: projectionLayer.name = "Label Projection" projectionLayer.visible = False projectionLayer.opacity = 1.0 layers.append(projectionLayer) # Show the mask over everything except labels maskSlot = self.topLevelOperatorView.PredictionMasks if maskSlot.ready(): maskLayer = self._create_binary_mask_layer_from_slot(maskSlot) maskLayer.name = "Mask" maskLayer.visible = True maskLayer.opacity = 1.0 layers.append(maskLayer) # Add the uncertainty estimate layer uncertaintySlot = self.topLevelOperatorView.UncertaintyEstimate if uncertaintySlot.ready(): uncertaintySrc = LazyflowSource(uncertaintySlot) uncertaintyLayer = AlphaModulatedLayer(uncertaintySrc, tintColor=QColor(Qt.cyan), range=(0.0, 1.0), normalize=(0.0, 1.0)) uncertaintyLayer.name = "Uncertainty" uncertaintyLayer.visible = False uncertaintyLayer.opacity = 1.0 uncertaintyLayer.shortcutRegistration = ( "u", ActionInfo("Prediction Layers", "Uncertainty", "Show/Hide Uncertainty", uncertaintyLayer.toggleVisible, self.viewerControlWidget(), uncertaintyLayer)) layers.append(uncertaintyLayer) labels = self.labelListData # Add each of the segmentations for channel, segmentationSlot in enumerate( self.topLevelOperatorView.SegmentationChannels): if segmentationSlot.ready() and channel < len(labels): ref_label = labels[channel] segsrc = LazyflowSource(segmentationSlot) segLayer = AlphaModulatedLayer(segsrc, tintColor=ref_label.pmapColor(), range=(0.0, 1.0), normalize=(0.0, 1.0)) segLayer.opacity = 1 segLayer.visible = False #self.labelingDrawerUi.liveUpdateButton.isChecked() segLayer.visibleChanged.connect( self.updateShowSegmentationCheckbox) def setLayerColor(c, segLayer_=segLayer, initializing=False): if not initializing and segLayer_ not in self.layerstack: # This layer has been removed from the layerstack already. # Don't touch it. return segLayer_.tintColor = c self._update_rendering() def setSegLayerName(n, segLayer_=segLayer, initializing=False): if not initializing and segLayer_ not in self.layerstack: # This layer has been removed from the layerstack already. # Don't touch it. return oldname = segLayer_.name newName = "Segmentation (%s)" % n segLayer_.name = newName if not self.render: return if oldname in self._renderedLayers: label = self._renderedLayers.pop(oldname) self._renderedLayers[newName] = label setSegLayerName(ref_label.name, initializing=True) ref_label.pmapColorChanged.connect(setLayerColor) ref_label.nameChanged.connect(setSegLayerName) #check if layer is 3d before adding the "Toggle 3D" option #this check is done this way to match the VolumeRenderer, in #case different 3d-axistags should be rendered like t-x-y #_axiskeys = segmentationSlot.meta.getAxisKeys() if len(segmentationSlot.meta.shape) == 4: #the Renderer will cut out the last shape-dimension, so #we're checking for 4 dimensions self._setup_contexts(segLayer) layers.append(segLayer) # Add each of the predictions for channel, predictionSlot in enumerate( self.topLevelOperatorView.PredictionProbabilityChannels): if predictionSlot.ready() and channel < len(labels): ref_label = labels[channel] predictsrc = LazyflowSource(predictionSlot) predictLayer = AlphaModulatedLayer( predictsrc, tintColor=ref_label.pmapColor(), range=(0.0, 1.0), normalize=(0.0, 1.0)) predictLayer.opacity = 0.25 predictLayer.visible = self.labelingDrawerUi.liveUpdateButton.isChecked( ) predictLayer.visibleChanged.connect( self.updateShowPredictionCheckbox) def setLayerColor(c, predictLayer_=predictLayer, initializing=False): if not initializing and predictLayer_ not in self.layerstack: # This layer has been removed from the layerstack already. # Don't touch it. return predictLayer_.tintColor = c def setPredLayerName(n, predictLayer_=predictLayer, initializing=False): if not initializing and predictLayer_ not in self.layerstack: # This layer has been removed from the layerstack already. # Don't touch it. return newName = "Prediction for %s" % n predictLayer_.name = newName setPredLayerName(ref_label.name, initializing=True) ref_label.pmapColorChanged.connect(setLayerColor) ref_label.nameChanged.connect(setPredLayerName) layers.append(predictLayer) # Add the raw data last (on the bottom) inputDataSlot = self.topLevelOperatorView.InputImages if inputDataSlot.ready(): inputLayer = self.createStandardLayerFromSlot(inputDataSlot) inputLayer.name = "Input Data" inputLayer.visible = True inputLayer.opacity = 1.0 # the flag window_leveling is used to determine if the contrast # of the layer is adjustable if isinstance(inputLayer, GrayscaleLayer): inputLayer.window_leveling = True else: inputLayer.window_leveling = False def toggleTopToBottom(): index = self.layerstack.layerIndex(inputLayer) self.layerstack.selectRow(index) if index == 0: self.layerstack.moveSelectedToBottom() else: self.layerstack.moveSelectedToTop() inputLayer.shortcutRegistration = ("i", ActionInfo( "Prediction Layers", "Bring Input To Top/Bottom", "Bring Input To Top/Bottom", toggleTopToBottom, self.viewerControlWidget(), inputLayer)) layers.append(inputLayer) # The thresholding button can only be used if the data is displayed as grayscale. if inputLayer.window_leveling: self.labelingDrawerUi.thresToolButton.show() else: self.labelingDrawerUi.thresToolButton.hide() self.handleLabelSelectionChange() return layers
def _create_alpha_modulated_layer_from_slot(cls, slot): layer = AlphaModulatedLayer(LazyflowSource(slot), tintColor=QColor(Qt.cyan), range=(0.0, 1.0), normalize=(0.0, 1.0)) return layer
class ObjectExtractionGui(LayerViewerGui): def stopAndCleanUp(self): # Unsubscribe to all signals for fn in self.__cleanup_fns: fn() super(ObjectExtractionGui, self).stopAndCleanUp() def __init__(self, *args, **kwargs): self.__cleanup_fns = [] self._lock = threading.Lock() super( ObjectExtractionGui, self ).__init__(*args, **kwargs) def setupLayers(self): mainOperator = self.topLevelOperatorView layers = [] if mainOperator.ObjectCenterImage.ready(): self.centerimagesrc = LazyflowSource(mainOperator.ObjectCenterImage) redct = [0, QColor(255, 0, 0).rgba()] layer = ColortableLayer(self.centerimagesrc, redct) layer.name = "Object centers" layer.setToolTip("Object center positions, marked with a little red cross") layer.visible = False layers.append(layer) ct = colortables.create_default_16bit() if mainOperator.LabelImage.ready(): self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Objects (connected components)" layer.setToolTip("Segmented objects, shown in different colors") layer.visible = False layer.opacity = 0.5 layers.append(layer) # white foreground on transparent background, even for labeled images binct = [QColor(255, 255, 255, 255).rgba()]*65536 binct[0] = 0 if mainOperator.BinaryImage.ready(): self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, binct) layer.name = "Binary image" layer.setToolTip("Segmented objects, binary mask") layers.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" layers.insert(len(layers), layerraw) mainOperator.RawImage.notifyReady(self._onReady) self.__cleanup_fns.append( partial( mainOperator.RawImage.unregisterReady, self._onReady ) ) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial( mainOperator.RawImage.unregisterMetaChanged, self._onMetaChanged ) ) if mainOperator.BinaryImage.meta.shape: self.editor.dataShape = mainOperator.BinaryImage.meta.shape mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial( mainOperator.BinaryImage.unregisterMetaChanged, self._onMetaChanged ) ) return layers def _onMetaChanged(self, slot): #FiXME: why do we need that? if slot is self.topLevelOperatorView.BinaryImage: if slot.meta.shape: self.editor.dataShape = slot.meta.shape if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" self.layerstack.append(layerraw) def _onReady(self, slot): if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" self.layerstack.append(layerraw) 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") self._drawer.selectFeaturesButton.pressed.connect(self._selectFeaturesButtonPressed) if not ilastik_config.getboolean("ilastik", "debug"): self._drawer.exportButton.setVisible(False) self._drawer.exportButton.pressed.connect(self._exportFeaturesButtonPressed) slot = self.topLevelOperatorView.Features if slot.ready(): selectedFeatures = self.topLevelOperatorView.Features([]).wait() else: selectedFeatures = None nfeatures = 0 if selectedFeatures is not None: for plugin_features in selectedFeatures.itervalues(): nfeatures += len(plugin_features) self._drawer.featuresSelected.setText("{} features computed, \nsome may have multiple channels".format(nfeatures)) # get the applet reference from the workflow (needed for the progressSignal) self.applet = self.topLevelOperatorView.parent.parent.objectExtractionApplet def _selectFeaturesButtonPressed(self): featureDict = {} mainOperator = self.topLevelOperatorView if not mainOperator.RawImage.ready(): mexBox=QMessageBox() mexBox.setText("Please add the raw data before selecting features") mexBox.exec_() return if not mainOperator.BinaryImage.ready(): mexBox=QMessageBox() mexBox.setText("Please add binary (segmentation) data before selecting features ") mexBox.exec_() return slot = mainOperator.Features if slot.ready(): selectedFeatures = mainOperator.Features([]).wait() else: selectedFeatures = None plugins = pluginManager.getPluginsOfCategory('ObjectFeatures') taggedShape = mainOperator.RawImage.meta.getTaggedShape() fakeimg = None fakeimgshp = [taggedShape['x'], taggedShape['y']] fakelabelsshp = [taggedShape['x'], taggedShape['y']] ndim = 3 if 'z' in taggedShape and taggedShape['z']>1: fakeimgshp.append(taggedShape['z']) fakelabelsshp.append(taggedShape['z']) ndim = 3 else: ndim = 2 if 'c' in taggedShape and taggedShape['c']>1: fakeimgshp.append(taggedShape['c']) fakeimg = np.empty(fakeimgshp, dtype=np.float32) fakelabels = np.empty(fakelabelsshp, dtype=np.uint32) if ndim==3: fakelabels = vigra.taggedView(fakelabels, 'xyz') if len(fakeimgshp)==4: fakeimg = vigra.taggedView(fakeimg, 'xyzc') else: fakeimg = vigra.taggedView(fakeimg, 'xyz') if ndim==2: fakelabels = vigra.taggedView(fakelabels, 'xy') if len(fakeimgshp)==3: fakeimg = vigra.taggedView(fakeimg, 'xyc') else: fakeimg = vigra.taggedView(fakeimg, 'xy') for pluginInfo in plugins: featureDict[pluginInfo.name] = pluginInfo.plugin_object.availableFeatures(fakeimg, fakelabels) dlg = FeatureSelectionDialog(featureDict=featureDict, selectedFeatures=selectedFeatures, ndim=ndim) dlg.exec_() if dlg.result() == QDialog.Accepted: mainOperator.Features.setValue(dlg.selectedFeatures) self._calculateFeatures() def _calculateFeatures(self, interactive=True): mainOperator = self.topLevelOperatorView mainOperator.ObjectCenterImage.setDirty(SubRegion(mainOperator.ObjectCenterImage)) current_t = self.editor.posModel.time def _handle_all_finished(*args): self._lock.acquire() self.applet.progressSignal.emit(100) self.topLevelOperatorView._opRegFeats.fixed = True feats = self.topLevelOperatorView.RegionFeatures[0].wait() nfeatures = 0 nchannels = 0 try: for pname, pfeats in feats[0].iteritems(): if pname != 'Default features': for featname, feat in pfeats.iteritems(): nchannels += feat.shape[1] nfeatures += 1 if interactive: self._drawer.featuresSelected.setText("{} features computed, {} channels in total".format(nfeatures, nchannels)) logger.info('Object Extraction: done.') success = True except AttributeError: if interactive: self._drawer.featuresSelected.setText("Feature computation failed (most likely due to memory issues)") logger.error('Object Extraction: failed.') success = False self.applet.appletStateUpdateRequested.emit() self._lock.release() self.applet.progressSignal.emit(0) self.applet.progressSignal.emit(-1) reqs = [] self.already_done = 0 req = mainOperator.RegionFeatures([current_t]) req.submit() req.notify_failed(self.handleFeatureComputationFailure) req.notify_finished(_handle_all_finished) reqs.append(req) @threadRouted def handleFeatureComputationFailure(self, exc, exc_info): import traceback traceback.print_tb(exc_info[2]) msg = "Feature computation failed due to the following error:\n{}".format( exc ) QMessageBox.critical(self, "Feature computation failed", msg) def _exportFeaturesButtonPressed(self): mainOperator = self.topLevelOperatorView if not mainOperator.RegionFeatures.ready(): mexBox=QMessageBox() mexBox.setText("No features have been computed yet. Nothing to save.") mexBox.exec_() return fname = QFileDialog.getSaveFileName(self, caption='Export Computed Features', filter="Pickled Objects (*.pkl);;All Files (*)") fname = encode_from_qstring( fname ) if len(fname)>0: #not cancelled with open(fname, 'w') as f: pickle.dump(mainOperator.RegionFeatures(list()).wait(), f) logger.debug("Exported object features to file '{}'".format(fname))
def createStandardLayerFromSlot(cls, slot, lastChannelIsAlpha=False): """ Convenience function. Generates a volumina layer using the given slot. Chooses between grayscale or RGB depending on the number of channels in the slot. * If *slot* has 1 channel or more than 4 channels, a GrayscaleLayer is created. * If *slot* has 2 non-alpha channels, an RGBALayer is created with R and G channels. * If *slot* has 3 non-alpha channels, an RGBALayer is created with R,G, and B channels. * If *slot* has 4 channels, an RGBA layer is created :param slot: The slot to generate a layer from :param lastChannelIsAlpha: If True, the last channel in the slot is assumed to be an alpha channel. If slot has 4 channels, this parameter has no effect. """ def getRange(meta): return meta.drange def getNormalize(meta): if meta.drange is not None and meta.normalizeDisplay is False: # do not normalize if the user provided a range and set normalization to False return False else: # If we don't know the range of the data and normalization is allowed # by the user, create a layer that is auto-normalized. # See volumina.pixelpipeline.datasources for details. # # Even in the case of integer data, which has more than 255 possible values, # (like uint16), it seems reasonable to use this setting as default return None # means autoNormalize shape = slot.meta.shape try: channelAxisIndex = slot.meta.axistags.index('c') #assert channelAxisIndex < len(slot.meta.axistags), \ # "slot %s has shape = %r, axistags = %r, but no channel dimension" \ # % (slot.name, slot.meta.shape, slot.meta.axistags) numChannels = shape[channelAxisIndex] axisinfo = slot.meta.axistags["c"].description except: numChannels = 1 axisinfo = "" # == no info on channels given rindex = None bindex = None gindex = None aindex = None if axisinfo == "" or axisinfo == "default": # Examine channel dimension to determine Grayscale vs. RGB if numChannels == 4: lastChannelIsAlpha = True if lastChannelIsAlpha: assert numChannels <= 4, "Can't display a standard layer with more than four channels (with alpha). Your image has {} channels.".format( numChannels) if numChannels == 1 or (numChannels > 4): assert not lastChannelIsAlpha, "Can't have an alpha channel if there is no color channel" source = LazyflowSource(slot) layer = GrayscaleLayer(source) layer.numberOfChannels = numChannels normalize = getNormalize(slot.meta) range = getRange(slot.meta) layer.set_range(0, range) layer.set_normalize(0, normalize) return layer assert numChannels > 2 or (numChannels == 2 and not lastChannelIsAlpha), \ "Unhandled combination of channels. numChannels={}, lastChannelIsAlpha={}, axistags={}".format( numChannels, lastChannelIsAlpha, slot.meta.axistags ) rindex = 0 gindex = 1 if numChannels > 3 or (numChannels == 3 and not lastChannelIsAlpha): bindex = 2 if lastChannelIsAlpha: aindex = numChannels - 1 elif axisinfo == "grayscale": source = LazyflowSource(slot) layer = GrayscaleLayer(source) layer.numberOfChannels = numChannels normalize = getNormalize(slot.meta) range = getRange(slot.meta) layer.set_range(0, range) layer.set_normalize(0, normalize) return layer elif axisinfo == "rgba": rindex = 0 if numChannels >= 2: gindex = 1 if numChannels >= 3: bindex = 2 if numChannels >= 4: aindex = numChannels - 1 else: raise RuntimeError("unknown channel display mode") redSource = None if rindex is not None: redProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) redProvider.Input.connect(slot) redProvider.Index.setValue(rindex) redSource = LazyflowSource(redProvider.Output) redSource.additional_owned_ops.append(redProvider) greenSource = None if gindex is not None: greenProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) greenProvider.Input.connect(slot) greenProvider.Index.setValue(gindex) greenSource = LazyflowSource(greenProvider.Output) greenSource.additional_owned_ops.append(greenProvider) blueSource = None if bindex is not None: blueProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) blueProvider.Input.connect(slot) blueProvider.Index.setValue(bindex) blueSource = LazyflowSource(blueProvider.Output) blueSource.additional_owned_ops.append(blueProvider) alphaSource = None if aindex is not None: alphaProvider = OpSingleChannelSelector( parent=slot.getRealOperator().parent) alphaProvider.Input.connect(slot) alphaProvider.Index.setValue(aindex) alphaSource = LazyflowSource(alphaProvider.Output) alphaSource.additional_owned_ops.append(alphaProvider) layer = RGBALayer(red=redSource, green=greenSource, blue=blueSource, alpha=alphaSource) normalize = getNormalize(slot.meta) range = getRange(slot.meta) for i in xrange(4): if [redSource, greenSource, blueSource, alphaSource][i]: layer.set_range(i, range) layer.set_normalize(i, normalize) return layer
class ObjectExtractionGui(QWidget): ########################################### ### AppletGuiInterface Concrete Methods ### ########################################### def centralWidget(self): """ Return the widget that will be displayed in the main viewer area. """ return self.volumeEditorWidget def appletDrawer(self): return self._drawer def menus(self): return [] def viewerControlWidget(self): return self._viewerControlWidget def stopAndCleanUp(self): pass ########################################### ########################################### def __init__(self, topLevelOperatorView): super(ObjectExtractionGui, self).__init__() self.mainOperator = topLevelOperatorView self.layerstack = LayerStackModel() self._viewerControlWidget = None self._initViewerControlUi() self.editor = None self._initEditor() self._initAppletDrawerUi() assert(self.appletDrawer() is not None) self._initViewer() def _onMetaChanged(self, slot): if slot is self.mainOperator.BinaryImage: if slot.meta.shape: self.editor.dataShape = slot.meta.shape if slot is self.mainOperator.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.mainOperator.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.append(layerraw) def _onReady(self, slot): if slot is self.mainOperator.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource(self.mainOperator.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.append(layerraw) def _initViewer(self): mainOperator = self.mainOperator # white foreground on transparent background ct = [QColor(0, 0, 0, 0).rgba(), QColor(255, 255, 255, 255).rgba()] self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, ct) layer.name = "Binary Image" self.layerstack.append(layer) ct = colortables.create_default_16bit() self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Label Image" layer.visible = False layer.opacity = 0.5 self.layerstack.append(layer) self.centerimagesrc = LazyflowSource(mainOperator.ObjectCenterImage) layer = RGBALayer(red=ConstantSource(255), alpha=self.centerimagesrc) layer.name = "Object Centers" layer.visible = False self.layerstack.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(self.mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw" self.layerstack.insert(len(self.layerstack), layerraw) mainOperator.RawImage.notifyReady(self._onReady) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) if mainOperator.BinaryImage.meta.shape: self.editor.dataShape = mainOperator.BinaryImage.meta.shape mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) def _initEditor(self): """Initialize the Volume Editor GUI.""" self.editor = VolumeEditor(self.layerstack, crosshair=False) self.volumeEditorWidget = VolumeEditorWidget() self.volumeEditorWidget.init(self.editor) # The editor's layerstack is in charge of which layer movement buttons are enabled model = self.editor.layerStack self._viewerControlWidget.setupConnections(model) self.editor._lastImageViewFocus = 0 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") self._drawer.selectFeaturesButton.pressed.connect(self._selectFeaturesButtonPressed) def _initViewerControlUi(self): self._viewerControlWidget = ViewerControls(self) def _selectFeaturesButtonPressed(self): featureDict = {} slot = self.mainOperator.Features if slot.ready(): selectedFeatures = self.mainOperator.Features([]).wait() else: selectedFeatures = None try: plugins = pluginManager.getPluginsOfCategory('ObjectFeatures') except: QMessageBox.warning(self, 'object features unavailable', 'Object features plugins failed. Perhaps Yapsy is not installed?', QMessageBox.Ok) return imgshape = list(self.mainOperator.RawImage.meta.shape) axistags = self.mainOperator.RawImage.meta.axistags imgshape.pop(axistags.index('t')) fakeimg = np.empty(imgshape, dtype=np.float32) labelshape = list(self.mainOperator.BinaryImage.meta.shape) axistags = self.mainOperator.BinaryImage.meta.axistags labelshape.pop(axistags.index('t')) labelshape.pop(axistags.index('c') - 1) fakelabels = np.empty(labelshape, dtype=np.uint32) for pluginInfo in plugins: featureDict[pluginInfo.name] = pluginInfo.plugin_object.availableFeatures(fakeimg, fakelabels) dlg = FeatureSelectionDialog(featureDict=featureDict, selectedFeatures=selectedFeatures) dlg.exec_() if dlg.result() == QDialog.Accepted: self.mainOperator.Features.setValue(dlg.selectedFeatures) self._calculateFeatures() def _calculateFeatures(self): self.mainOperator.ObjectCenterImage.setDirty(SubRegion(self.mainOperator.ObjectCenterImage)) maxt = self.mainOperator.LabelImage.meta.shape[0] progress = QProgressDialog("Calculating features...", "Cancel", 0, maxt) progress.setWindowModality(Qt.ApplicationModal) progress.setMinimumDuration(0) progress.setValue(0) # We will use notify_finished() to update the progress bar. # However, the callback will be called from a non-gui thread, # which cannot access gui elements directly. Therefore we use # this callback object to send signals back to this thread. class Callback(QObject): ndone = 0 timestep_done = pyqtSignal(int) all_finished = pyqtSignal() def __call__(self, *args, **kwargs): self.ndone += 1 self.timestep_done.emit(self.ndone) if self.ndone == len(reqs): self.all_finished.emit() callback = Callback() def updateProgress(progress, n): progress.setValue(n) callback.timestep_done.connect(partial(updateProgress, progress)) def finished(): self.mainOperator._opRegFeats.fixed = True print 'Object Extraction: done.' callback.all_finished.connect(finished) self.mainOperator._opRegFeats.fixed = False reqs = [] for t in range(maxt): req = self.mainOperator.RegionFeatures([t]) req.submit() reqs.append(req) for i, req in enumerate(reqs): req.notify_finished(callback) # handle cancel button def cancel(): for req in reqs: req.cancel() progress.canceled.connect(cancel)
def setupLayers(self): layers = [] opLane = self.topLevelOperatorView selection_names = opLane.SelectionNames.value selection = selection_names[opLane.InputSelection.value] # This code is written to handle the specific output cases we know about. # If those change, update this function! assert selection in [ 'Object Predictions', 'Object Probabilities', 'Blockwise Object Predictions', 'Blockwise Object Probabilities', 'Pixel Probabilities' ] if selection in ("Object Predictions", "Blockwise Object Predictions"): fromDiskSlot = self.topLevelOperatorView.ImageOnDisk if fromDiskSlot.ready(): exportLayer = ColortableLayer(LazyflowSource(fromDiskSlot), colorTable=self._colorTable16) exportLayer.name = "Prediction - Exported" exportLayer.visible = True layers.append(exportLayer) previewSlot = self.topLevelOperatorView.ImageToExport if previewSlot.ready(): previewLayer = ColortableLayer(LazyflowSource(previewSlot), colorTable=self._colorTable16) previewLayer.name = "Prediction - Preview" previewLayer.visible = False layers.append(previewLayer) elif selection in ("Object Probabilities", "Blockwise Object Probabilities"): exportedLayers = self._initPredictionLayers(opLane.ImageOnDisk) for layer in exportedLayers: layer.visible = True layer.name = layer.name + "- Exported" layers += exportedLayers previewLayers = self._initPredictionLayers(opLane.ImageToExport) for layer in previewLayers: layer.visible = False layer.name = layer.name + "- Preview" layers += previewLayers elif selection == 'Pixel Probabilities': exportedLayers = self._initPredictionLayers(opLane.ImageOnDisk) for layer in exportedLayers: layer.visible = True layer.name = layer.name + "- Exported" layers += exportedLayers previewLayers = self._initPredictionLayers(opLane.ImageToExport) for layer in previewLayers: layer.visible = False layer.name = layer.name + "- Preview" layers += previewLayers else: assert False, "Unknown selection." rawSlot = self.topLevelOperatorView.RawData if rawSlot.ready(): rawLayer = self.createStandardLayerFromSlot(rawSlot) rawLayer.name = "Raw Data" rawLayer.opacity = 1.0 layers.append(rawLayer) return layers
def setupLayers(self): layers = [] # use same colortable for the following two generated layers: the merger # and the tracking layer self.tracking_colortable = colortables.create_random_16bit() self.tracking_colortable[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent self.tracking_colortable[1] = QColor(128, 128, 128, 255).rgba( ) # misdetections have id 1 and will be indicated by grey self.merger_colortable = colortables.create_default_16bit() for i in range(7): self.merger_colortable[i] = self.mergerColors[i].rgba() if "MergerOutput" in self.topLevelOperatorView.outputs: parameters = self.mainOperator.Parameters.value if 'withMergerResolution' in parameters.keys( ) and not parameters['withMergerResolution']: merger_ct = self.merger_colortable else: merger_ct = self.tracking_colortable # Using same color table for tracking with and without mergers (Is there any reason for using different color tables?) merger_ct = self.tracking_colortable if self.topLevelOperatorView.MergerCachedOutput.ready(): self.mergersrc = LazyflowSource( self.topLevelOperatorView.MergerCachedOutput) else: self.mergersrc = LazyflowSource( self.topLevelOperatorView.zeroProvider.Output) mergerLayer = ColortableLayer(self.mergersrc, merger_ct) mergerLayer.name = "Merger" if 'withMergerResolution' in parameters.keys( ) and not parameters['withMergerResolution']: mergerLayer.visible = True else: mergerLayer.visible = False layers.append(mergerLayer) if self.topLevelOperatorView.CachedOutput.ready(): self.trackingsrc = LazyflowSource( self.topLevelOperatorView.CachedOutput) trackingLayer = ColortableLayer(self.trackingsrc, self.tracking_colortable) trackingLayer.name = "Tracking" trackingLayer.visible = True trackingLayer.opacity = 1.0 layers.append(trackingLayer) elif self.topLevelOperatorView.zeroProvider.Output.ready(): # provide zeros while waiting for the tracking result self.trackingsrc = LazyflowSource( self.topLevelOperatorView.zeroProvider.Output) trackingLayer = ColortableLayer(self.trackingsrc, self.tracking_colortable) trackingLayer.name = "Tracking" trackingLayer.visible = True trackingLayer.opacity = 1.0 layers.append(trackingLayer) if "RelabeledImage" in self.topLevelOperatorView.outputs: if self.topLevelOperatorView.RelabeledCachedOutput.ready(): self.objectssrc = LazyflowSource( self.topLevelOperatorView.RelabeledCachedOutput) else: self.objectssrc = LazyflowSource( self.topLevelOperatorView.zeroProvider.Output) else: if self.topLevelOperatorView.LabelImage.ready(): self.objectssrc = LazyflowSource( self.topLevelOperatorView.LabelImage) ct = colortables.create_random_16bit() ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent objLayer = ColortableLayer(self.objectssrc, ct) objLayer.name = "Objects" objLayer.opacity = 1.0 objLayer.visible = False layers.append(objLayer) if self.mainOperator.RawImage.ready(): rawLayer = self.createStandardLayerFromSlot( self.mainOperator.RawImage) rawLayer.name = "Raw" layers.insert(len(layers), rawLayer) if self.topLevelOperatorView.LabelImage.meta.shape: maxt = self.topLevelOperatorView.LabelImage.meta.shape[0] - 1 maxx = self.topLevelOperatorView.LabelImage.meta.shape[1] - 1 maxy = self.topLevelOperatorView.LabelImage.meta.shape[2] - 1 maxz = self.topLevelOperatorView.LabelImage.meta.shape[3] - 1 if not self.mainOperator.Parameters.ready(): raise Exception("Parameter slot is not ready") parameters = self.mainOperator.Parameters.value self._setRanges() if 'size_range' in parameters: self._drawer.to_size.setValue(parameters['size_range'][1] - 1) self._drawer.from_size.setValue(parameters['size_range'][0]) else: self._drawer.from_size.setValue(0) self._drawer.to_size.setValue(10000) if 'x_range' in parameters: self._drawer.to_x.setValue(parameters['x_range'][1] - 1) self._drawer.from_x.setValue(parameters['x_range'][0]) else: self._drawer.from_x.setValue(0) self._drawer.to_x.setValue(maxx) if 'y_range' in parameters: self._drawer.to_y.setValue(parameters['y_range'][1] - 1) self._drawer.from_y.setValue(parameters['y_range'][0]) else: self._drawer.from_y.setValue(0) self._drawer.to_y.setValue(maxy) if 'z_range' in parameters: self._drawer.to_z.setValue(parameters['z_range'][1] - 1) self._drawer.from_z.setValue(parameters['z_range'][0]) else: self._drawer.from_z.setValue(0) self._drawer.to_z.setValue(maxz) if 'time_range' in parameters: self._drawer.to_time.setValue(parameters['time_range'][1]) self._drawer.from_time.setValue(parameters['time_range'][0]) else: self._drawer.from_time.setValue(0) self._drawer.to_time.setValue(maxt) if 'scales' in parameters: self._drawer.x_scale.setValue(parameters['scales'][0]) self._drawer.y_scale.setValue(parameters['scales'][1]) self._drawer.z_scale.setValue(parameters['scales'][2]) else: self._drawer.x_scale.setValue(1) self._drawer.y_scale.setValue(1) self._drawer.z_scale.setValue(1) return layers
def setupLayers(self): mainOperator = self.topLevelOperatorView layers = [] if mainOperator.ObjectCenterImage.ready(): self.centerimagesrc = LazyflowSource( mainOperator.ObjectCenterImage) redct = [0, QColor(255, 0, 0).rgba()] layer = ColortableLayer(self.centerimagesrc, redct) layer.name = "Object centers" layer.setToolTip( "Object center positions, marked with a little red cross") layer.visible = False layers.append(layer) ct = colortables.create_default_16bit() if mainOperator.LabelImage.ready(): self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Objects (connected components)" layer.setToolTip("Segmented objects, shown in different colors") layer.visible = False layer.opacity = 0.5 layers.append(layer) # white foreground on transparent background, even for labeled images binct = [QColor(255, 255, 255, 255).rgba()] * 65536 binct[0] = 0 if mainOperator.BinaryImage.ready(): self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, binct) layer.name = "Binary image" layer.setToolTip("Segmented objects, binary mask") layers.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" layers.insert(len(layers), layerraw) mainOperator.RawImage.notifyReady(self._onReady) self.__cleanup_fns.append( partial(mainOperator.RawImage.unregisterReady, self._onReady)) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial(mainOperator.RawImage.unregisterMetaChanged, self._onMetaChanged)) mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial(mainOperator.BinaryImage.unregisterMetaChanged, self._onMetaChanged)) return layers
class ObjectExtractionGui(LayerViewerGui): def stopAndCleanUp(self): # Unsubscribe to all signals for fn in self.__cleanup_fns: fn() super(ObjectExtractionGui, self).stopAndCleanUp() def __init__(self, *args, **kwargs): self.__cleanup_fns = [] self._lock = threading.Lock() super(ObjectExtractionGui, self).__init__(*args, **kwargs) def setupLayers(self): mainOperator = self.topLevelOperatorView layers = [] if mainOperator.ObjectCenterImage.ready(): self.centerimagesrc = LazyflowSource( mainOperator.ObjectCenterImage) redct = [0, QColor(255, 0, 0).rgba()] layer = ColortableLayer(self.centerimagesrc, redct) layer.name = "Object centers" layer.setToolTip( "Object center positions, marked with a little red cross") layer.visible = False layers.append(layer) ct = colortables.create_default_16bit() if mainOperator.LabelImage.ready(): self.objectssrc = LazyflowSource(mainOperator.LabelImage) self.objectssrc.setObjectName("LabelImage LazyflowSrc") ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent layer = ColortableLayer(self.objectssrc, ct) layer.name = "Objects (connected components)" layer.setToolTip("Segmented objects, shown in different colors") layer.visible = False layer.opacity = 0.5 layers.append(layer) # white foreground on transparent background, even for labeled images binct = [QColor(255, 255, 255, 255).rgba()] * 65536 binct[0] = 0 if mainOperator.BinaryImage.ready(): self.binaryimagesrc = LazyflowSource(mainOperator.BinaryImage) self.binaryimagesrc.setObjectName("Binary LazyflowSrc") layer = ColortableLayer(self.binaryimagesrc, binct) layer.name = "Binary image" layer.setToolTip("Segmented objects, binary mask") layers.append(layer) ## raw data layer self.rawsrc = None self.rawsrc = LazyflowSource(mainOperator.RawImage) self.rawsrc.setObjectName("Raw Lazyflow Src") layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" layers.insert(len(layers), layerraw) mainOperator.RawImage.notifyReady(self._onReady) self.__cleanup_fns.append( partial(mainOperator.RawImage.unregisterReady, self._onReady)) mainOperator.RawImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial(mainOperator.RawImage.unregisterMetaChanged, self._onMetaChanged)) mainOperator.BinaryImage.notifyMetaChanged(self._onMetaChanged) self.__cleanup_fns.append( partial(mainOperator.BinaryImage.unregisterMetaChanged, self._onMetaChanged)) return layers def _onMetaChanged(self, slot): #FiXME: why do we need that? if slot is self.topLevelOperatorView.BinaryImage: if slot.meta.shape: self.editor.dataShape = slot.meta.shape if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource( self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" self.layerstack.append(layerraw) def _onReady(self, slot): if slot is self.topLevelOperatorView.RawImage: if slot.meta.shape and not self.rawsrc: self.rawsrc = LazyflowSource( self.topLevelOperatorView.RawImage) layerraw = GrayscaleLayer(self.rawsrc) layerraw.name = "Raw data" self.layerstack.append(layerraw) 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") self._drawer.selectFeaturesButton.pressed.connect( self._selectFeaturesButtonPressed) if not ilastik_config.getboolean("ilastik", "debug"): self._drawer.exportButton.setVisible(False) self._drawer.exportButton.pressed.connect( self._exportFeaturesButtonPressed) slot = self.topLevelOperatorView.Features if slot.ready(): selectedFeatures = self.topLevelOperatorView.Features([]).wait() else: selectedFeatures = None nfeatures = 0 if selectedFeatures is not None: for plugin_features in selectedFeatures.values(): nfeatures += len(plugin_features) self._drawer.featuresSelected.setText( "{} features computed, \nsome may have multiple channels".format( nfeatures)) # get the applet reference from the workflow (needed for the progressSignal) self.applet = self.topLevelOperatorView.parent.parent.objectExtractionApplet def _selectFeaturesButtonPressed(self): featureDict = {} mainOperator = self.topLevelOperatorView if not mainOperator.RawImage.ready(): mexBox = QMessageBox() mexBox.setText("Please add the raw data before selecting features") mexBox.exec_() return if not mainOperator.BinaryImage.ready(): mexBox = QMessageBox() mexBox.setText( "Please add binary (segmentation) data before selecting features " ) mexBox.exec_() return slot = mainOperator.Features if slot.ready(): selectedFeatures = mainOperator.Features([]).wait() else: selectedFeatures = None plugins = pluginManager.getPluginsOfCategory('ObjectFeatures') taggedShape = mainOperator.RawImage.meta.getTaggedShape() fakeimgshp = [taggedShape['x'], taggedShape['y']] fakelabelsshp = [taggedShape['x'], taggedShape['y']] ndim = 3 if 'z' in taggedShape and taggedShape['z'] > 1: fakeimgshp.append(taggedShape['z']) fakelabelsshp.append(taggedShape['z']) ndim = 3 else: ndim = 2 if 'c' in taggedShape and taggedShape['c'] > 1: fakeimgshp.append(taggedShape['c']) fakeimg = numpy.empty(fakeimgshp, dtype=numpy.float32) fakelabels = numpy.empty(fakelabelsshp, dtype=numpy.uint32) if ndim == 3: fakelabels = vigra.taggedView(fakelabels, 'xyz') if len(fakeimgshp) == 4: fakeimg = vigra.taggedView(fakeimg, 'xyzc') else: fakeimg = vigra.taggedView(fakeimg, 'xyz') if ndim == 2: fakelabels = vigra.taggedView(fakelabels, 'xy') if len(fakeimgshp) == 3: fakeimg = vigra.taggedView(fakeimg, 'xyc') else: fakeimg = vigra.taggedView(fakeimg, 'xy') for pluginInfo in plugins: availableFeatures = pluginInfo.plugin_object.availableFeatures( fakeimg, fakelabels) if len(availableFeatures) > 0: featureDict[pluginInfo.name] = availableFeatures # Make sure no plugins use the same feature names. # (Currently, our feature export implementation doesn't support repeated column names.) all_feature_names = chain(*[ list(plugin_dict.keys()) for plugin_dict in list(featureDict.values()) ]) feature_set = set() for name in all_feature_names: assert name not in feature_set, \ "Feature name '{}' is used by more than one feature plugin.\n"\ "All plugins must produce uniquely named features.\n"\ "The plugins and feature names we found are:\n{}"\ .format(name, featureDict) feature_set.add(name) dlg = FeatureSelectionDialog(featureDict=featureDict, selectedFeatures=selectedFeatures, ndim=ndim) dlg.exec_() if dlg.result() == QDialog.Accepted: mainOperator.Features.setValue(dlg.selectedFeatures) self._calculateFeatures() def _calculateFeatures(self, interactive=True): mainOperator = self.topLevelOperatorView mainOperator.ObjectCenterImage.setDirty( SubRegion(mainOperator.ObjectCenterImage)) current_t = self.editor.posModel.time def _handle_all_finished(*args): self._lock.acquire() self.applet.progressSignal(100) self.topLevelOperatorView._opRegFeats.fixed = True feats = self.topLevelOperatorView.RegionFeatures[0].wait() nfeatures = 0 nchannels = 0 try: for pname, pfeats in feats[0].items(): if pname != default_features_key: for featname, feat in pfeats.items(): nchannels += feat.shape[1] nfeatures += 1 if interactive: self._drawer.featuresSelected.setText( "{} features computed, {} channels in total".format( nfeatures, nchannels)) logger.info('Object Extraction: done.') success = True except AttributeError: if interactive: self._drawer.featuresSelected.setText( "Feature computation failed (most likely due to memory issues)" ) logger.error('Object Extraction: failed.') success = False self.applet.appletStateUpdateRequested() self._lock.release() self.applet.progressSignal(0) self.applet.progressSignal(-1) reqs = [] self.already_done = 0 req = mainOperator.RegionFeatures([current_t]) req.submit() req.notify_failed(self.handleFeatureComputationFailure) req.notify_finished(_handle_all_finished) reqs.append(req) @threadRouted def handleFeatureComputationFailure(self, exc, exc_info): msg = "Feature computation failed due to the following error:\n{}".format( exc) log_exception(logger, msg, exc_info) QMessageBox.critical(self, "Feature computation failed", msg) def _exportFeaturesButtonPressed(self): mainOperator = self.topLevelOperatorView if not mainOperator.RegionFeatures.ready(): mexBox = QMessageBox() mexBox.setText( "No features have been computed yet. Nothing to save.") mexBox.exec_() return fname, _filter = QFileDialog.getSaveFileName( self, caption='Export Computed Features', filter="Pickled Objects (*.pkl);;All Files (*)") if len(fname) > 0: #not cancelled with open(fname, 'w') as f: pickle.dump(mainOperator.RegionFeatures(list()).wait(), f, 0) logger.debug("Exported object features to file '{}'".format(fname))
def setupLayers(self): # Base class provides the label layer. layers = super(ObjectClassificationGui, self).setupLayers() binarySlot = self.op.BinaryImages segmentedSlot = self.op.SegmentationImages rawSlot = self.op.RawImages #This is just for colors labels = self.labelListData for channel, probSlot in enumerate( self.op.PredictionProbabilityChannels): if probSlot.ready() and channel < len(labels): ref_label = labels[channel] probsrc = LazyflowSource(probSlot) probLayer = AlphaModulatedLayer( probsrc, tintColor=ref_label.pmapColor(), range=(0.0, 1.0), normalize=(0.0, 1.0)) probLayer.opacity = 0.25 #probLayer.visible = self.labelingDrawerUi.checkInteractive.isChecked() #False, because it's much faster to draw predictions without these layers below probLayer.visible = False probLayer.setToolTip( "Probability that the object belongs to class {}".format( channel + 1)) def setLayerColor(c, predictLayer_=probLayer, ch=channel, initializing=False): if not initializing and predictLayer_ not in self.layerstack: # This layer has been removed from the layerstack already. # Don't touch it. return predictLayer_.tintColor = c def setLayerName(n, predictLayer_=probLayer, initializing=False): if not initializing and predictLayer_ not in self.layerstack: # This layer has been removed from the layerstack already. # Don't touch it. return newName = "Prediction for %s" % n predictLayer_.name = newName setLayerName(ref_label.name, initializing=True) ref_label.pmapColorChanged.connect(setLayerColor) ref_label.nameChanged.connect(setLayerName) layers.append(probLayer) predictionSlot = self.op.PredictionImages if predictionSlot.ready(): predictsrc = LazyflowSource(predictionSlot) self._colorTable16_forpmaps[0] = 0 predictLayer = ColortableLayer( predictsrc, colorTable=self._colorTable16_forpmaps) predictLayer.name = self.PREDICTION_LAYER_NAME predictLayer.ref_object = None predictLayer.visible = self.labelingDrawerUi.checkInteractive.isChecked( ) predictLayer.opacity = 0.5 predictLayer.setToolTip( "Classification results, assigning a label to each object") # This weakref stuff is a little more fancy than strictly necessary. # The idea is to use the weakref's callback to determine when this layer instance is destroyed by the garbage collector, # and then we disconnect the signal that updates that layer. weak_predictLayer = weakref.ref(predictLayer) colortable_changed_callback = bind(self._setPredictionColorTable, weak_predictLayer) self._labelControlUi.labelListModel.dataChanged.connect( colortable_changed_callback) weak_predictLayer2 = weakref.ref( predictLayer, partial(self._disconnect_dataChange_callback, colortable_changed_callback)) # We have to make sure the weakref isn't destroyed because it is responsible for calling the callback. # Therefore, we retain it by adding it to a list. self._retained_weakrefs.append(weak_predictLayer2) # Ensure we're up-to-date (in case this is the first time the prediction layer is being added. for row in range(self._labelControlUi.labelListModel.rowCount()): self._setPredictionColorTableForRow(predictLayer, row) # put right after Labels, so that it is visible after hitting "live # predict". layers.insert(1, predictLayer) badObjectsSlot = self.op.BadObjectImages if badObjectsSlot.ready(): ct_black = [0, QColor(Qt.black).rgba()] badSrc = LazyflowSource(badObjectsSlot) badLayer = ColortableLayer(badSrc, colorTable=ct_black) badLayer.name = "Ambiguous objects" badLayer.setToolTip( "Objects with infinite or invalid values in features") badLayer.visible = False layers.append(badLayer) if segmentedSlot.ready(): ct = colortables.create_default_16bit() objectssrc = LazyflowSource(segmentedSlot) ct[0] = QColor(0, 0, 0, 0).rgba() # make 0 transparent objLayer = ColortableLayer(objectssrc, ct) objLayer.name = "Objects" objLayer.opacity = 0.5 objLayer.visible = False objLayer.setToolTip( "Segmented objects (labeled image/connected components)") layers.append(objLayer) if binarySlot.ready(): ct_binary = [0, QColor(255, 255, 255, 255).rgba()] # white foreground on transparent background, even for labeled images binct = [QColor(255, 255, 255, 255).rgba()] * 65536 binct[0] = 0 binaryimagesrc = LazyflowSource(binarySlot) binLayer = ColortableLayer(binaryimagesrc, binct) binLayer.name = "Binary image" binLayer.visible = True binLayer.opacity = 1.0 binLayer.setToolTip("Segmentation results as a binary mask") layers.append(binLayer) if rawSlot.ready(): rawLayer = self.createStandardLayerFromSlot(rawSlot) rawLayer.name = "Raw data" def toggleTopToBottom(): index = self.layerstack.layerIndex(rawLayer) self.layerstack.selectRow(index) if index == 0: self.layerstack.moveSelectedToBottom() else: self.layerstack.moveSelectedToTop() ActionInfo = ShortcutManager.ActionInfo rawLayer.shortcutRegistration = ("i", ActionInfo( "Prediction Layers", "Bring Input To Top/Bottom", "Bring Input To Top/Bottom", toggleTopToBottom, self.viewerControlWidget(), rawLayer)) layers.append(rawLayer) # since we start with existing labels, it makes sense to start # with the first one selected. This would make more sense in # __init__(), but it does not take effect there. #self.selectLabel(0) return layers
def _create_random_colortable_layer_from_slot(cls, slot, num_colors=256): colortable = generateRandomColors(num_colors, clamp={'v': 1.0, 's' : 0.5}, zeroIsTransparent=True) layer = ColortableLayer(LazyflowSource(slot), colortable) layer.colortableIsRandom = True return layer
def initGraph(self): shape = self.inputProvider.outputs["Output"].shape srcs = [] minMax = [] normalize = [] print "* Data has shape=%r" % (shape,) #create a layer for each channel of the input: slicer=OpMultiArraySlicer2(self.g) slicer.inputs["Input"].connect(self.inputProvider.outputs["Output"]) slicer.inputs["AxisFlag"].setValue('c') nchannels = shape[-1] for ich in xrange(nchannels): data=slicer.outputs['Slices'][ich][:].allocate().wait() #find the minimum and maximum value for normalization mm = (numpy.min(data), numpy.max(data)) print " - channel %d: min=%r, max=%r" % (ich, mm[0], mm[1]) minMax.append(mm) if self._normalize_data: normalize.append(mm) else: normalize.append((0,255)) layersrc = LazyflowSource(slicer.outputs['Slices'][ich], priority = 100) layersrc.setObjectName("raw data channel=%d" % ich) srcs.append(layersrc) #FIXME: we shouldn't merge channels automatically, but for now it's prettier layer1 = None if nchannels == 1: layer1 = GrayscaleLayer(srcs[0], range=minMax[0], normalize=normalize[0]) print " - showing raw data as grayscale" elif nchannels==2: layer1 = RGBALayer(red = srcs[0], normalizeR=normalize[0], green = srcs[1], normalizeG=normalize[1], range=minMax[0:2]+[(0,255), (0,255)]) print " - showing channel 1 as red, channel 2 as green" elif nchannels==3: layer1 = RGBALayer(red = srcs[0], normalizeR=normalize[0], green = srcs[1], normalizeG=normalize[1], blue = srcs[2], normalizeB=normalize[2], range = minMax[0:3]) print " - showing channel 1 as red, channel 2 as green, channel 3 as blue" else: print "only 1,2 or 3 channels supported so far" return print layer1.name = "Input data" layer1.ref_object = None self.layerstack.append(layer1) opImageList = Op5ToMulti(self.g) opImageList.inputs["Input0"].connect(self.inputProvider.outputs["Output"]) #init the features operator opPF = OpPixelFeaturesPresmoothed(self.g) opPF.inputs["Input"].connect(opImageList.outputs["Outputs"]) opPF.inputs["Scales"].setValue(self.featScalesList) self.opPF=opPF #Caches the features opFeatureCache = OpBlockedArrayCache(self.g) opFeatureCache.inputs["innerBlockShape"].setValue((1,32,32,32,16)) opFeatureCache.inputs["outerBlockShape"].setValue((1,128,128,128,64)) opFeatureCache.inputs["Input"].connect(opPF.outputs["Output"]) opFeatureCache.inputs["fixAtCurrent"].setValue(False) self.opFeatureCache=opFeatureCache self.initLabels() self.dataReadyToView.emit()
def setupLayers(self): layers = [] opLane = self.topLevelOperatorView # This code depends on a specific order for the export slots. # If those change, update this function! selection_names = opLane.SelectionNames.value # see comment above for name, expected in zip(selection_names[0:5], [ 'Probabilities', 'Simple Segmentation', 'Uncertainty', 'Features', 'Labels' ]): assert name.startswith( expected ), "The Selection Names don't match the expected selection names." selection = selection_names[opLane.InputSelection.value] if selection.startswith('Probabilities'): exportedLayers = self._initPredictionLayers(opLane.ImageOnDisk) for layer in exportedLayers: layer.visible = True layer.name = layer.name + "- Exported" layers += exportedLayers previewLayers = self._initPredictionLayers(opLane.ImageToExport) for layer in previewLayers: layer.visible = False layer.name = layer.name + "- Preview" layers += previewLayers elif selection.startswith( "Simple Segmentation") or selection.startswith("Labels"): exportedLayer = self._initColortablelayer(opLane.ImageOnDisk) if exportedLayer: exportedLayer.visible = True exportedLayer.name = selection + " - Exported" layers.append(exportedLayer) previewLayer = self._initColortablelayer(opLane.ImageToExport) if previewLayer: previewLayer.visible = False previewLayer.name = selection + " - Preview" layers.append(previewLayer) elif selection.startswith("Uncertainty"): if opLane.ImageToExport.ready(): previewUncertaintySource = LazyflowSource(opLane.ImageToExport) previewLayer = AlphaModulatedLayer( previewUncertaintySource, tintColor=QColor(0, 255, 255), # cyan range=(0.0, 1.0), normalize=(0.0, 1.0)) previewLayer.opacity = 0.5 previewLayer.visible = False previewLayer.name = "Uncertainty - Preview" layers.append(previewLayer) if opLane.ImageOnDisk.ready(): exportedUncertaintySource = LazyflowSource(opLane.ImageOnDisk) exportedLayer = AlphaModulatedLayer( exportedUncertaintySource, tintColor=QColor(0, 255, 255), # cyan range=(0.0, 1.0), normalize=(0.0, 1.0)) exportedLayer.opacity = 0.5 exportedLayer.visible = True exportedLayer.name = "Uncertainty - Exported" layers.append(exportedLayer) else: # Features and all other layers. if selection.startswith("Features"): warnings.warn( "Not sure how to display '{}' result. Showing with default layer settings." .format(selection)) if opLane.ImageToExport.ready(): previewLayer = self.createStandardLayerFromSlot( opLane.ImageToExport) previewLayer.visible = False previewLayer.name = "{} - Preview".format(selection) previewLayer.set_normalize(0, None) layers.append(previewLayer) if opLane.ImageOnDisk.ready(): exportedLayer = self.createStandardLayerFromSlot( opLane.ImageOnDisk) exportedLayer.visible = True exportedLayer.name = "{} - Exported".format(selection) exportedLayer.set_normalize(0, None) layers.append(exportedLayer) # If available, also show the raw data layer rawSlot = opLane.FormattedRawData if rawSlot.ready(): rawLayer = self.createStandardLayerFromSlot(rawSlot) rawLayer.name = "Raw Data" rawLayer.visible = True rawLayer.opacity = 1.0 layers.append(rawLayer) return layers
def setupLayers(self): layers = [] op = self.topLevelOperatorView binct = [QColor(Qt.black), QColor(Qt.white)] binct[0] = 0 ct = create_default_16bit() ct[0] = 0 # Show the cached output, since it goes through a blocked cache if op.CachedOutput.ready(): outputSrc = LazyflowSource(op.CachedOutput) outputLayer = ColortableLayer(outputSrc, ct) outputLayer.name = "Final output" outputLayer.visible = False outputLayer.opacity = 1.0 outputLayer.setToolTip("Results of thresholding and size filter") layers.append(outputLayer) if op.InputChannelColors.ready(): input_channel_colors = map(lambda (r, g, b): QColor(r, g, b), op.InputChannelColors.value) else: input_channel_colors = map(QColor, self._defaultInputChannelColors) for channel, channelProvider in enumerate(self._channelProviders): slot_drange = channelProvider.Output.meta.drange if slot_drange is not None: drange = slot_drange else: drange = (0.0, 1.0) channelSrc = LazyflowSource(channelProvider.Output) inputChannelLayer = AlphaModulatedLayer( channelSrc, tintColor=input_channel_colors[channel], range=drange, normalize=drange) inputChannelLayer.opacity = 0.5 inputChannelLayer.visible = True inputChannelLayer.name = "Input Channel " + str(channel) inputChannelLayer.setToolTip("Select input channel " + str(channel) + \ " if this prediction image contains the objects of interest.") layers.append(inputChannelLayer) if self._showDebug: #FIXME: We have to do that, because lazyflow doesn't have a way to make an operator partially ready curIndex = op.CurOperator.value if curIndex == 1: if op.BigRegions.ready(): lowThresholdSrc = LazyflowSource(op.BigRegions) lowThresholdLayer = ColortableLayer(lowThresholdSrc, binct) lowThresholdLayer.name = "After low threshold" lowThresholdLayer.visible = False lowThresholdLayer.opacity = 1.0 lowThresholdLayer.setToolTip( "Results of thresholding with the low pixel value threshold" ) layers.append(lowThresholdLayer) if op.FilteredSmallLabels.ready(): filteredSmallLabelsSrc = LazyflowSource( op.FilteredSmallLabels) #filteredSmallLabelsLayer = self.createStandardLayerFromSlot( op.FilteredSmallLabels ) filteredSmallLabelsLayer = ColortableLayer( filteredSmallLabelsSrc, binct) filteredSmallLabelsLayer.name = "After high threshold and size filter" filteredSmallLabelsLayer.visible = False filteredSmallLabelsLayer.opacity = 1.0 filteredSmallLabelsLayer.setToolTip( "Results of thresholding with the high pixel value threshold,\ followed by the size filter" ) layers.append(filteredSmallLabelsLayer) if op.SmallRegions.ready(): highThresholdSrc = LazyflowSource(op.SmallRegions) highThresholdLayer = ColortableLayer( highThresholdSrc, binct) highThresholdLayer.name = "After high threshold" highThresholdLayer.visible = False highThresholdLayer.opacity = 1.0 highThresholdLayer.setToolTip( "Results of thresholding with the high pixel value threshold" ) layers.append(highThresholdLayer) elif curIndex == 0: if op.BeforeSizeFilter.ready(): thSrc = LazyflowSource(op.BeforeSizeFilter) thLayer = ColortableLayer(thSrc, ct) thLayer.name = "Before size filter" thLayer.visible = False thLayer.opacity = 1.0 thLayer.setToolTip( "Results of thresholding before the size filter is applied" ) layers.append(thLayer) # Selected input channel, smoothed. if op.Smoothed.ready(): smoothedLayer = self.createStandardLayerFromSlot(op.Smoothed) smoothedLayer.name = "Smoothed input" smoothedLayer.visible = True smoothedLayer.opacity = 1.0 smoothedLayer.setToolTip( "Selected channel data, smoothed with a Gaussian with user-defined sigma" ) layers.append(smoothedLayer) # Show the raw input data rawSlot = self.topLevelOperatorView.RawInput if rawSlot.ready(): rawLayer = self.createStandardLayerFromSlot(rawSlot) rawLayer.name = "Raw data" rawLayer.visible = True rawLayer.opacity = 1.0 layers.append(rawLayer) return layers
def setupLayers(self): """ Called by our base class when one of our data slots has changed. This function creates a layer for each slot we want displayed in the volume editor. """ # Base class provides the label layer. layers = super(PixelClassificationGui, self).setupLayers() # Add the uncertainty estimate layer uncertaintySlot = self.topLevelOperatorView.UncertaintyEstimate if uncertaintySlot.ready(): uncertaintySrc = LazyflowSource(uncertaintySlot) uncertaintyLayer = AlphaModulatedLayer(uncertaintySrc, tintColor=QColor(Qt.cyan), range=(0.0, 1.0), normalize=(0.0, 1.0)) uncertaintyLayer.name = "Uncertainty" uncertaintyLayer.visible = False uncertaintyLayer.opacity = 1.0 uncertaintyLayer.shortcutRegistration = ( "Prediction Layers", "Show/Hide Uncertainty", QShortcut(QKeySequence("u"), self.viewerControlWidget(), uncertaintyLayer.toggleVisible), uncertaintyLayer) layers.append(uncertaintyLayer) labels = self.labelListData # Add each of the segmentations for channel, segmentationSlot in enumerate( self.topLevelOperatorView.SegmentationChannels): if segmentationSlot.ready() and channel < len(labels): ref_label = labels[channel] segsrc = LazyflowSource(segmentationSlot) segLayer = AlphaModulatedLayer(segsrc, tintColor=ref_label.pmapColor(), range=(0.0, 1.0), normalize=(0.0, 1.0)) segLayer.opacity = 1 segLayer.visible = False #self.labelingDrawerUi.liveUpdateButton.isChecked() segLayer.visibleChanged.connect( self.updateShowSegmentationCheckbox) def setLayerColor(c, segLayer=segLayer): segLayer.tintColor = c self._update_rendering() def setSegLayerName(n, segLayer=segLayer): oldname = segLayer.name newName = "Segmentation (%s)" % n segLayer.name = newName if not self.render: return if oldname in self._renderedLayers: label = self._renderedLayers.pop(oldname) self._renderedLayers[newName] = label setSegLayerName(ref_label.name) ref_label.pmapColorChanged.connect(setLayerColor) ref_label.nameChanged.connect(setSegLayerName) #check if layer is 3d before adding the "Toggle 3D" option #this check is done this way to match the VolumeRenderer, in #case different 3d-axistags should be rendered like t-x-y #_axiskeys = segmentationSlot.meta.getAxisKeys() if len(segmentationSlot.meta.shape) == 4: #the Renderer will cut out the last shape-dimension, so #we're checking for 4 dimensions self._setup_contexts(segLayer) layers.append(segLayer) # Add each of the predictions for channel, predictionSlot in enumerate( self.topLevelOperatorView.PredictionProbabilityChannels): if predictionSlot.ready() and channel < len(labels): ref_label = labels[channel] predictsrc = LazyflowSource(predictionSlot) predictLayer = AlphaModulatedLayer( predictsrc, tintColor=ref_label.pmapColor(), range=(0.0, 1.0), normalize=(0.0, 1.0)) predictLayer.opacity = 0.25 predictLayer.visible = self.labelingDrawerUi.liveUpdateButton.isChecked( ) predictLayer.visibleChanged.connect( self.updateShowPredictionCheckbox) def setLayerColor(c, predictLayer=predictLayer): predictLayer.tintColor = c def setPredLayerName(n, predictLayer=predictLayer): newName = "Prediction for %s" % n predictLayer.name = newName setPredLayerName(ref_label.name) ref_label.pmapColorChanged.connect(setLayerColor) ref_label.nameChanged.connect(setPredLayerName) layers.append(predictLayer) # Add the raw data last (on the bottom) inputDataSlot = self.topLevelOperatorView.InputImages if inputDataSlot.ready(): inputLayer = self.createStandardLayerFromSlot(inputDataSlot) inputLayer.name = "Input Data" inputLayer.visible = True inputLayer.opacity = 1.0 def toggleTopToBottom(): index = self.layerstack.layerIndex(inputLayer) self.layerstack.selectRow(index) if index == 0: self.layerstack.moveSelectedToBottom() else: self.layerstack.moveSelectedToTop() inputLayer.shortcutRegistration = ("Prediction Layers", "Bring Input To Top/Bottom", QShortcut( QKeySequence("i"), self.viewerControlWidget(), toggleTopToBottom), inputLayer) layers.append(inputLayer) self.handleLabelSelectionChange() return layers
def createStandardLayerFromSlot(self, slot, lastChannelIsAlpha=False): """ Generate a volumina layer using the given slot. Choose between grayscale or RGB depending on the number of channels. """ def getRange(meta): if 'drange' in meta: return meta.drange if numpy.issubdtype(meta.dtype, numpy.integer): # We assume that ints range up to their max possible value, return (0, numpy.iinfo(meta.dtype).max) else: # If we don't know the range of the data, create a layer that is auto-normalized. # See volumina.pixelpipeline.datasources for details. return 'autoPercentiles' # Examine channel dimension to determine Grayscale vs. RGB shape = slot.meta.shape normalize = getRange(slot.meta) try: channelAxisIndex = slot.meta.axistags.index('c') #assert channelAxisIndex < len(slot.meta.axistags), \ # "slot %s has shape = %r, axistags = %r, but no channel dimension" \ # % (slot.name, slot.meta.shape, slot.meta.axistags) numChannels = shape[channelAxisIndex] except: numChannels = 1 if lastChannelIsAlpha: assert numChannels <= 4, "Can't display a standard layer with more than four channels (with alpha). Your image has {} channels.".format( numChannels) else: assert numChannels <= 3, "Can't display a standard layer with more than three channels (with no alpha). Your image has {} channels.".format( numChannels) if numChannels == 1: assert not lastChannelIsAlpha, "Can't have an alpha channel if there is no color channel" source = LazyflowSource(slot) normSource = NormalizingSource(source, bounds=normalize) return GrayscaleLayer(normSource) assert numChannels > 2 or (numChannels == 2 and not lastChannelIsAlpha) redProvider = OpSingleChannelSelector(graph=slot.graph) redProvider.Input.connect(slot) redProvider.Index.setValue(0) redSource = LazyflowSource(redProvider.Output) redNormSource = NormalizingSource(redSource, bounds=normalize) greenProvider = OpSingleChannelSelector(graph=slot.graph) greenProvider.Input.connect(slot) greenProvider.Index.setValue(1) greenSource = LazyflowSource(greenProvider.Output) greenNormSource = NormalizingSource(greenSource, bounds=normalize) blueNormSource = None if numChannels > 3 or (numChannels == 3 and not lastChannelIsAlpha): blueProvider = OpSingleChannelSelector(graph=slot.graph) blueProvider.Input.connect(slot) blueProvider.Index.setValue(2) blueSource = LazyflowSource(blueProvider.Output) blueNormSource = NormalizingSource(blueSource, bounds=normalize) alphaNormSource = None if lastChannelIsAlpha: alphaProvider = OpSingleChannelSelector(graph=slot.graph) alphaProvider.Input.connect(slot) alphaProvider.Index.setValue(numChannels - 1) alphaSource = LazyflowSource(alphaProvider.Output) alphaNormSource = NormalizingSource(alphaSource, bounds=normalize) layer = RGBALayer(red=redNormSource, green=greenNormSource, blue=blueNormSource, alpha=alphaNormSource) return layer
def setupLayers(self, currentImageIndex): """ Called by our base class when one of our data slots has changed. This function creates a layer for each slot we want displayed in the volume editor. """ # Base class provides the label layer. layers = super(PixelClassificationGui, self).setupLayers(currentImageIndex) labels = self.labelListData # Add the uncertainty estimate layer uncertaintySlot = self.pipeline.UncertaintyEstimate[currentImageIndex] if uncertaintySlot.ready(): uncertaintySrc = LazyflowSource(uncertaintySlot) uncertaintyLayer = AlphaModulatedLayer(uncertaintySrc, tintColor=QColor(Qt.cyan), range=(0.0, 1.0), normalize=(0.0, 1.0)) uncertaintyLayer.name = "Uncertainty" uncertaintyLayer.visible = False uncertaintyLayer.opacity = 1.0 uncertaintyLayer.shortcutRegistration = ( "Prediction Layers", "Show/Hide Uncertainty", QShortcut(QKeySequence("u"), self.viewerControlWidget(), uncertaintyLayer.toggleVisible), uncertaintyLayer) layers.append(uncertaintyLayer) # Add each of the predictions for channel, predictionSlot in enumerate( self.pipeline.PredictionProbabilityChannels[currentImageIndex] ): if predictionSlot.ready() and channel < len(labels): ref_label = labels[channel] predictsrc = LazyflowSource(predictionSlot) predictLayer = AlphaModulatedLayer(predictsrc, tintColor=ref_label.color, range=(0.0, 1.0), normalize=(0.0, 1.0)) predictLayer.opacity = 0.25 predictLayer.visible = self.labelingDrawerUi.checkInteractive.isChecked( ) predictLayer.visibleChanged.connect( self.updateShowPredictionCheckbox) def setLayerColor(c): predictLayer.tintColor = c def setLayerName(n): newName = "Prediction for %s" % ref_label.name predictLayer.name = newName setLayerName(ref_label.name) ref_label.colorChanged.connect(setLayerColor) ref_label.nameChanged.connect(setLayerName) layers.append(predictLayer) # Add each of the segementations for channel, segmentationSlot in enumerate( self.pipeline.SegmentationChannels[currentImageIndex]): if segmentationSlot.ready() and channel < len(labels): ref_label = labels[channel] segsrc = LazyflowSource(segmentationSlot) segLayer = AlphaModulatedLayer(segsrc, tintColor=ref_label.color, range=(0.0, 1.0), normalize=(0.0, 1.0)) segLayer.opacity = 1 segLayer.visible = self.labelingDrawerUi.checkInteractive.isChecked( ) segLayer.visibleChanged.connect( self.updateShowSegmentationCheckbox) def setLayerColor(c): segLayer.tintColor = c def setLayerName(n): newName = "Segmentation (%s)" % ref_label.name segLayer.name = newName setLayerName(ref_label.name) ref_label.colorChanged.connect(setLayerColor) ref_label.nameChanged.connect(setLayerName) layers.append(segLayer) # Add the raw data last (on the bottom) inputDataSlot = self.pipeline.InputImages[currentImageIndex] if inputDataSlot.ready(): inputLayer = self.createStandardLayerFromSlot(inputDataSlot) inputLayer.name = "Input Data" inputLayer.visible = True inputLayer.opacity = 1.0 def toggleTopToBottom(): index = self.layerstack.layerIndex(inputLayer) self.layerstack.selectRow(index) if index == 0: self.layerstack.moveSelectedToBottom() else: self.layerstack.moveSelectedToTop() inputLayer.shortcutRegistration = ("Prediction Layers", "Bring Input To Top/Bottom", QShortcut( QKeySequence("i"), self.viewerControlWidget(), toggleTopToBottom), inputLayer) layers.append(inputLayer) return layers