Exemplo n.º 1
0
    def testBasic(self):
        start = TinyVector([10, 100, 200, 300, 1])
        stop = TinyVector([11, 150, 300, 500, 3])
        image_shape = [20, 152, 500, 500, 10]
        
        sigma = 3.1
        window = 2
        enlarge_axes = (False, True, True, True, False)
        
        enlarged_start, enlarged_stop = enlargeRoiForHalo(start, stop, image_shape, sigma, window, enlarge_axes )
        
        full_halo_width = numpy.ceil(sigma*window)
        
        # Non-enlarged axes should remain the same
        assert (enlarged_start[[0,4]] == (start[0], start[4])).all(), \
            "{} == {}".format( enlarged_start[[0,4]], (start[0], start[4]) )
        assert (enlarged_stop[[0,4]] == (stop[0], stop[4])).all(), \
            "{} == {}".format( enlarged_stop[[0,4]], (stop[0], stop[4]) )
        
        # The start coord isn't close to the image border, so the halo should be full-sized on the start side
        assert (enlarged_start[1:4] == numpy.array(start)[1:4] - full_halo_width).all()

        # The stop coord is close to the image border in some dimensions, 
        #  so some axes couldn't be expanded by the full halo width.
        assert enlarged_stop[1] == 152
        assert enlarged_stop[2] == stop[2] + full_halo_width
        assert enlarged_stop[3] == 500
Exemplo n.º 2
0
    def _getInputComputeRois(self, roi):
        shape = self.Input.meta.shape
        start = numpy.asarray(roi.start)
        stop = numpy.asarray(roi.stop)
        n = len(stop)
        spatStart = [roi.start[i] for i in range(n) if shape[i] > 1]
        spatStop = [roi.stop[i] for i in range(n) if shape[i] > 1]
        sigma = [0] + map(self._sigmas.get, 'xyz') + [0]
        spatialRoi = (spatStart, spatStop)

        inputSpatialRoi = enlargeRoiForHalo(roi.start, roi.stop, shape,
                                      sigma, window=2.0)

        # Determine the roi within the input data we're going to request
        inputRoiOffset = roi.start - inputSpatialRoi[0]
        computeRoi = [inputRoiOffset, inputRoiOffset + stop - start]
        for i in (0, 1):
            computeRoi[i] = [computeRoi[i][j] for j in range(n)
                             if shape[j] > 1 and j not in (0, 4)]

        # make sure that vigra understands our integer types
        computeRoi = (tuple(map(int, computeRoi[0])),
                      tuple(map(int, computeRoi[1])))

        inputRoi = (list(inputSpatialRoi[0]), list(inputSpatialRoi[1]))

        return inputRoi, computeRoi
Exemplo n.º 3
0
    def _collect_blocks(self, image_slot, label_slot, block_slicings):
        model = self.ModelSession.value
        image_data_blocks = []
        label_data_blocks = []
        block_ids = []
        for block_slicing in block_slicings:
            # Get labels
            block_label_roi = sliceToRoi(block_slicing, label_slot.meta.shape)
            block_label_data = label_slot(*block_label_roi).wait()

            bb_roi_within_block = numpy.array([[0] *
                                               len(block_label_data.shape),
                                               list(block_label_data.shape)])
            block_label_bb_roi = bb_roi_within_block + block_label_roi[0]

            # Ask for the halo needed by the classifier
            axiskeys = image_slot.meta.getAxisKeys()
            halo_shape = model.get_halo(axiskeys)
            assert len(halo_shape) == len(block_label_roi[0])
            assert halo_shape[
                -1] == 0, "Didn't expect a non-zero halo for channel dimension."

            # Expand block by halo, but keep clipped to image bounds
            padded_label_roi, bb_roi_within_padded = enlargeRoiForHalo(
                *block_label_bb_roi,
                shape=label_slot.meta.shape,
                sigma=halo_shape,
                window=1,
                return_result_roi=True)

            # Copy labels to new array, which has size == bounding-box + halo
            padded_label_data = numpy.zeros(
                padded_label_roi[1] - padded_label_roi[0],
                label_slot.meta.dtype)
            padded_label_data[roiToSlice(
                *bb_roi_within_padded)] = block_label_data[roiToSlice(
                    *bb_roi_within_block)]

            padded_image_roi = numpy.array(padded_label_roi)
            assert (padded_image_roi[:, -1] == [0, 1]).all()
            num_channels = image_slot.meta.shape[-1]
            padded_image_roi[:, -1] = [0, num_channels]

            # Ensure the results are plain ndarray, not VigraArray,
            #  which some classifiers might have trouble with.
            padded_image_data = numpy.asarray(
                image_slot(*padded_image_roi).wait())

            image_data_blocks.append(padded_image_data)
            label_data_blocks.append(padded_label_data)
            block_ids.append(
                tuple(
                    int(block_label_bb_roi[0][i])
                    for i, key in enumerate(axiskeys) if key != "c"))

        return image_data_blocks, label_data_blocks, block_ids
Exemplo n.º 4
0
 def execute(self, slot, subindex, roi, result):
     sigma = 3.0
     roi_with_halo, result_roi = enlargeRoiForHalo(
         roi.start, roi.stop, self.Input.meta.shape, sigma, return_result_roi=True
     )
     start, stop = roi_with_halo
     newroi = SubRegion(self.Input, start=start, stop=stop)
     data = self.Input.get(newroi).wait()
     time.sleep(self.delay)
     result[:] = data[roiToSlice(*result_roi)]
 def execute(self, slot, subindex, roi, result):
     sigma = 3.0
     roi_with_halo, result_roi = enlargeRoiForHalo(
         roi.start, roi.stop, self.Input.meta.shape, sigma, return_result_roi=True
     )
     start, stop = roi_with_halo
     newroi = SubRegion(self.Input, start=start, stop=stop)
     data = self.Input.get(newroi).wait()
     time.sleep(self.delay)
     result[:] = data[roiToSlice(*result_roi)]
Exemplo n.º 6
0
    def _getInputComputeRois(self, roi):
        axiskeys = self.Input.meta.getAxisKeys()
        spatialkeys = [k for k in axiskeys if k in 'zyx']
        sigma = list(map(self._sigmas.get, spatialkeys))
        inputSpatialShape = self.Input.meta.getTaggedShape()
        spatialRoi = (TinyVector(roi.start), TinyVector(roi.stop))
        tIndex = None
        cIndex = None
        zIndex = None
        if 'c' in inputSpatialShape:
            del inputSpatialShape['c']
            cIndex = axiskeys.index('c')
        if 't' in list(inputSpatialShape.keys()):
            assert inputSpatialShape['t'] == 1
            tIndex = axiskeys.index('t')

        if 'z' in list(
                inputSpatialShape.keys()) and inputSpatialShape['z'] == 1:
            #2D image, avoid kernel longer than line exception
            del inputSpatialShape['z']
            zIndex = axiskeys.index('z')

        indices = [tIndex, cIndex, zIndex]
        indices = sorted(indices, reverse=True)
        for ind in indices:
            if ind:
                spatialRoi[0].pop(ind)
                spatialRoi[1].pop(ind)

        inputSpatialRoi = enlargeRoiForHalo(spatialRoi[0],
                                            spatialRoi[1],
                                            list(inputSpatialShape.values()),
                                            sigma,
                                            window=2.0)

        # Determine the roi within the input data we're going to request
        inputRoiOffset = spatialRoi[0] - inputSpatialRoi[0]
        computeRoi = (inputRoiOffset,
                      inputRoiOffset + spatialRoi[1] - spatialRoi[0])

        # For some reason, vigra.filters.gaussianSmoothing will raise an exception if this parameter doesn't have the correct integer type.
        # (for example, if we give it as a numpy.ndarray with dtype=int64, we get an error)
        computeRoi = (tuple(map(int,
                                computeRoi[0])), tuple(map(int,
                                                           computeRoi[1])))

        inputRoi = (list(inputSpatialRoi[0]), list(inputSpatialRoi[1]))
        for ind in reversed(indices):
            if ind:
                inputRoi[0].insert(ind, 0)
                inputRoi[1].insert(ind, 1)

        return inputRoi, computeRoi
Exemplo n.º 7
0
    def _getInputComputeRois(self, roi):
        axiskeys = self.Input.meta.getAxisKeys()
        spatialkeys = filter( lambda k: k in 'xyz', axiskeys )
        sigma = map( self._sigmas.get, spatialkeys )
        inputSpatialShape = self.Input.meta.getTaggedShape()
        spatialRoi = ( TinyVector(roi.start), TinyVector(roi.stop) )
        tIndex = None
        cIndex = None
        zIndex = None
        if 'c' in inputSpatialShape:
            del inputSpatialShape['c']
            cIndex = axiskeys.index('c')
        if 't' in inputSpatialShape.keys():
            assert inputSpatialShape['t'] == 1
            tIndex = axiskeys.index('t')

        if 'z' in inputSpatialShape.keys() and inputSpatialShape['z']==1:
            #2D image, avoid kernel longer than line exception
            del inputSpatialShape['z']
            zIndex = axiskeys.index('z')
            
        indices = [tIndex, cIndex, zIndex]
        indices = sorted(indices, reverse=True)
        for ind in indices:
            if ind:
                spatialRoi[0].pop(ind)
                spatialRoi[1].pop(ind)
        
        inputSpatialRoi = enlargeRoiForHalo(spatialRoi[0], spatialRoi[1], inputSpatialShape.values(), sigma, window=2.0)
        
        # Determine the roi within the input data we're going to request
        inputRoiOffset = spatialRoi[0] - inputSpatialRoi[0]
        computeRoi = (inputRoiOffset, inputRoiOffset + spatialRoi[1] - spatialRoi[0])
        
        # For some reason, vigra.filters.gaussianSmoothing will raise an exception if this parameter doesn't have the correct integer type.
        # (for example, if we give it as a numpy.ndarray with dtype=int64, we get an error)
        computeRoi = ( tuple(map(int, computeRoi[0])),
                       tuple(map(int, computeRoi[1])) )
        
        inputRoi = (list(inputSpatialRoi[0]), list(inputSpatialRoi[1]))
        for ind in reversed(indices):
            if ind:
                inputRoi[0].insert( ind, 0 )
                inputRoi[1].insert( ind, 1 )

        return inputRoi, computeRoi
    def _enlarge_roi_for_halo(self, start, stop):
        """
        Given a roi of INPUT coordinates (3D+c, not 3D+ij),
          enlarge it with an appropriate halo.  Also return the "result roi".
        (See enlargeRoiForHalo() docs for details.)
        """
        assert len(self.Input.meta.shape) == 4, "Data must be exactly 3D+c (no time axis)"
        assert self.Input.meta.getAxisKeys()[-1] == 'c'

        spatial_axes = (True, True, True, False) # don't enlarge channel roi
        enlarged_roi, result_roi = enlargeRoiForHalo( start, 
                                                      stop, 
                                                      self.Input.meta.shape, 
                                                      self.Sigma.value, 
                                                      window=self.WINDOW_SIZE, 
                                                      enlarge_axes=spatial_axes,
                                                      return_result_roi=True )
        return enlarged_roi, result_roi
    def _enlarge_roi_for_halo(self, start, stop):
        """
        Given a roi of INPUT coordinates (3D+c, not 3D+ij),
          enlarge it with an appropriate halo.  Also return the "result roi".
        (See enlargeRoiForHalo() docs for details.)
        """
        assert len(self.Input.meta.shape) == 4, "Data must be exactly 3D+c (no time axis)"
        assert self.Input.meta.getAxisKeys()[-1] == 'c'

        spatial_axes = (True, True, True, False) # don't enlarge channel roi
        enlarged_roi, result_roi = enlargeRoiForHalo( start, 
                                                      stop, 
                                                      self.Input.meta.shape, 
                                                      self.Sigma.value, 
                                                      window=self.WINDOW_SIZE, 
                                                      enlarge_axes=spatial_axes,
                                                      return_result_roi=True )
        return enlarged_roi, result_roi
Exemplo n.º 10
0
    def propagateDirty(self, slot, subindex, rroi):
        # If some input we don't know about is dirty (i.e. we are subclassed by an operator with extra inputs),
        # then mark the entire output dirty.  This is the correct behavior for e.g. 'sigma' inputs.
        out_dirty = slice(None)

        # Check for proper name because subclasses may define extra inputs.
        # (but decline to override notifyDirty)
        if slot is self.Input:
            out_dirty = list(rroi.toSlice())
            out_dirty[1] = slice(
                None
            )  # todo: map dirty input channels to dirty output channels

            if self.invalid_z or self.ComputeIn2d.value:
                axes2enlarge = [0, 0, 0, 1, 1]
            else:
                axes2enlarge = [0, 0, 1, 1, 1]

            output_shape = self.Output.meta.shape
            rroi = roi.sliceToRoi(out_dirty, output_shape)

            out_dirty = roi.roiToSlice(
                *roi.enlargeRoiForHalo(rroi[0],
                                       rroi[1],
                                       output_shape,
                                       self.max_sigma,
                                       window=self.window_size_smoother,
                                       enlarge_axes=axes2enlarge))

        elif slot is self.ComputeIn2d:
            if self.invalid_z:
                # Output is computed in 2D anyway due to a small z dimension
                if not self.ComputeIn2d.value:
                    logger.warning(
                        f'{self.name}: filtering in 2d for {self.filter_kwargs} (z dimension too small)'
                    )

                return

        self.Output.setDirty(out_dirty)
Exemplo n.º 11
0
    def execute(self, slot, subindex, slot_roi, target):
        assert slot == self.Features or slot == self.Output
        if slot == self.Features:
            feature_slice = roiToSlice(slot_roi.start, slot_roi.stop)
            index = subindex[0]
            feature_slice = list(feature_slice)

            # Translate channel slice of this feature to the channel slice of the output slot.
            output_channel_offset = self.featureOutputChannels[index][0]
            feature_slice[1] = slice(
                output_channel_offset + feature_slice[1].start, output_channel_offset + feature_slice[1].stop
            )
            slot_roi = SubRegion(self.Output, pslice=feature_slice)

            # Get output slot region for this channel
            return self.execute(self.Output, (), slot_roi, target)
        elif slot == self.Output:
            # Correlation of variable 'families' representing reference frames:
            #  ______________________________
            # | input/output frame           |  input/output shape given by slots
            # |  _________________________   |
            # | | smooth frame            |  |  pre-smoothing op needs halo around filter roi
            # | |  ____________________   |  |
            # | | |filter frame        |  |  |  filter needs halo around target roi
            # | | |  _______________   |  |  |
            # | | | | target frame  |  |  |  |  target is given by output_roi

            # note: The 'full_' variable prefix refers to the full 5D shape (tczyx), without 'full_' variables mostly
            #       refer to the 3D space subregion (zyx)

            full_output_slice = slot_roi.toSlice()

            logger.debug(f"OpPixelFeaturesPresmoothed: request {slot_roi.pprint()}")

            assert (slot_roi.stop <= self.Output.meta.shape).all()

            full_output_shape = self.Output.meta.shape
            full_output_start, full_output_stop = sliceToRoi(full_output_slice, full_output_shape)
            assert len(full_output_shape) == 5
            if all(self.ComputeIn2d.value):  # todo: check for this particular slice
                axes2enlarge = (0, 1, 1)
            else:
                axes2enlarge = (1, 1, 1)

            output_shape = full_output_shape[2:]
            output_start = full_output_start[2:]
            output_stop = full_output_stop[2:]

            axistags = self.Output.meta.axistags
            target = target.view(vigra.VigraArray)
            target.axistags = copy.copy(axistags)

            # filter roi in input frame
            # sigma = 0.7, because the features receive a pre-smoothed array and don't need much of a neighborhood
            input_filter_start, input_filter_stop = roi.enlargeRoiForHalo(
                output_start, output_stop, output_shape, 0.7, self.WINDOW_SIZE, enlarge_axes=axes2enlarge
            )

            # smooth roi in input frame
            input_smooth_start, input_smooth_stop = roi.enlargeRoiForHalo(
                input_filter_start,
                input_filter_stop,
                output_shape,
                self.max_sigma,
                self.WINDOW_SIZE,
                enlarge_axes=axes2enlarge,
            )

            # target roi in filter frame
            filter_target_start = roi.TinyVector(output_start - input_filter_start)
            filter_target_stop = roi.TinyVector(output_stop - input_filter_start)

            # filter roi in smooth frame
            smooth_filter_start = roi.TinyVector(input_filter_start - input_smooth_start)
            smooth_filter_stop = roi.TinyVector(input_filter_stop - input_smooth_start)

            filter_target_slice = roi.roiToSlice(filter_target_start, filter_target_stop)
            input_smooth_slice = roi.roiToSlice(input_smooth_start, input_smooth_stop)

            # pre-smooth for all requested time slices and all channels
            full_input_smooth_slice = (full_output_slice[0], slice(None), *input_smooth_slice)
            req = self.Input[full_input_smooth_slice]
            source = req.wait()
            req.clean()
            req.destination = None
            if source.dtype != numpy.float32:
                sourceF = source.astype(numpy.float32)
                try:
                    source.resize((1,), refcheck=False)
                except Exception:
                    pass
                del source
                source = sourceF

            sourceV = source.view(vigra.VigraArray)
            sourceV.axistags = copy.copy(self.Input.meta.axistags)

            dimCol = len(self.scales)
            dimRow = self.matrix.shape[0]

            presmoothed_source = [None] * dimCol

            source_smooth_shape = tuple(smooth_filter_stop - smooth_filter_start)
            full_source_smooth_shape = (
                full_output_stop[0] - full_output_start[0],
                self.Input.meta.shape[1],
            ) + source_smooth_shape
            try:
                for j in range(dimCol):
                    for i in range(dimRow):
                        if self.matrix[i, j]:
                            # There is at least one filter op with this scale
                            break
                    else:
                        # There is no filter op at this scale
                        continue

                    if self.scales[j] > 1.0:
                        tempSigma = math.sqrt(self.scales[j] ** 2 - 1.0)
                    else:
                        tempSigma = self.scales[j]

                    presmoothed_source[j] = numpy.ndarray(full_source_smooth_shape, numpy.float32)

                    droi = (
                        (0, *tuple(smooth_filter_start._asint())),
                        (sourceV.shape[1], *tuple(smooth_filter_stop._asint())),
                    )
                    for i, vsa in enumerate(sourceV.timeIter()):
                        presmoothed_source[j][i, ...] = self._computeGaussianSmoothing(
                            vsa, tempSigma, droi, in2d=self.ComputeIn2d.value[j]
                        )

            except RuntimeError as e:
                if "kernel longer than line" in str(e):
                    raise RuntimeError(
                        "Feature computation error:\nYour image is too small to apply a filter with "
                        f"sigma={self.scales[j]:.1f}. Please select features with smaller sigmas."
                    )
                else:
                    raise e

            del sourceV
            try:
                source.resize((1,), refcheck=False)
            except ValueError:
                # Sometimes this fails, but that's okay.
                logger.debug("Failed to free array memory.")
            del source

            cnt = 0
            written = 0
            closures = []
            # connect individual operators
            for i in range(dimRow):
                for j in range(dimCol):
                    if self.matrix[i, j]:
                        oslot = self.featureOps[i][j].Output
                        req = None
                        slices = oslot.meta.shape[1]
                        if (
                            cnt + slices >= slot_roi.start[1]
                            and slot_roi.start[1] - cnt < slices
                            and slot_roi.start[1] + written < slot_roi.stop[1]
                        ):
                            begin = 0
                            if cnt < slot_roi.start[1]:
                                begin = slot_roi.start[1] - cnt
                            end = slices
                            if cnt + end > slot_roi.stop[1]:
                                end = slot_roi.stop[1] - cnt

                            # feature slice in output frame
                            feature_slice = (slice(None), slice(written, written + end - begin)) + (slice(None),) * 3

                            subtarget = target[feature_slice]
                            # readjust the roi for the new source array
                            full_filter_target_slice = [full_output_slice[0], slice(begin, end), *filter_target_slice]
                            filter_target_roi = SubRegion(oslot, pslice=full_filter_target_slice)

                            closure = partial(
                                oslot.operator.execute,
                                oslot,
                                (),
                                filter_target_roi,
                                subtarget,
                                sourceArray=presmoothed_source[j],
                            )
                            closures.append(closure)

                            written += end - begin
                        cnt += slices
            pool = RequestPool()
            for c in closures:
                pool.request(c)
            pool.wait()
            pool.clean()

            for i in range(len(presmoothed_source)):
                if presmoothed_source[i] is not None:
                    try:
                        presmoothed_source[i].resize((1,))
                    except Exception:
                        presmoothed_source[i] = None
Exemplo n.º 12
0
    def execute(self, slot, subindex, slot_roi, target):
        assert slot == self.Features or slot == self.Output
        if slot == self.Features:
            feature_slice = roiToSlice(slot_roi.start, slot_roi.stop)
            index = subindex[0]
            feature_slice = list(feature_slice)

            # Translate channel slice of this feature to the channel slice of the output slot.
            output_channel_offset = self.featureOutputChannels[index][0]
            feature_slice[1] = slice(
                output_channel_offset + feature_slice[1].start,
                output_channel_offset + feature_slice[1].stop)
            slot_roi = SubRegion(self.Output, pslice=feature_slice)

            # Get output slot region for this channel
            return self.execute(self.Output, (), slot_roi, target)
        elif slot == self.Output:
            # Correlation of variable 'families' representing reference frames:
            #  ______________________________
            # | input/output frame           |  input/output shape given by slots
            # |  _________________________   |
            # | | smooth frame            |  |  pre-smoothing op needs halo around filter roi
            # | |  ____________________   |  |
            # | | |filter frame        |  |  |  filter needs halo around target roi
            # | | |  _______________   |  |  |
            # | | | | target frame  |  |  |  |  target is given by output_roi

            # note: The 'full_' variable prefix refers to the full 5D shape (tczyx), without 'full_' variables mostly
            #       refer to the 3D space subregion (zyx)

            full_output_slice = slot_roi.toSlice()

            logger.debug(
                f"OpPixelFeaturesPresmoothed: request {slot_roi.pprint()}")

            assert (slot_roi.stop <= self.Output.meta.shape).all()

            full_output_shape = self.Output.meta.shape
            full_output_start, full_output_stop = sliceToRoi(
                full_output_slice, full_output_shape)
            assert len(full_output_shape) == 5
            if all(self.ComputeIn2d.value
                   ):  # todo: check for this particular slice
                axes2enlarge = (0, 1, 1)
            else:
                axes2enlarge = (1, 1, 1)

            output_shape = full_output_shape[2:]
            output_start = full_output_start[2:]
            output_stop = full_output_stop[2:]

            axistags = self.Output.meta.axistags
            target = target.view(vigra.VigraArray)
            target.axistags = copy.copy(axistags)

            # filter roi in input frame
            # sigma = 0.7, because the features receive a pre-smoothed array and don't need much of a neighborhood
            input_filter_start, input_filter_stop = roi.enlargeRoiForHalo(
                output_start,
                output_stop,
                output_shape,
                0.7,
                self.WINDOW_SIZE,
                enlarge_axes=axes2enlarge)

            # smooth roi in input frame
            input_smooth_start, input_smooth_stop = roi.enlargeRoiForHalo(
                input_filter_start,
                input_filter_stop,
                output_shape,
                self.max_sigma,
                self.WINDOW_SIZE,
                enlarge_axes=axes2enlarge,
            )

            # target roi in filter frame
            filter_target_start = roi.TinyVector(output_start -
                                                 input_filter_start)
            filter_target_stop = roi.TinyVector(output_stop -
                                                input_filter_start)

            # filter roi in smooth frame
            smooth_filter_start = roi.TinyVector(input_filter_start -
                                                 input_smooth_start)
            smooth_filter_stop = roi.TinyVector(input_filter_stop -
                                                input_smooth_start)

            filter_target_slice = roi.roiToSlice(filter_target_start,
                                                 filter_target_stop)
            input_smooth_slice = roi.roiToSlice(input_smooth_start,
                                                input_smooth_stop)

            # pre-smooth for all requested time slices and all channels
            full_input_smooth_slice = (full_output_slice[0], slice(None),
                                       *input_smooth_slice)
            req = self.Input[full_input_smooth_slice]
            source = req.wait()
            req.clean()
            req.destination = None
            if source.dtype != numpy.float32:
                sourceF = source.astype(numpy.float32)
                try:
                    source.resize((1, ), refcheck=False)
                except Exception:
                    pass
                del source
                source = sourceF

            sourceV = source.view(vigra.VigraArray)
            sourceV.axistags = copy.copy(self.Input.meta.axistags)

            dimCol = len(self.scales)
            dimRow = self.matrix.shape[0]

            presmoothed_source = [None] * dimCol

            source_smooth_shape = tuple(smooth_filter_stop -
                                        smooth_filter_start)
            full_source_smooth_shape = (
                full_output_stop[0] - full_output_start[0],
                self.Input.meta.shape[1],
            ) + source_smooth_shape
            try:
                for j in range(dimCol):
                    for i in range(dimRow):
                        if self.matrix[i, j]:
                            # There is at least one filter op with this scale
                            break
                    else:
                        # There is no filter op at this scale
                        continue

                    if self.scales[j] > 1.0:
                        tempSigma = math.sqrt(self.scales[j]**2 - 1.0)
                    else:
                        tempSigma = self.scales[j]

                    presmoothed_source[j] = numpy.ndarray(
                        full_source_smooth_shape, numpy.float32)

                    droi = (
                        (0, *tuple(smooth_filter_start._asint())),
                        (sourceV.shape[1],
                         *tuple(smooth_filter_stop._asint())),
                    )
                    for i, vsa in enumerate(sourceV.timeIter()):
                        presmoothed_source[j][
                            i, ...] = self._computeGaussianSmoothing(
                                vsa,
                                tempSigma,
                                droi,
                                in2d=self.ComputeIn2d.value[j])

            except RuntimeError as e:
                if "kernel longer than line" in str(e):
                    raise RuntimeError(
                        "Feature computation error:\nYour image is too small to apply a filter with "
                        f"sigma={self.scales[j]:.1f}. Please select features with smaller sigmas."
                    )
                else:
                    raise e

            del sourceV
            try:
                source.resize((1, ), refcheck=False)
            except ValueError:
                # Sometimes this fails, but that's okay.
                logger.debug("Failed to free array memory.")
            del source

            cnt = 0
            written = 0
            closures = []
            # connect individual operators
            for i in range(dimRow):
                for j in range(dimCol):
                    if self.matrix[i, j]:
                        oslot = self.featureOps[i][j].Output
                        req = None
                        slices = oslot.meta.shape[1]
                        if (cnt + slices >= slot_roi.start[1]
                                and slot_roi.start[1] - cnt < slices
                                and slot_roi.start[1] + written <
                                slot_roi.stop[1]):
                            begin = 0
                            if cnt < slot_roi.start[1]:
                                begin = slot_roi.start[1] - cnt
                            end = slices
                            if cnt + end > slot_roi.stop[1]:
                                end = slot_roi.stop[1] - cnt

                            # feature slice in output frame
                            feature_slice = (slice(None),
                                             slice(
                                                 written, written + end -
                                                 begin)) + (slice(None), ) * 3

                            subtarget = target[feature_slice]
                            # readjust the roi for the new source array
                            full_filter_target_slice = [
                                full_output_slice[0],
                                slice(begin, end), *filter_target_slice
                            ]
                            filter_target_roi = SubRegion(
                                oslot, pslice=full_filter_target_slice)

                            closure = partial(
                                oslot.operator.execute,
                                oslot,
                                (),
                                filter_target_roi,
                                subtarget,
                                sourceArray=presmoothed_source[j],
                            )
                            closures.append(closure)

                            written += end - begin
                        cnt += slices
            pool = RequestPool()
            for c in closures:
                pool.request(c)
            pool.wait()
            pool.clean()

            for i in range(len(presmoothed_source)):
                if presmoothed_source[i] is not None:
                    try:
                        presmoothed_source[i].resize((1, ))
                    except Exception:
                        presmoothed_source[i] = None
Exemplo n.º 13
0
    def execute(self, slot, subindex, roi, result):
        classifier_factory = self.ClassifierFactory.value
        assert issubclass(type(classifier_factory), LazyflowPixelwiseClassifierFactoryABC), \
            "Factory is of type {}, which does not satisfy the LazyflowPixelwiseClassifierFactoryABC interface."\
            "".format( type(classifier_factory) )

        # Accumulate all non-zero blocks of each image into lists
        label_data_blocks = []
        image_data_blocks = []
        for image_slot, label_slot, nonzero_block_slot in zip(
                self.Images, self.Labels, self.nonzeroLabelBlocks):
            block_slicings = nonzero_block_slot.value
            for block_slicing in block_slicings:
                # Get labels
                block_label_roi = sliceToRoi(block_slicing,
                                             label_slot.meta.shape)
                block_label_data = label_slot(*block_label_roi).wait()

                # Shrink roi to bounding box of actual label pixels
                bb_roi_within_block = nonzero_bounding_box(block_label_data)
                block_label_bb_roi = bb_roi_within_block + block_label_roi[0]

                # Double-check that there is at least 1 non-zero label in the block.
                if (block_label_bb_roi[1] > block_label_bb_roi[0]).all():
                    # Ask for the halo needed by the classifier
                    axiskeys = image_slot.meta.getAxisKeys()
                    halo_shape = classifier_factory.get_halo_shape(axiskeys)
                    assert len(halo_shape) == len(block_label_roi[0])
                    assert halo_shape[
                        -1] == 0, "Didn't expect a non-zero halo for channel dimension."

                    # Expand block by halo, but keep clipped to image bounds
                    padded_label_roi, bb_roi_within_padded = enlargeRoiForHalo(
                        *block_label_bb_roi,
                        shape=label_slot.meta.shape,
                        sigma=halo_shape,
                        window=1,
                        return_result_roi=True)

                    # Copy labels to new array, which has size == bounding-box + halo
                    padded_label_data = numpy.zeros(
                        padded_label_roi[1] - padded_label_roi[0],
                        label_slot.meta.dtype)
                    padded_label_data[roiToSlice(
                        *bb_roi_within_padded)] = block_label_data[roiToSlice(
                            *bb_roi_within_block)]

                    padded_image_roi = numpy.array(padded_label_roi)
                    assert (padded_image_roi[:, -1] == [0, 1]).all()
                    num_channels = image_slot.meta.shape[-1]
                    padded_image_roi[:, -1] = [0, num_channels]

                    # Ensure the results are plain ndarray, not VigraArray,
                    #  which some classifiers might have trouble with.
                    padded_image_data = numpy.asarray(
                        image_slot(*padded_image_roi).wait())

                    label_data_blocks.append(padded_label_data)
                    image_data_blocks.append(padded_image_data)

        if len(image_data_blocks) == 0:
            result[0] = None
        else:
            channel_names = self.Images[0].meta.channel_names
            axistags = self.Images[0].meta.axistags
            logger.debug("Training new pixelwise classifier: {}".format(
                classifier_factory.description))
            classifier = classifier_factory.create_and_train_pixelwise(
                image_data_blocks, label_data_blocks, axistags, channel_names)
            result[0] = classifier
            if classifier is not None:
                assert issubclass(type(classifier), LazyflowPixelwiseClassifierABC), \
                    "Classifier is of type {}, which does not satisfy the LazyflowPixelwiseClassifierABC interface."\
                    "".format( type(classifier) )
Exemplo n.º 14
0
    def execute(self, slot, subindex, rroi, result, sourceArray=None):
        assert len(subindex) == self.Output.level == 0
        key = roiToSlice(rroi.start, rroi.stop)

        kwparams = {}
        for islot in list(self.inputs.values()):
            if islot.name != "Input":
                kwparams[islot.name] = islot.value

        if "sigma" in self.inputs:
            sigma = self.inputs["sigma"].value
        elif "scale" in self.inputs:
            sigma = self.inputs["scale"].value
        elif "sigma0" in self.inputs:
            sigma = self.inputs["sigma0"].value
        elif "innerScale" in self.inputs:
            sigma = self.inputs["innerScale"].value

        windowSize = 3.5
        if self.supportsWindow:
            kwparams['window_size']=self.window_size_feature
            windowSize = self.window_size_smoother

        largestSigma = max(0.7,sigma) #we use 0.7 as an approximation of not doing any smoothing
        #smoothing was already applied previously

        shape = self.outputs["Output"].meta.shape

        axistags = self.inputs["Input"].meta.axistags
        hasChannelAxis = self.inputs["Input"].meta.axistags.axisTypeCount(vigra.AxisType.Channels)
        channelAxis=self.inputs["Input"].meta.axistags.index('c')
        hasTimeAxis = self.inputs["Input"].meta.axistags.axisTypeCount(vigra.AxisType.Time)
        timeAxis=self.inputs["Input"].meta.axistags.index('t')
        zAxis = self.inputs["Input"].meta.axistags.index('z')

        subkey = popFlagsFromTheKey(key,axistags,'c')
        subshape=popFlagsFromTheKey(shape,axistags,'c')
        at2 = copy.copy(axistags)
        at2.dropChannelAxis()
        subshape=popFlagsFromTheKey(subshape,at2,'t')
        subkey = popFlagsFromTheKey(subkey,at2,'t')

        oldstart, oldstop = roi.sliceToRoi(key, shape)
        
        start, stop = roi.sliceToRoi(subkey,subkey)
        
        if sourceArray is not None and zAxis<len(axistags):
            if timeAxis>zAxis:
                subshape[at2.index('z')]=sourceArray.shape[zAxis]
            else:
                subshape[at2.index('z')-1]=sourceArray.shape[zAxis]
        
        newStart, newStop = roi.enlargeRoiForHalo(start, stop, subshape, largestSigma, window = windowSize)
        readKey = roi.roiToSlice(newStart, newStop)

        writeNewStart = start - newStart
        writeNewStop = writeNewStart +  stop - start

        if (writeNewStart == 0).all() and (newStop == writeNewStop).all():
            fullResult = True
        else:
            fullResult = False

        writeKey = roi.roiToSlice(writeNewStart, writeNewStop)
        writeKey = list(writeKey)
        if timeAxis < channelAxis:
            writeKey.insert(channelAxis-1, slice(None,None,None))
        else:
            writeKey.insert(channelAxis, slice(None,None,None))
        writeKey = tuple(writeKey)

        #print writeKey

        channelsPerChannel = self.resultingChannels()

        if self.supportsRoi is False and largestSigma > 5:
            logger.warning(f"WARNING: operator {self.name} does not support roi!!")

        i2 = 0
        for i in range(int(numpy.floor(1.0 * oldstart[channelAxis]/channelsPerChannel)),int(numpy.ceil(1.0 * oldstop[channelAxis]/channelsPerChannel))):
            newReadKey = list(readKey) #add channel and time axis if needed
            if hasTimeAxis:
                if channelAxis > timeAxis:
                    newReadKey.insert(timeAxis, key[timeAxis])
                else:
                    newReadKey.insert(timeAxis-1, key[timeAxis])
            if hasChannelAxis:
                newReadKey.insert(channelAxis, slice(i, i+1, None))
                
            if sourceArray is None:
                req = self.inputs["Input"][newReadKey]
                t = req.wait()
            else:
                if hasChannelAxis:
                    t = sourceArray[getAllExceptAxis(len(newReadKey),channelAxis,slice(i,i+1,None) )]
                else:
                    fullkey = [slice(None, None, None)]*len(newReadKey)
                    t = sourceArray[fullkey]

            t = numpy.require(t, dtype=self.inputDtype)
            t = t.view(vigra.VigraArray)
            t.axistags = copy.copy(axistags)
            t = t.insertChannelAxis()

            sourceBegin = 0

            if oldstart[channelAxis] > i * channelsPerChannel:
                sourceBegin = oldstart[channelAxis] - i * channelsPerChannel
            sourceEnd = channelsPerChannel
            if oldstop[channelAxis] < (i+1) * channelsPerChannel:
                sourceEnd = channelsPerChannel - ((i+1) * channelsPerChannel - oldstop[channelAxis])
            destBegin = i2
            destEnd = i2 + sourceEnd - sourceBegin

            if channelsPerChannel>1:
                tkey=getAllExceptAxis(len(shape),channelAxis,slice(destBegin,destEnd,None))
                resultArea = result[tkey]
            else:
                tkey=getAllExceptAxis(len(shape),channelAxis,slice(i2,i2+1,None))
                resultArea = result[tkey]

            i2 += destEnd-destBegin

            supportsOut = self.supportsOut
            if (destEnd-destBegin != channelsPerChannel):
                supportsOut = False

            supportsOut = False #disable for now due to vigra crashes! #FIXME
            for step,image in enumerate(t.timeIter()):
                nChannelAxis = channelAxis - 1

                if timeAxis > channelAxis or not hasTimeAxis:
                    nChannelAxis = channelAxis
                twriteKey=getAllExceptAxis(image.ndim, nChannelAxis, slice(sourceBegin,sourceEnd,None))

                if hasTimeAxis > 0:
                    tresKey  = getAllExceptAxis(resultArea.ndim, timeAxis, step)
                else:
                    tresKey  = slice(None, None,None)

                #print tresKey, twriteKey, resultArea.shape, temp.shape
                vres = resultArea[tresKey]
                               
                if supportsOut:
                    if self.supportsRoi:
                        vroi = (tuple(writeNewStart._asint()), tuple(writeNewStop._asint()))
                        try:
                            vres = vres.view(vigra.VigraArray)
                            vres.axistags = copy.copy(image.axistags)
                            logger.debug( "FAST LANE {} {} {} {}".format( self.name, vres.shape, image[twriteKey].shape, vroi ) )
                            temp = self.vigraFilter(image[twriteKey], roi = vroi,out=vres, **kwparams)
                        except:
                            logger.error( "{} {} {} {}".format(self.name, image.shape, vroi, kwparams) )
                            raise
                    else:
                        try:
                            temp = self.vigraFilter(image, **kwparams)
                        except:
                            logger.error( "{} {} {} {}".format(self.name, image.shape, vroi, kwparams) )
                            raise
                        temp=temp[writeKey]
                else:
                    if self.supportsRoi:
                        vroi = (tuple(writeNewStart._asint()), tuple(writeNewStop._asint()))
                        try:
                            temp = self.vigraFilter(image, roi = vroi, **kwparams)
                        except Exception as e:
                            logger.error( "EXCEPT 2.1 {} {} {} {}".format( self.name, image.shape, vroi, kwparams ) )
                            traceback.print_exc(e)
                            import sys
                            sys.exit(1)
                    else:
                        try:
                            temp = self.vigraFilter(image, **kwparams)
                        except Exception as e:
                            logger.error( "EXCEPT 2.2 {} {} {}".format( self.name, image.shape, kwparams ) )
                            traceback.print_exc(e)
                            import sys
                            sys.exit(1)
                        temp=temp[writeKey]


                    try:
                        vres[:] = temp[twriteKey]
                    except:
                        logger.error( "EXCEPT3 {} {} {}".format( vres.shape, temp.shape, twriteKey ) )
                        logger.error( "EXCEPT3 {} {} {}".format( resultArea.shape,  tresKey, twriteKey ) )
                        logger.error( "EXCEPT3 {} {} {}".format( step, t.shape, timeAxis ) )
                        raise
Exemplo n.º 15
0
    def execute(self, slot, subindex, roi, result):
        classifier_factory = self.ClassifierFactory.value
        assert issubclass(type(classifier_factory), LazyflowPixelwiseClassifierFactoryABC), \
            "Factory is of type {}, which does not satisfy the LazyflowPixelwiseClassifierFactoryABC interface."\
            "".format( type(classifier_factory) )
        
        # Accumulate all non-zero blocks of each image into lists
        label_data_blocks = []
        image_data_blocks = []
        for image_slot, label_slot, nonzero_block_slot in zip(self.Images, self.Labels, self.nonzeroLabelBlocks):
            block_slicings = nonzero_block_slot.value
            for block_slicing in block_slicings:
                # Get labels
                block_label_roi = sliceToRoi( block_slicing, label_slot.meta.shape )
                block_label_data = label_slot(*block_label_roi).wait()
                
                # Shrink roi to bounding box of actual label pixels
                bb_roi_within_block = nonzero_bounding_box(block_label_data)
                block_label_bb_roi = bb_roi_within_block + block_label_roi[0]

                # Double-check that there is at least 1 non-zero label in the block.
                if (block_label_bb_roi[1] > block_label_bb_roi[0]).all():
                    # Ask for the halo needed by the classifier
                    axiskeys = image_slot.meta.getAxisKeys()
                    halo_shape = classifier_factory.get_halo_shape(axiskeys)
                    assert len(halo_shape) == len( block_label_roi[0] )
                    assert halo_shape[-1] == 0, "Didn't expect a non-zero halo for channel dimension."
    
                    # Expand block by halo, but keep clipped to image bounds
                    padded_label_roi, bb_roi_within_padded = enlargeRoiForHalo( *block_label_bb_roi, 
                                                                                shape=label_slot.meta.shape,
                                                                                sigma=halo_shape,
                                                                                window=1,
                                                                                return_result_roi=True )
                    
                    # Copy labels to new array, which has size == bounding-box + halo
                    padded_label_data = numpy.zeros( padded_label_roi[1] - padded_label_roi[0], label_slot.meta.dtype )                
                    padded_label_data[roiToSlice(*bb_roi_within_padded)] = block_label_data[roiToSlice(*bb_roi_within_block)]
    
                    padded_image_roi = numpy.array( padded_label_roi )
                    assert (padded_image_roi[:, -1] == [0,1]).all()
                    num_channels = image_slot.meta.shape[-1]
                    padded_image_roi[:, -1] = [0, num_channels]
    
                    # Ensure the results are plain ndarray, not VigraArray, 
                    #  which some classifiers might have trouble with.
                    padded_image_data = numpy.asarray( image_slot(*padded_image_roi).wait() )
                    
                    label_data_blocks.append( padded_label_data )
                    image_data_blocks.append( padded_image_data )

        if len(image_data_blocks) == 0:
            result[0] = None
        else:
            channel_names = self.Images[0].meta.channel_names
            axistags = self.Images[0].meta.axistags
            logger.debug("Training new pixelwise classifier: {}".format( classifier_factory.description ))
            classifier = classifier_factory.create_and_train_pixelwise( image_data_blocks, label_data_blocks, axistags, channel_names )
            result[0] = classifier
            if classifier is not None:
                assert issubclass(type(classifier), LazyflowPixelwiseClassifierABC), \
                    "Classifier is of type {}, which does not satisfy the LazyflowPixelwiseClassifierABC interface."\
                    "".format( type(classifier) )
Exemplo n.º 16
0
    def execute(self, slot, subindex, output_roi, target, sourceArray=None):
        assert slot == self.Output
        # explanatory notes for variable 'families':
        #   output_* : associated with Output slot
        #   target_* : associated with target area inside of output, described by output_roi
        #   input_*  : associated with Input slot (same shape as Output slot, except for channels)
        #   source_* : associated with source area inside of input, described by output_roi + halo
        #   result_* : associated with the filtered source
        #
        # relations between variable 'families': (for further clarification)
        #   TARGET is subregion of OUTPUT
        #   SOURCE is subregion of INPUT (or from sourceArray)
        #   TARGET area plus halo equals SOURCE area
        #   applying filter to SOURCE yields RESULT
        #   RESULT without halo is TARGET

        # note: The 'full_' variable prefix refers to the full 5D shape (tczyx), without 'full_' variables mostly
        #       refer to the 3D space subregion (zyx)

        assert len(subindex) == self.Output.level == 0
        if self.supports_roi is False and self.max_sigma > 5:
            logger.warning(f"WARNING: operator {self.name} does not support roi!!")

        key = roiToSlice(output_roi.start, output_roi.stop)

        full_output_shape = self.Output.meta.shape
        full_output_start, full_output_stop = roi.sliceToRoi(key, full_output_shape)
        if self.invalid_z or self.ComputeIn2d.value:
            axes2enlarge = (0, 1, 1)
            process_in_2d = True
            axistags = vigra.defaultAxistags("cyx")
        else:
            axes2enlarge = (1, 1, 1)
            process_in_2d = False
            axistags = vigra.defaultAxistags("czyx")

        output_shape = full_output_shape[2:]  # without tc
        assert output_shape == self.Input.meta.shape[2:], (output_shape, self.Input.meta.shape[2:])
        output_start = full_output_start[2:]
        output_stop = full_output_stop[2:]

        input_start, input_stop = roi.enlargeRoiForHalo(
            output_start,
            output_stop,
            output_shape,
            self.max_sigma,
            window=self.window_size_smoother,
            enlarge_axes=axes2enlarge,
        )
        input_slice = roi.roiToSlice(input_start, input_stop)

        result_start = output_start - input_start
        result_stop = result_start + output_stop - output_start
        result_slice = roi.roiToSlice(result_start, result_stop)

        filter_kwargs = self.filter_kwargs

        def step(tstep, target_z_slice, full_input_slice, full_result_slice):
            if sourceArray is None:
                # no tmatter, if slices or indices are in 'full_input_slice', they will be converted to slices => 5d
                source = self.Input[full_input_slice].wait()[0]  # => remove singleton t dimension
                if process_in_2d:
                    source = source[:, 0]  # if processing in 2d, remove singleton z dimension

                assert source.shape[0] == 1  # single channel axis for input
            else:
                assert sourceArray.shape[1] == self.Input.meta.shape[1]
                source = sourceArray[tstep, full_input_slice[1], ...]
                if process_in_2d:
                    # eliminate singleton z dimension
                    assert isinstance(target_z_slice, int)
                    source = source[:, target_z_slice]  # in 2d z is shared between source and target (like time)

            source = numpy.require(source, dtype=self.input_dtype)
            source = source.view(vigra.VigraArray)
            source.axistags = axistags

            supports_roi = self.supports_roi
            # in vigra the roi parameter does not support a channel roi
            if not WITH_FAST_FILTERS:
                if target_c_stop - target_c_start != self.resultingChannels():
                    supports_roi = False

            if supports_roi:
                if not WITH_FAST_FILTERS:
                    # filter_roi without channel axis (not supported by vigra)
                    filter_roi = roi.sliceToRoi(full_result_slice[1:], source.shape[1:])
                if self.supports_out:
                    try:
                        subtarget = target[tstep, target_c_start:target_c_stop, target_z_slice].view(vigra.VigraArray)
                        if process_in_2d:
                            subtarget = subtarget[:, 0]

                        subtarget.axistags = copy.copy(axistags)
                        logger.debug(
                            f"r o: {self.name} {source.shape} {full_result_slice} {subtarget.shape} {filter_kwargs}"
                        )

                        self.filter_fn(source, roi=filter_roi, out=subtarget, **filter_kwargs)
                        return
                    except Exception:
                        logger.error(
                            f"r o: {self.name} {source.shape} {filter_roi} {subtarget.shape} {filter_kwargs} "
                            f"{process_in_2d}"
                        )
                        raise
                else:
                    try:
                        logger.debug(f"r  : {self.name} {source.shape} {full_result_slice} {filter_kwargs}")
                        result = self.filter_fn(source, roi=filter_roi, **filter_kwargs)
                    except Exception:
                        logger.error(f"r  : {self.name} {source.shape} {target.shape} {filter_kwargs}")
                        raise
            else:
                # note: support of 'out' gives no advantage, if no roi can be specified. The filter result (including a
                #       halo) would not fit into the target (without a halo).
                # todo: implement 'no halo exception' of above note
                try:
                    logger.debug(f"   : {self.name} {source.shape} {filter_kwargs} {process_in_2d}")
                    result = self.filter_fn(source, **filter_kwargs)
                except Exception:
                    logger.error(f"   : {self.name} {source.shape} {filter_kwargs} {process_in_2d}")
                    raise
                result = result[full_result_slice]

            try:
                target[tstep, target_c_start:target_c_stop, target_z_slice] = result
            except Exception:
                logger.error(f"t  : {target.shape} {target[tstep, target_c_start:target_c_stop].shape} {result.shape}")
                logger.error(f"tstep {tstep}  c {target_c_start},{target_c_stop}  z {target_z_slice} {result.shape}")
                raise

        resC = self.resultingChannels()

        for tstep, t in enumerate(range(full_output_start[0], full_output_stop[0])):
            target_c_stop = 0
            for input_c in range(
                int(numpy.floor(full_output_start[1] / resC)), int(numpy.ceil(full_output_stop[1] / resC))
            ):
                output_c_start = resC * input_c
                output_c_stop = resC * (input_c + 1)
                result_c_start = 0
                result_c_stop = resC
                if output_c_start < full_output_start[1]:
                    result_c_start = full_output_start[1] - output_c_start
                    output_c_start = full_output_start[1]
                if output_c_stop > full_output_stop[1]:
                    result_c_stop -= output_c_stop - full_output_stop[1]
                    output_c_stop = full_output_stop[1]

                target_c_start = target_c_stop
                target_c_stop += result_c_stop - result_c_start
                result_c_slice = slice(result_c_start, result_c_stop)
                input_c_slice = slice(input_c, input_c + 1)

                if process_in_2d:
                    for target_z, input_z in enumerate(range(input_start[0], input_stop[0])):
                        step(
                            tstep,
                            target_z_slice=target_z,
                            full_input_slice=(t, input_c_slice, input_z, *input_slice[1:]),
                            full_result_slice=(result_c_slice, *result_slice[1:]),
                        )
                else:
                    step(
                        tstep,
                        target_z_slice=slice(None),
                        full_input_slice=(t, input_c_slice, *input_slice),
                        full_result_slice=(result_c_slice, *result_slice),
                    )
Exemplo n.º 17
0
    def execute(self, slot, subindex, rroi, result):
        assert slot == self.Features or slot == self.Output
        if slot == self.Features:
            key = roiToSlice(rroi.start, rroi.stop)
            index = subindex[0]
            key = list(key)
            channelIndex = self.Input.meta.axistags.index('c')
            
            # Translate channel slice to the correct location for the output slot.
            key[channelIndex] = slice(self.featureOutputChannels[index][0] + key[channelIndex].start,
                                      self.featureOutputChannels[index][0] + key[channelIndex].stop)
            rroi = SubRegion(self.Output, pslice=key)

            # Get output slot region for this channel
            return self.execute(self.Output, (), rroi, result)
        elif slot == self.outputs["Output"]:
            key = rroi.toSlice()
            
            logger.debug("OpPixelFeaturesPresmoothed: request %s" % (rroi.pprint(),))
            
            cnt = 0
            written = 0
            assert (rroi.stop<=self.outputs["Output"].meta.shape).all()
            flag = 'c'
            channelAxis=self.inputs["Input"].meta.axistags.index('c')
            axisindex = channelAxis
            oldkey = list(key)
            oldkey.pop(axisindex)


            inShape  = self.inputs["Input"].meta.shape
            hasChannelAxis = (self.Input.meta.axistags.axisTypeCount(vigra.AxisType.Channels) > 0)
            #if (self.Input.meta.axistags.axisTypeCount(vigra.AxisType.Channels) == 0):
            #    noChannels = True
            inAxistags = self.inputs["Input"].meta.axistags
                
            shape = self.outputs["Output"].meta.shape
            axistags = self.outputs["Output"].meta.axistags

            result = result.view(vigra.VigraArray)
            result.axistags = copy.copy(axistags)


            hasTimeAxis = self.inputs["Input"].meta.axistags.axisTypeCount(vigra.AxisType.Time)
            timeAxis=self.inputs["Input"].meta.axistags.index('t')

            subkey = popFlagsFromTheKey(key,axistags,'c')
            subshape=popFlagsFromTheKey(shape,axistags,'c')
            at2 = copy.copy(axistags)
            at2.dropChannelAxis()
            subshape=popFlagsFromTheKey(subshape,at2,'t')
            subkey = popFlagsFromTheKey(subkey,at2,'t')

            oldstart, oldstop = roi.sliceToRoi(key, shape)

            start, stop = roi.sliceToRoi(subkey,subkey)
            maxSigma = max(0.7,self.maxSigma)  #we use 0.7 as an approximation of not doing any smoothing
            #smoothing was already applied previously
            
            # The region of the smoothed image we need to give to the feature filter (in terms of INPUT coordinates)
            # 0.7, because the features receive a pre-smoothed array and don't need much of a neighborhood 
            vigOpSourceStart, vigOpSourceStop = roi.enlargeRoiForHalo(start, stop, subshape, 0.7, self.WINDOW_SIZE)
            
            
            # The region of the input that we need to give to the smoothing operator (in terms of INPUT coordinates)
            newStart, newStop = roi.enlargeRoiForHalo(vigOpSourceStart, vigOpSourceStop, subshape, maxSigma, self.WINDOW_SIZE)
            
            newStartSmoother = roi.TinyVector(start - vigOpSourceStart)
            newStopSmoother = roi.TinyVector(stop - vigOpSourceStart)
            roiSmoother = roi.roiToSlice(newStartSmoother, newStopSmoother)

            # Translate coordinates (now in terms of smoothed image coordinates)
            vigOpSourceStart = roi.TinyVector(vigOpSourceStart - newStart)
            vigOpSourceStop = roi.TinyVector(vigOpSourceStop - newStart)

            readKey = roi.roiToSlice(newStart, newStop)

            writeNewStart = start - newStart
            writeNewStop = writeNewStart +  stop - start

            treadKey=list(readKey)

            if hasTimeAxis:
                if timeAxis < channelAxis:
                    treadKey.insert(timeAxis, key[timeAxis])
                else:
                    treadKey.insert(timeAxis-1, key[timeAxis])
            if  self.inputs["Input"].meta.axistags.axisTypeCount(vigra.AxisType.Channels) == 0:
                treadKey =  popFlagsFromTheKey(treadKey,axistags,'c')
            else:
                treadKey.insert(channelAxis, slice(None,None,None))

            treadKey=tuple(treadKey)

            req = self.inputs["Input"][treadKey]
            
            sourceArray = req.wait()
            req.clean()
            #req.result = None
            req.destination = None
            if sourceArray.dtype != numpy.float32:
                sourceArrayF = sourceArray.astype(numpy.float32)
                try:
                    sourceArray.resize((1,), refcheck = False)
                except:
                    pass
                del sourceArray
                sourceArray = sourceArrayF
                
            #if (self.Input.meta.axistags.axisTypeCount(vigra.AxisType.Channels) == 0):
                #add a channel dimension to make the code afterwards more uniform
            #    sourceArray = sourceArray.view(numpy.ndarray)
            #    sourceArray = sourceArray.reshape(sourceArray.shape+(1,))
            sourceArrayV = sourceArray.view(vigra.VigraArray)
            sourceArrayV.axistags =  copy.copy(inAxistags)
            
            dimCol = len(self.scales)
            dimRow = self.matrix.shape[0]

            sourceArraysForSigmas = [None]*dimCol

            #connect individual operators
            try:
                for j in range(dimCol):
                    hasScale = False
                    for i in range(dimRow):
                        if self.matrix[i,j]:
                            hasScale = True
                    if not hasScale:
                        continue
                    destSigma = 1.0
                    if self.scales[j] > destSigma:
                        tempSigma = math.sqrt(self.scales[j]**2 - destSigma**2)
                    else:
                        destSigma = 0.0
                        tempSigma = self.scales[j]
                    vigOpSourceShape = list(vigOpSourceStop - vigOpSourceStart)
                                        
                    if hasTimeAxis:
                        if timeAxis < channelAxis:
                            vigOpSourceShape.insert(timeAxis, ( oldstop - oldstart)[timeAxis])
                        else:
                            vigOpSourceShape.insert(timeAxis-1, ( oldstop - oldstart)[timeAxis])
                        vigOpSourceShape.insert(channelAxis, inShape[channelAxis])
    
                        sourceArraysForSigmas[j] = numpy.ndarray(tuple(vigOpSourceShape),numpy.float32)
                        
                        for i,vsa in enumerate(sourceArrayV.timeIter()):
                            droi = (tuple(vigOpSourceStart._asint()), tuple(vigOpSourceStop._asint()))
                            tmp_key = getAllExceptAxis(len(sourceArraysForSigmas[j].shape),timeAxis, i) 
                            sourceArraysForSigmas[j][tmp_key] = self._computeGaussianSmoothing(vsa, tempSigma, droi)

                    else:
                        droi = (tuple(vigOpSourceStart._asint()), tuple(vigOpSourceStop._asint()))                            
                        sourceArraysForSigmas[j] = self._computeGaussianSmoothing(sourceArrayV, tempSigma, droi)
            
            except RuntimeError as e:
                if e.message.find('kernel longer than line') > -1:
                    message = "Feature computation error:\nYour image is too small to apply a filter with sigma=%.1f. Please select features with smaller sigmas." % self.scales[j]
                    raise RuntimeError(message)
                else:
                    raise e

            del sourceArrayV
            try:
                sourceArray.resize((1,), refcheck = False)
            except ValueError:
                # Sometimes this fails, but that's okay.
                logger.debug("Failed to free array memory.")                
            del sourceArray

            closures = []

            #connect individual operators
            for i in range(dimRow):
                for j in range(dimCol):
                    val=self.matrix[i,j]
                    if val:
                        vop= self.featureOps[i][j]
                        oslot = vop.outputs["Output"]
                        req = None
                        #inTagKeys = [ax.key for ax in oslot.meta.axistags]
                        #print inTagKeys, flag
                        if hasChannelAxis:
                            slices = oslot.meta.shape[axisindex]
                            if cnt + slices >= rroi.start[axisindex] and rroi.start[axisindex]-cnt<slices and rroi.start[axisindex]+written<rroi.stop[axisindex]:
                                begin = 0
                                if cnt < rroi.start[axisindex]:
                                    begin = rroi.start[axisindex] - cnt
                                end = slices
                                if cnt + end > rroi.stop[axisindex]:
                                    end -= cnt + end - rroi.stop[axisindex]
                                key_ = copy.copy(oldkey)
                                key_.insert(axisindex, slice(begin, end, None))
                                reskey = [slice(None, None, None) for x in range(len(result.shape))]
                                reskey[axisindex] = slice(written, written+end-begin, None)
                                
                                destArea = result[tuple(reskey)]
                                #readjust the roi for the new source array
                                roiSmootherList = list(roiSmoother)
                                
                                roiSmootherList.insert(axisindex, slice(begin, end, None))
                                
                                if hasTimeAxis:
                                    # The time slice in the ROI doesn't matter:
                                    # The sourceArrayParameter below overrides the input data to be used.
                                    roiSmootherList.insert(timeAxis, 0)
                                roiSmootherRegion = SubRegion(oslot, pslice=roiSmootherList)
                                
                                closure = partial(oslot.operator.execute, oslot, (), roiSmootherRegion, destArea, sourceArray = sourceArraysForSigmas[j])
                                closures.append(closure)

                                written += end - begin
                            cnt += slices
                        else:
                            if cnt>=rroi.start[axisindex] and rroi.start[axisindex] + written < rroi.stop[axisindex]:
                                reskey = [slice(None, None, None) for x in range(len(result.shape))]
                                slices = oslot.meta.shape[axisindex]
                                reskey[axisindex]=slice(written, written+slices, None)
                                #print "key: ", key, "reskey: ", reskey, "oldkey: ", oldkey, "resshape:", result.shape
                                #print "roiSmoother:", roiSmoother
                                destArea = result[tuple(reskey)]
                                #print "destination area:", destArea.shape
                                logger.debug(oldkey, destArea.shape, sourceArraysForSigmas[j].shape)
                                oldroi = SubRegion(oslot, pslice=oldkey)
                                #print "passing roi:", oldroi
                                closure = partial(oslot.operator.execute, oslot, (), oldroi, destArea, sourceArray = sourceArraysForSigmas[j])
                                closures.append(closure)

                                written += 1
                            cnt += 1
            pool = RequestPool()
            for c in closures:
                r = pool.request(c)
            pool.wait()
            pool.clean()

            for i in range(len(sourceArraysForSigmas)):
                if sourceArraysForSigmas[i] is not None:
                    try:
                        sourceArraysForSigmas[i].resize((1,))
                    except:
                        sourceArraysForSigmas[i] = None