def __init__(self, *args, **kwargs): super(OpPredictionPipelineNoCache, self).__init__(*args, **kwargs) # Random forest prediction using the raw feature image slot (not the cached features) # This would be bad for interactive labeling, but it's good for headless flows # because it avoids the overhead of cache. self.cacheless_predict = OpClassifierPredict(parent=self) self.cacheless_predict.name = "OpClassifierPredict (Cacheless Path)" self.cacheless_predict.Classifier.connect(self.Classifier) self.cacheless_predict.Image.connect( self.FeatureImages) # <--- Not from cache self.cacheless_predict.LabelsCount.connect(self.NumClasses) self.cacheless_predict.PredictionMask.connect(self.PredictionMask) self.HeadlessPredictionProbabilities.connect( self.cacheless_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.cacheless_predict.PMaps) self.opConvertToUint8.Function.setValue(lambda a: (255 * a).astype(numpy.uint8)) self.HeadlessUint8PredictionProbabilities.connect( self.opConvertToUint8.Output) self.opArgmaxChannel = OpArgmaxChannel(parent=self) self.opArgmaxChannel.Input.connect(self.cacheless_predict.PMaps) self.SimpleSegmentation.connect(self.opArgmaxChannel.Output) # Create a layer for uncertainty estimate self.opUncertaintyEstimator = OpEnsembleMargin(parent=self) self.opUncertaintyEstimator.Input.connect(self.cacheless_predict.PMaps) self.HeadlessUncertaintyEstimate.connect( self.opUncertaintyEstimator.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 __init__(self, *args, **kwargs): super(_OpThresholdOneLevel, self).__init__(*args, **kwargs) self._opThresholder = OpPixelOperator(parent=self) self._opThresholder.Input.connect(self.InputImage) self._opLabeler = OpLabelVolume(parent=self) self._opLabeler.Method.setValue(_labeling_impl) self._opLabeler.Input.connect(self._opThresholder.Output) self.BeforeSizeFilter.connect(self._opLabeler.Output) self._opFilter = OpFilterLabels(parent=self) self._opFilter.Input.connect(self._opLabeler.Output) self._opFilter.MinLabelSize.connect(self.MinSize) self._opFilter.MaxLabelSize.connect(self.MaxSize) self._opFilter.BinaryOut.setValue(False) self.Output.connect(self._opFilter.Output)
def __init__(self, *args, **kwargs): super(OpPredictionPipelineNoCache, self).__init__(*args, **kwargs) # Random forest prediction using the raw feature image slot (not the cached features) # This would be bad for interactive labeling, but it's good for headless flows # because it avoids the overhead of cache. self.cacheless_predict = OpPredictRandomForest(parent=self) self.cacheless_predict.name = "OpPredictRandomForest (Cacheless Path)" self.cacheless_predict.inputs['Classifier'].connect(self.Classifier) self.cacheless_predict.inputs['Image'].connect( self.FeatureImages) # <--- Not from cache self.cacheless_predict.inputs['LabelsCount'].connect(self.MaxLabel) self.HeadlessPredictionProbabilities.connect( self.cacheless_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.cacheless_predict.PMaps) self.opConvertToUint8.Function.setValue(lambda a: (255 * a).astype(numpy.uint8)) self.HeadlessUint8PredictionProbabilities.connect( self.opConvertToUint8.Output)
def testBasic(self): """ Test the OpPrecomputedInput oeprator. """ graph = Graph() dataShape = (1, 10, 10, 10, 1) data = numpy.indices(dataShape) precomputedData = data * 10 computeCount = [0] def compute(x): computeCount[0] += 1 return x * 10 opSlow = OpPixelOperator(graph=graph) opSlow.Input.setValue(data) opSlow.Function.setValue(compute) opFast = OpArrayPiper(graph=graph) opFast.Input.setValue(precomputedData) op = OpPrecomputedInput(ignore_dirty_input=False, graph=graph) op.SlowInput.connect(opSlow.Output) # Should use slow input if no fast input is provided. computeCount[0] = 0 result = op.Output[...].wait() assert (result == precomputedData).all() assert computeCount[0] == 1 # Provide a fast input, which it should immediately start using. op.PrecomputedInput.connect(opFast.Output) # When input is still clean, it should use the fast input computeCount[0] = 0 result = op.Output[...].wait() assert (result == precomputedData).all() assert computeCount[0] == 0 # Subscribe to dirty output notifications dirtyRois = [] def handleDirty(slot, roi): dirtyRois.append(roi) op.Output.notifyDirty(handleDirty) # Mark the slow input dirty. Did the output see it? # (Output should see the dirty roi from the slow input even # though it was previously connected to the fast input). opSlow.Input.setDirty(slice(None)) assert len(dirtyRois) == 1 # Op should switch to the slow input. result = op.Output[...].wait() assert (result == precomputedData).all() assert computeCount[0] == 1 # Reset the operator. Compute count should not change. computeCount[0] = 0 op.Reset.setValue(True) op.Reset.setValue(False) result = op.Output[...].wait() assert (result == precomputedData).all() assert computeCount[0] == 0
def __init__(self, *args, **kwargs): super(_OpThresholdTwoLevels, self).__init__(*args, **kwargs) self._opLowThresholder = OpPixelOperator(parent=self) self._opLowThresholder.Input.connect(self.InputImage) self._opHighThresholder = OpPixelOperator(parent=self) self._opHighThresholder.Input.connect(self.InputImage) self._opLowLabeler = OpLabelVolume(parent=self) self._opLowLabeler.Method.setValue(_labeling_impl) self._opLowLabeler.Input.connect(self._opLowThresholder.Output) self._opHighLabeler = OpLabelVolume(parent=self) self._opHighLabeler.Method.setValue(_labeling_impl) self._opHighLabeler.Input.connect(self._opHighThresholder.Output) self._opHighLabelSizeFilter = OpFilterLabels(parent=self) self._opHighLabelSizeFilter.Input.connect(self._opHighLabeler.Output) self._opHighLabelSizeFilter.MinLabelSize.connect(self.MinSize) self._opHighLabelSizeFilter.MaxLabelSize.connect(self.MaxSize) self._opHighLabelSizeFilter.BinaryOut.setValue( False) # we do the binarization in opSelectLabels # this way, we get to display pretty colors self._opSelectLabels = OpSelectLabels(parent=self) self._opSelectLabels.BigLabels.connect(self._opLowLabeler.Output) self._opSelectLabels.SmallLabels.connect( self._opHighLabelSizeFilter.Output) # remove the remaining very large objects - # they might still be present in case a big object # was split into many small ones for the higher threshold # and they got reconnected again at lower threshold self._opFinalLabelSizeFilter = OpFilterLabels(parent=self) self._opFinalLabelSizeFilter.Input.connect(self._opSelectLabels.Output) self._opFinalLabelSizeFilter.MinLabelSize.connect(self.MinSize) self._opFinalLabelSizeFilter.MaxLabelSize.connect(self.MaxSize) self._opFinalLabelSizeFilter.BinaryOut.setValue(False) self._opCache = OpCompressedCache(parent=self) self._opCache.name = "_OpThresholdTwoLevels._opCache" self._opCache.InputHdf5.connect(self.InputHdf5) self._opCache.Input.connect(self._opFinalLabelSizeFilter.Output) # Connect our own outputs self.Output.connect(self._opFinalLabelSizeFilter.Output) self.CachedOutput.connect(self._opCache.Output) # Serialization outputs self.CleanBlocks.connect(self._opCache.CleanBlocks) self.OutputHdf5.connect(self._opCache.OutputHdf5) #self.InputChannel.connect( self._opChannelSelector.Output ) # More debug outputs. These all go through their own caches self._opBigRegionCache = OpCompressedCache(parent=self) self._opBigRegionCache.name = "_OpThresholdTwoLevels._opBigRegionCache" self._opBigRegionCache.Input.connect(self._opLowThresholder.Output) self.BigRegions.connect(self._opBigRegionCache.Output) self._opSmallRegionCache = OpCompressedCache(parent=self) self._opSmallRegionCache.name = "_OpThresholdTwoLevels._opSmallRegionCache" self._opSmallRegionCache.Input.connect(self._opHighThresholder.Output) self.SmallRegions.connect(self._opSmallRegionCache.Output) self._opFilteredSmallLabelsCache = OpCompressedCache(parent=self) self._opFilteredSmallLabelsCache.name = "_OpThresholdTwoLevels._opFilteredSmallLabelsCache" self._opFilteredSmallLabelsCache.Input.connect( self._opHighLabelSizeFilter.Output) self._opColorizeSmallLabels = OpColorizeLabels(parent=self) self._opColorizeSmallLabels.Input.connect( self._opFilteredSmallLabelsCache.Output) self.FilteredSmallLabels.connect(self._opColorizeSmallLabels.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)