def __init__(self, *args, **kwargs): super(OpDLClassification, self).__init__(*args, **kwargs) self.predict = OpPixelwiseClassifierPredict(parent=self) self.predict.name = "OpClassifierPredict" self.predict.Image.connect(self.InputImage) self.predict.Classifier.connect(self.Classifier) self.predict.LabelsCount.connect(self.NumClasses) self.PredictionProbabilities.connect(self.predict.PMaps) self.prediction_cache = OpBlockedArrayCache(parent=self) self.prediction_cache.name = "BlockedArrayCache" self.prediction_cache.inputs["Input"].connect(self.predict.PMaps) self.prediction_cache.BlockShape.connect(self.BlockShape) self.prediction_cache.inputs["fixAtCurrent"].connect(self.FreezePredictions) self.CachedPredictionProbabilities.connect(self.prediction_cache.Output) self.opPredictionSlicer = OpMultiArraySlicer2(parent=self) self.opPredictionSlicer.name = "opPredictionSlicer" self.opPredictionSlicer.Input.connect(self.prediction_cache.Output) self.opPredictionSlicer.AxisFlag.setValue("c") self.PredictionProbabilityChannels.connect(self.opPredictionSlicer.Slices) self.opSegmentor = OpMaxChannelIndicatorOperator(parent=self) # IMPROVEME: this "max channel" works for binary classification, but not when we have more than 2 classes self.opSegmentor.Input.connect(self.prediction_cache.Output) self.Segmentation.connect(self.opSegmentor.Output) self.opSegmentationSlicer = OpMultiArraySlicer2(parent=self) self.opSegmentationSlicer.name = "opSegmentationSlicer" self.opSegmentationSlicer.Input.connect(self.opSegmentor.Output) self.opSegmentationSlicer.AxisFlag.setValue("c") self.SegmentationChannels.connect(self.opSegmentationSlicer.Slices)
def __init__(self, *args, **kwargs): super(OpRegionFeatures, self).__init__(*args, **kwargs) # Distribute the raw data self.opRawTimeSlicer = OpMultiArraySlicer2(parent=self) self.opRawTimeSlicer.name = 'OpRegionFeatures.opRawTimeSlicer' self.opRawTimeSlicer.AxisFlag.setValue('t') self.opRawTimeSlicer.Input.connect(self.RawImage) assert self.opRawTimeSlicer.Slices.level == 1 # Distribute the labels self.opLabelTimeSlicer = OpMultiArraySlicer2(parent=self) self.opLabelTimeSlicer.name = 'OpRegionFeatures.opLabelTimeSlicer' self.opLabelTimeSlicer.AxisFlag.setValue('t') self.opLabelTimeSlicer.Input.connect(self.LabelImage) assert self.opLabelTimeSlicer.Slices.level == 1 self.opRegionFeatures3dBlocks = OperatorWrapper(OpRegionFeatures3d, operator_args=[], parent=self) assert self.opRegionFeatures3dBlocks.RawVolume.level == 1 assert self.opRegionFeatures3dBlocks.LabelVolume.level == 1 self.opRegionFeatures3dBlocks.RawVolume.connect(self.opRawTimeSlicer.Slices) self.opRegionFeatures3dBlocks.LabelVolume.connect(self.opLabelTimeSlicer.Slices) self.opRegionFeatures3dBlocks.Features.connect(self.Features) assert self.opRegionFeatures3dBlocks.Output.level == 1 self.opTimeStacker = OpMultiArrayStacker(parent=self) self.opTimeStacker.name = 'OpRegionFeatures.opTimeStacker' self.opTimeStacker.AxisFlag.setValue('t') assert self.opTimeStacker.Images.level == 1 self.opTimeStacker.Images.connect(self.opRegionFeatures3dBlocks.Output) # Connect our outputs self.Output.connect(self.opTimeStacker.Output)
def __init__(self, *args, **kwargs): super(OpPredictionPipeline, self).__init__(*args, **kwargs) # Random forest prediction using CACHED features. self.predict = OpClassifierPredict(parent=self) self.predict.name = "OpClassifierPredict" self.predict.Classifier.connect(self.Classifier) self.predict.Image.connect(self.CachedFeatureImages) self.predict.PredictionMask.connect(self.PredictionMask) self.predict.LabelsCount.connect(self.NumClasses) self.PredictionProbabilities.connect(self.predict.PMaps) # Alternate headless output: uint8 instead of float. # Note that drange is automatically updated. self.opConvertToUint8 = OpPixelOperator(parent=self) self.opConvertToUint8.Input.connect(self.predict.PMaps) self.opConvertToUint8.Function.setValue(lambda a: (255 * a).astype(numpy.uint8)) self.PredictionProbabilitiesUint8.connect(self.opConvertToUint8.Output) # Prediction cache for the GUI self.prediction_cache_gui = OpSlicedBlockedArrayCache(parent=self) self.prediction_cache_gui.name = "prediction_cache_gui" self.prediction_cache_gui.inputs["fixAtCurrent"].connect( self.FreezePredictions) self.prediction_cache_gui.inputs["Input"].connect(self.predict.PMaps) self.CachedPredictionProbabilities.connect( self.prediction_cache_gui.Output) # Also provide each prediction channel as a separate layer (for the GUI) self.opPredictionSlicer = OpMultiArraySlicer2(parent=self) self.opPredictionSlicer.name = "opPredictionSlicer" self.opPredictionSlicer.Input.connect(self.prediction_cache_gui.Output) self.opPredictionSlicer.AxisFlag.setValue('c') self.PredictionProbabilityChannels.connect( self.opPredictionSlicer.Slices) self.opSegmentor = OpMaxChannelIndicatorOperator(parent=self) self.opSegmentor.Input.connect(self.prediction_cache_gui.Output) self.opSegmentationSlicer = OpMultiArraySlicer2(parent=self) self.opSegmentationSlicer.name = "opSegmentationSlicer" self.opSegmentationSlicer.Input.connect(self.opSegmentor.Output) self.opSegmentationSlicer.AxisFlag.setValue('c') self.SegmentationChannels.connect(self.opSegmentationSlicer.Slices) # Create a layer for uncertainty estimate self.opUncertaintyEstimator = OpEnsembleMargin(parent=self) self.opUncertaintyEstimator.Input.connect( self.prediction_cache_gui.Output) # Cache the uncertainty so we get zeros for uncomputed points self.opUncertaintyCache = OpSlicedBlockedArrayCache(parent=self) self.opUncertaintyCache.name = "opUncertaintyCache" self.opUncertaintyCache.Input.connect( self.opUncertaintyEstimator.Output) self.opUncertaintyCache.fixAtCurrent.connect(self.FreezePredictions) self.UncertaintyEstimate.connect(self.opUncertaintyCache.Output)
def __init__(self, *args, **kwargs): super(OpPredictionPipeline, self).__init__(*args, **kwargs) # Random forest prediction using CACHED features. self.predict = OpClassifierPredict(parent=self) self.predict.name = "OpClassifierPredict" self.predict.Classifier.connect(self.Classifier) self.predict.Image.connect(self.CachedFeatureImages) self.predict.PredictionMask.connect(self.PredictionMask) self.predict.LabelsCount.connect(self.NumClasses) self.PredictionProbabilities.connect(self.predict.PMaps) # Prepare operator for Autocontext self.opConvertPMapsToInputPixelType = OpPixelOperator(parent=self) self.opConvertPMapsToInputPixelType.Input.connect(self.predict.PMaps) self.PredictionProbabilitiesAutocontext.connect( self.opConvertPMapsToInputPixelType.Output) # Prediction cache for the GUI self.prediction_cache_gui = OpSlicedBlockedArrayCache(parent=self) self.prediction_cache_gui.name = "prediction_cache_gui" self.prediction_cache_gui.inputs["fixAtCurrent"].connect( self.FreezePredictions) self.prediction_cache_gui.inputs["Input"].connect(self.predict.PMaps) self.CachedPredictionProbabilities.connect( self.prediction_cache_gui.Output) # Also provide each prediction channel as a separate layer (for the GUI) self.opPredictionSlicer = OpMultiArraySlicer2(parent=self) self.opPredictionSlicer.name = "opPredictionSlicer" self.opPredictionSlicer.Input.connect(self.prediction_cache_gui.Output) self.opPredictionSlicer.AxisFlag.setValue("c") self.PredictionProbabilityChannels.connect( self.opPredictionSlicer.Slices) self.opSegmentor = OpMaxChannelIndicatorOperator(parent=self) self.opSegmentor.Input.connect(self.prediction_cache_gui.Output) self.opSegmentationSlicer = OpMultiArraySlicer2(parent=self) self.opSegmentationSlicer.name = "opSegmentationSlicer" self.opSegmentationSlicer.Input.connect(self.opSegmentor.Output) self.opSegmentationSlicer.AxisFlag.setValue("c") self.SegmentationChannels.connect(self.opSegmentationSlicer.Slices) # Create a layer for uncertainty estimate self.opUncertaintyEstimator = OpEnsembleMargin(parent=self) self.opUncertaintyEstimator.Input.connect( self.prediction_cache_gui.Output) # Cache the uncertainty so we get zeros for uncomputed points self.opUncertaintyCache = OpSlicedBlockedArrayCache(parent=self) self.opUncertaintyCache.name = "opUncertaintyCache" self.opUncertaintyCache.Input.connect( self.opUncertaintyEstimator.Output) self.opUncertaintyCache.fixAtCurrent.connect(self.FreezePredictions) self.UncertaintyEstimate.connect(self.opUncertaintyCache.Output)
def _initPredictionLayers(self, predictionSlot): layers = [] opLane = self.topLevelOperatorView # Use a slicer to provide a separate slot for each channel layer opSlicer = OpMultiArraySlicer2(parent=opLane.viewed_operator().parent) opSlicer.Input.connect(predictionSlot) opSlicer.AxisFlag.setValue('c') for channel, channelSlot in enumerate(opSlicer.Slices): if channelSlot.ready(): drange = channelSlot.meta.drange or (0.0, 1.0) predictsrc = LazyflowSource(channelSlot) predictLayer = AlphaModulatedLayer( predictsrc, tintColor=QColor.fromRgba(self._colorTable16[channel + 1]), # FIXME: This is weird. Why are range and normalize both set to the same thing? range=drange, normalize=drange) predictLayer.opacity = 1.0 predictLayer.visible = True predictLayer.name = "Probability Channel #{}".format(channel + 1) layers.append(predictLayer) return layers
def __init__(self, *args, **kwargs): super(OpPredictionPipeline, self).__init__(*args, **kwargs) self.cacheless_predict = OpTikTorchClassifierPredict(parent=self) self.cacheless_predict.name = "OpTiktorchClassifierPredict (Cacheless Path)" self.cacheless_predict.ModelSession.connect(self.Classifier) self.cacheless_predict.Image.connect( self.RawImage) # <--- Not from cache self.cacheless_predict.LabelsCount.connect(self.NumClasses) self.predict = OpTikTorchClassifierPredict(parent=self) self.predict.name = "OpTiktorchClassifierPredict" self.predict.ModelSession.connect(self.Classifier) self.predict.Image.connect(self.RawImage) self.predict.LabelsCount.connect(self.NumClasses) self.predict.BlockShape.connect(self.BlockShape) self.splitReqests = OpBlockedArrayCache(parent=self) self.splitReqests.Input.connect(self.predict.PMaps) self.splitReqests.BlockShape.connect(self.predict.BlockShape) self.PredictionProbabilities.connect(self.splitReqests.Output) self.prediction_cache = OpBlockedArrayCache(parent=self) self.prediction_cache.name = "BlockedArrayCache" self.prediction_cache.fixAtCurrent.connect(self.FreezePredictions) self.prediction_cache.BlockShape.connect(self.BlockShape) self.prediction_cache.Input.connect(self.predict.PMaps) self.CachedPredictionProbabilities.connect( self.prediction_cache.Output) self.opPredictionSlicer = OpMultiArraySlicer2(parent=self) self.opPredictionSlicer.name = "opPredictionSlicer" self.opPredictionSlicer.Input.connect(self.prediction_cache.Output) self.opPredictionSlicer.AxisFlag.setValue("c") self.PredictionProbabilityChannels.connect( self.opPredictionSlicer.Slices)
def testBasicWithObjectDtype(self): """ Make sure the slicer works even if dtype is 'object' """ class SpecialNumber(object): def __init__(self, x): self.n = x data = numpy.ndarray(shape=(2,3), dtype=object) data = data.view(vigra.VigraArray) data.axistags = vigra.defaultAxistags('tc') for i in range(2): for j in range(3): data[i,j] = SpecialNumber(i*j) graph = Graph() opSlicer = OpMultiArraySlicer2(graph=graph) opSlicer.AxisFlag.setValue('t') opSlicer.Input.setValue( data ) assert len(opSlicer.Slices) == 2 assert opSlicer.Input.meta.dtype == numpy.object_ assert opSlicer.Slices[0].meta.dtype == numpy.object_ for i, slot in enumerate( opSlicer.Slices ): a = slot[:].wait() assert a.shape == (1,3) for j in range(3): val = a[0,j] assert type(val) == SpecialNumber assert val.n == i*j
def setup_method(self, method): graph = Graph() self.graph = graph # Data is tagged by channel data = numpy.indices((10,10,10,3))[3] data = data.view(vigra.VigraArray) data.axistags = vigra.defaultAxistags('xyzc') self.opProvider = OpArrayPiper(graph=graph) self.opProvider.Input.setValue(data) self.opSlicer = OpMultiArraySlicer2(graph=graph) self.opSlicer.AxisFlag.setValue('c') self.opSlicer.Input.connect(self.opProvider.Output)
def _initPredictionLayers(self, predictionSlot): layers = [] colors = [] names = [] opLane = self.topLevelOperatorView if opLane.PmapColors.ready(): colors = opLane.PmapColors.value if opLane.LabelNames.ready(): names = opLane.LabelNames.value # Use a slicer to provide a separate slot for each channel layer opSlicer = OpMultiArraySlicer2(parent=opLane.viewed_operator().parent) opSlicer.Input.connect(predictionSlot) opSlicer.AxisFlag.setValue("c") colors = [QColor(*c) for c in colors] for channel in range(len(colors), len(opSlicer.Slices)): colors.append(PredictionViewerGui.DefaultColors[channel]) for channel in range(len(names), len(opSlicer.Slices)): names.append("Class {}".format(channel + 1)) for channel, channelSlot in enumerate(opSlicer.Slices): if channelSlot.ready( ) and channel < len(colors) and channel < len(names): predictsrc = createDataSource(channelSlot) predictLayer = AlphaModulatedLayer(predictsrc, tintColor=colors[channel], range=(0.0, 1.0), normalize=(0.0, 1.0)) predictLayer.opacity = 0.25 predictLayer.visible = True predictLayer.name = names[channel] layers.append(predictLayer) return layers return colors
def __init__(self, *args, **kwargs): super(OpNNClassification, self).__init__(*args, **kwargs) self.predict = OpPixelwiseClassifierPredict(parent=self) self.predict.name = "OpClassifierPredict" self.predict.Image.connect(self.InputImage) self.predict.Classifier.connect(self.Classifier) self.predict.LabelsCount.connect(self.NumClasses) self.PredictionProbabilities.connect(self.predict.PMaps) self.prediction_cache = OpBlockedArrayCache(parent=self) self.prediction_cache.name = "BlockedArrayCache" self.prediction_cache.inputs["Input"].connect(self.predict.PMaps) self.prediction_cache.BlockShape.connect(self.BlockShape) self.prediction_cache.inputs["fixAtCurrent"].connect(self.FreezePredictions) self.CachedPredictionProbabilities.connect(self.prediction_cache.Output) self.opPredictionSlicer = OpMultiArraySlicer2(parent=self) self.opPredictionSlicer.name = "opPredictionSlicer" self.opPredictionSlicer.Input.connect(self.prediction_cache.Output) self.opPredictionSlicer.AxisFlag.setValue("c") self.PredictionProbabilityChannels.connect(self.opPredictionSlicer.Slices)
def __init__(self, *args, **kwargs): """ Set up the internal pipeline. Since each labeling operator can only handle a single time and channel, we split the volume along time and channel axes to produce N 3D volumes, where N=T*C. The volumes are combined again into a 5D volume on the output using stackers. See ascii schematic in comments above for an overview. """ super(_OpLabelImage, self).__init__(*args, **kwargs) self.opTimeSlicer = OpMultiArraySlicer2(parent=self) self.opTimeSlicer.AxisFlag.setValue("t") self.opTimeSlicer.Input.connect(self.Input) assert self.opTimeSlicer.Slices.level == 1 self.opChannelSlicer = OperatorWrapper(OpMultiArraySlicer2, parent=self) self.opChannelSlicer.AxisFlag.setValue("c") self.opChannelSlicer.Input.connect(self.opTimeSlicer.Slices) assert self.opChannelSlicer.Slices.level == 2 class OpWrappedVigraLabelVolume(Operator): """ This quick hack is necessary because there's not currently a way to wrap an OperatorWrapper. We need to double-wrap OpVigraLabelVolume, so we need this operator to provide the first level of wrapping. """ Input = InputSlot(level=1) BackgroundValue = InputSlot(optional=True, level=1) Output = OutputSlot(level=1) def __init__(self, *args, **kwargs): super(OpWrappedVigraLabelVolume, self).__init__(*args, **kwargs) self._innerOperator = OperatorWrapper(OpVigraLabelVolume, parent=self) self._innerOperator.Input.connect(self.Input) self._innerOperator.BackgroundValue.connect( self.BackgroundValue) self.Output.connect(self._innerOperator.Output) def execute(self, slot, subindex, roi, destination): assert False, "Shouldn't get here." def propagateDirty(self, slot, subindex, roi): pass # Nothing to do... # Wrap OpVigraLabelVolume TWICE. self.opLabelers = OperatorWrapper(OpWrappedVigraLabelVolume, parent=self) assert self.opLabelers.Input.level == 2 self.opLabelers.Input.connect(self.opChannelSlicer.Slices) # The background labels will be converted to a VigraArray with axistags 'tc' so they can # be distributed to the labeling operators via slicers in the same manner as the input data. # Here, we set up the slicers that will distribute the background labels to the appropriate labelers. self.opBgTimeSlicer = OpMultiArraySlicer2(parent=self) self.opBgTimeSlicer.AxisFlag.setValue("t") assert self.opBgTimeSlicer.Slices.level == 1 self.opBgChannelSlicer = OperatorWrapper(OpMultiArraySlicer2, parent=self) self.opBgChannelSlicer.AxisFlag.setValue("c") self.opBgChannelSlicer.Input.connect(self.opBgTimeSlicer.Slices) assert self.opBgChannelSlicer.Slices.level == 2 assert self.opLabelers.BackgroundValue.level == 2 self.opLabelers.BackgroundValue.connect(self.opBgChannelSlicer.Slices) self.opChannelStacker = OperatorWrapper(OpMultiArrayStacker, parent=self) self.opChannelStacker.AxisFlag.setValue("c") assert self.opLabelers.Output.level == 2 assert self.opChannelStacker.Images.level == 2 self.opChannelStacker.Images.connect(self.opLabelers.Output) self.opTimeStacker = OpMultiArrayStacker(parent=self) self.opTimeStacker.AxisFlag.setValue("t") assert self.opChannelStacker.Output.level == 1 assert self.opTimeStacker.Images.level == 1 self.opTimeStacker.Images.connect(self.opChannelStacker.Output) # Connect our outputs self.Output.connect(self.opTimeStacker.Output)
def __init__(self, *args, **kwargs): super(OpVigraWatershedViewer, self).__init__(*args, **kwargs) self._seedThreshold = None # Overview Schematic # Example here uses input channels 0,2,5 # InputChannelIndexes=[0,2,5] ---- # \ # InputImage --> opChannelSlicer .Slices[0] ---\ # .Slices[1] ----> opAverage -------------------------------------------------> opWatershed --> opWatershedCache --> opColorizer --> GUI # .Slices[2] ---/ \ / # \ MinSeedSize / # \ \ / # SeedThresholdValue ----------> opThreshold --> opSeedLabeler --> opSeedFilter --> opSeedCache --> opSeedColorizer --> GUI # Create operators self.opChannelSlicer = OpMultiArraySlicer2(parent=self) self.opAverage = OpMultiArrayMerger(parent=self) self.opWatershed = OpVigraWatershed(parent=self) self.opWatershedCache = OpSlicedBlockedArrayCache(parent=self) self.opColorizer = OpColorizeLabels(parent=self) self.opThreshold = OpPixelOperator(parent=self) self.opSeedLabeler = OpVigraLabelVolume(parent=self) self.opSeedFilter = OpFilterLabels(parent=self) self.opSeedCache = OpSlicedBlockedArrayCache(parent=self) self.opSeedColorizer = OpColorizeLabels(parent=self) # Select specific input channels self.opChannelSlicer.Input.connect(self.InputImage) self.opChannelSlicer.SliceIndexes.connect(self.InputChannelIndexes) self.opChannelSlicer.AxisFlag.setValue('c') # Average selected channels def average(arrays): if len(arrays) == 0: return 0 else: return sum(arrays) / float(len(arrays)) self.opAverage.MergingFunction.setValue(average) self.opAverage.Inputs.connect(self.opChannelSlicer.Slices) # Threshold for seeds self.opThreshold.Input.connect(self.opAverage.Output) # Label seeds self.opSeedLabeler.Input.connect(self.opThreshold.Output) # Filter seeds self.opSeedFilter.MinLabelSize.connect(self.MinSeedSize) self.opSeedFilter.Input.connect(self.opSeedLabeler.Output) # Cache seeds self.opSeedCache.fixAtCurrent.connect(self.FreezeCache) self.opSeedCache.Input.connect(self.opSeedFilter.Output) # Color seeds for RBG display self.opSeedColorizer.Input.connect(self.opSeedCache.Output) self.opSeedColorizer.OverrideColors.setValue({0: (0, 0, 0, 0)}) # Compute watershed labels (possibly with seeds, see setupOutputs) self.opWatershed.InputImage.connect(self.opAverage.Output) self.opWatershed.PaddingWidth.connect(self.WatershedPadding) # Cache the watershed output self.opWatershedCache.fixAtCurrent.connect(self.FreezeCache) self.opWatershedCache.Input.connect(self.opWatershed.Output) # Colorize the watershed labels for RGB display self.opColorizer.Input.connect(self.opWatershedCache.Output) self.opColorizer.OverrideColors.connect(self.OverrideLabels) # Connnect external outputs the operators that provide them self.Seeds.connect(self.opSeedCache.Output) self.ColoredPixels.connect(self.opColorizer.Output) self.SelectedInputChannels.connect(self.opChannelSlicer.Slices) self.SummedInput.connect(self.opAverage.Output) self.ColoredSeeds.connect(self.opSeedColorizer.Output)