Example #1
0
def grow_regions(input, output, window=3, val=50):
    """ Threshold water classification and grow lakes by 1 pixel"""
    print(f"Growing regions (window = {window})")
    p50 = threshold(input, val=val)

    # Write
    out50 = np.empty_like(p50)
    modal(p50, selem=np.ones((window, window)), out=out50)
    p50 = None
    maximum_filter(out50, size=window, output=out50)
    du.write_array_like(input, output, out50, dtype=2)
Example #2
0
def modefilter(input, output, window=7):
    """ Threshold water classification at 50% water likelihood"""
    print(f"Running mode filter (window = {window})")
    # split into 50% and 100% water
    p50 = threshold(input, val=50)

    # Write
    out50 = np.empty_like(p50)
    modal(p50, selem=np.ones((window, window)), out=out50)
    p50 = None
    du.write_array_like(input, output, out50, dtype=2)
        def check_all():
            selem = morphology.disk(1)
            refs = np.load(
                os.path.join(skimage.data_dir, "rank_filter_tests.npz"))

            assert_equal(refs["autolevel"], rank.autolevel(self.image, selem))
            assert_equal(refs["autolevel_percentile"],
                         rank.autolevel_percentile(self.image, selem))
            assert_equal(refs["bottomhat"], rank.bottomhat(self.image, selem))
            assert_equal(refs["equalize"], rank.equalize(self.image, selem))
            assert_equal(refs["gradient"], rank.gradient(self.image, selem))
            assert_equal(refs["gradient_percentile"],
                         rank.gradient_percentile(self.image, selem))
            assert_equal(refs["maximum"], rank.maximum(self.image, selem))
            assert_equal(refs["mean"], rank.mean(self.image, selem))
            assert_equal(refs["geometric_mean"],
                         rank.geometric_mean(self.image, selem)),
            assert_equal(refs["mean_percentile"],
                         rank.mean_percentile(self.image, selem))
            assert_equal(refs["mean_bilateral"],
                         rank.mean_bilateral(self.image, selem))
            assert_equal(refs["subtract_mean"],
                         rank.subtract_mean(self.image, selem))
            assert_equal(refs["subtract_mean_percentile"],
                         rank.subtract_mean_percentile(self.image, selem))
            assert_equal(refs["median"], rank.median(self.image, selem))
            assert_equal(refs["minimum"], rank.minimum(self.image, selem))
            assert_equal(refs["modal"], rank.modal(self.image, selem))
            assert_equal(refs["enhance_contrast"],
                         rank.enhance_contrast(self.image, selem))
            assert_equal(refs["enhance_contrast_percentile"],
                         rank.enhance_contrast_percentile(self.image, selem))
            assert_equal(refs["pop"], rank.pop(self.image, selem))
            assert_equal(refs["pop_percentile"],
                         rank.pop_percentile(self.image, selem))
            assert_equal(refs["pop_bilateral"],
                         rank.pop_bilateral(self.image, selem))
            assert_equal(refs["sum"], rank.sum(self.image, selem))
            assert_equal(refs["sum_bilateral"],
                         rank.sum_bilateral(self.image, selem))
            assert_equal(refs["sum_percentile"],
                         rank.sum_percentile(self.image, selem))
            assert_equal(refs["threshold"], rank.threshold(self.image, selem))
            assert_equal(refs["threshold_percentile"],
                         rank.threshold_percentile(self.image, selem))
            assert_equal(refs["tophat"], rank.tophat(self.image, selem))
            assert_equal(refs["noise_filter"],
                         rank.noise_filter(self.image, selem))
            assert_equal(refs["entropy"], rank.entropy(self.image, selem))
            assert_equal(refs["otsu"], rank.otsu(self.image, selem))
            assert_equal(refs["percentile"],
                         rank.percentile(self.image, selem))
            assert_equal(refs["windowed_histogram"],
                         rank.windowed_histogram(self.image, selem))
def lone_object_filter(image, min_size=2, connectivity=1, kernel_size=3):
    """
    Replaces isolated, contiguous regions of values in a raster with values
    representing the surrounding pixels.

    More specifically, this reduces noise in a raster by setting
    contiguous regions of values of a specified minimum size to
    the modal value in a specified neighborhood.

    The default argument values filter out lone, singular pixels.
    This filter is not idempotent, so it may need to be applied repeatedly
    until the output stops changing or the results are acceptable.

    Args:
        image (numpy.ndarray):
            The image to filter.
        min_size (int):
            Defines the minimum number of contiguous pixels that will not
            be set to the modal value of their neighborhood. Setting this to 1
            is pointless, since this function will then do nothing to the raster.
        connectivity (int):
            The maximum distance between any two pixels such that they are
            considered one group. For example, a connectivity of 1 considers
            only adjacent values to be within one group, but a connectivity of 2
            also considers diagonally connected values to be within one group.
        kernel_size (int or float):
            The diameter of the circular kernel to use for the modal filter.
            If there are still large, contiguous regions of lone pixels,
            increase this value to remove them. Note that the larger this value
            is, the more detail may be lost in the image.

    Returns:
        The filtered image.

    Authors:
        Andrew Lubawy ([email protected])\n
        John Rattz    ([email protected])
    """
    assert kernel_size % 2 == 1, "The parameter `kernel_size` must be an odd number."
    modal_filtered = modal(image, create_circular_mask(kernel_size,
                                                       kernel_size))

    da = xr.DataArray(image)
    for i, val in enumerate(np.unique(image)):
        layer = remove_small_objects(image == val,
                                     min_size=min_size,
                                     connectivity=connectivity)
        filtered = da.where(layer) if i == 0 else filtered.combine_first(
            da.where(layer))
    filtered.values[np.isnan(filtered.values)] = modal_filtered[np.isnan(
        filtered.values)]
    return filtered.values
Example #5
0
 def majority_filter(self, classes_map, selems):
     """
     :param classes_map: 2 dim image
     :param selems: elements: [disk(1),square(2)...]
     :return:
     """
     from skimage.filters.rank import modal
     # from skimage.morphology import disk,square
     classes_map__ = classes_map.astype(np.uint16)  # convert dtype to uint16
     out = classes_map__
     for selem in selems:
         out = modal(classes_map__, selem)
         classes_map__ = out
     return out.astype(np.int8)
Example #6
0
def check_all():
    np.random.seed(0)
    image = np.random.rand(25, 25)
    selem = morphology.disk(1)
    refs = np.load(os.path.join(skimage.data_dir, "rank_filter_tests.npz"))

    assert_equal(refs["autolevel"], rank.autolevel(image, selem))
    assert_equal(refs["autolevel_percentile"], rank.autolevel_percentile(image, selem))
    assert_equal(refs["bottomhat"], rank.bottomhat(image, selem))
    assert_equal(refs["equalize"], rank.equalize(image, selem))
    assert_equal(refs["gradient"], rank.gradient(image, selem))
    assert_equal(refs["gradient_percentile"], rank.gradient_percentile(image, selem))
    assert_equal(refs["maximum"], rank.maximum(image, selem))
    assert_equal(refs["mean"], rank.mean(image, selem))
    assert_equal(refs["mean_percentile"], rank.mean_percentile(image, selem))
    assert_equal(refs["mean_bilateral"], rank.mean_bilateral(image, selem))
    assert_equal(refs["subtract_mean"], rank.subtract_mean(image, selem))
    assert_equal(refs["subtract_mean_percentile"], rank.subtract_mean_percentile(image, selem))
    assert_equal(refs["median"], rank.median(image, selem))
    assert_equal(refs["minimum"], rank.minimum(image, selem))
    assert_equal(refs["modal"], rank.modal(image, selem))
    assert_equal(refs["enhance_contrast"], rank.enhance_contrast(image, selem))
    assert_equal(refs["enhance_contrast_percentile"], rank.enhance_contrast_percentile(image, selem))
    assert_equal(refs["pop"], rank.pop(image, selem))
    assert_equal(refs["pop_percentile"], rank.pop_percentile(image, selem))
    assert_equal(refs["pop_bilateral"], rank.pop_bilateral(image, selem))
    assert_equal(refs["sum"], rank.sum(image, selem))
    assert_equal(refs["sum_bilateral"], rank.sum_bilateral(image, selem))
    assert_equal(refs["sum_percentile"], rank.sum_percentile(image, selem))
    assert_equal(refs["threshold"], rank.threshold(image, selem))
    assert_equal(refs["threshold_percentile"], rank.threshold_percentile(image, selem))
    assert_equal(refs["tophat"], rank.tophat(image, selem))
    assert_equal(refs["noise_filter"], rank.noise_filter(image, selem))
    assert_equal(refs["entropy"], rank.entropy(image, selem))
    assert_equal(refs["otsu"], rank.otsu(image, selem))
    assert_equal(refs["percentile"], rank.percentile(image, selem))
    assert_equal(refs["windowed_histogram"], rank.windowed_histogram(image, selem))
Example #7
0
def lone_object_filter(image,
                       min_size=2,
                       connectivity=1,
                       kernel_size=3,
                       unique_vals=None):
    """
    Replaces isolated, contiguous regions of values in a raster with values
    representing the surrounding pixels.

    More specifically, this reduces noise in a raster by setting
    contiguous regions of values greater than a specified minimum size to
    the modal value in a specified neighborhood.

    The default argument values filter out lone, singular pixels.
    This filter is not idempotent, so it may need to be applied repeatedly
    until the output stops changing or the results are acceptable.

    Args:
        image (numpy.ndarray):
            The image to filter. Must not contain NaNs.
        min_size (int):
            Defines the minimum number of contiguous pixels that will not
            be set to the modal value of their neighborhood. Must be greater than 2.
            Setting this to 1 is pointless, since this function will then do nothing to the raster.
        connectivity (int):
            The maximum distance between any two pixels such that they are
            considered one group. For example, a connectivity of 1 considers
            only adjacent values to be within one group (contiguous areas), but 
            a connectivity of 2 also considers diagonally connected values to be 
            within one group. Must be greater than 0.
        kernel_size (int or float):
            The diameter of the circular kernel to use for the modal filter.
            If there are still pixels that should be set to the
            modal value of their neighborhood, increase this value to remove them.
            Note that the larger this value is, the more detail will tend to be
            lost in the image and the slower this function will run.
        unique_vals: numpy.ndarray
            The unique values in `image`. If this is not supplied, the unique values will be
            determined on each call.

    Returns:
        The filtered image.

    Authors:
        Andrew Lubawy ([email protected])\n
        John Rattz    ([email protected])
    """
    import dask
    from .clean_mask import create_circular_mask
    from skimage.filters.rank import modal
    from skimage.morphology import remove_small_objects
    from .unique import dask_array_uniques

    assert kernel_size % 2 == 1, "The parameter `kernel_size` must be an odd number."
    image_min, image_max = image.min(), image.max()
    image_dtype = image.dtype
    image = (((image - image_min) / (image_max - image_min)) * 255).astype(
        np.uint8)
    if isinstance(image, np.ndarray):
        modal_filtered = modal(image,
                               create_circular_mask(kernel_size, kernel_size))
    elif isinstance(image, dask.array.core.Array):
        modal_filtered = image.map_blocks(modal,
                                          selem=create_circular_mask(
                                              kernel_size, kernel_size))

    image_da = xr.DataArray(image)
    if unique_vals is None:
        unique_vals = []
        if isinstance(image, np.ndarray):
            unique_vals = np.unique(image)
        elif isinstance(image, dask.array.core.Array):
            unique_vals = dask_array_uniques(image)
    else:  # Scale to the range [0,1].
        unique_vals = (((unique_vals - image_min) / (image_max - image_min)) *
                       255).astype(np.uint8)

    for i, val in enumerate(unique_vals):
        # Determine the pixels with this value that will not be filtered (True to keep).
        if isinstance(image, np.ndarray):
            layer = remove_small_objects(image == val,
                                         min_size=min_size,
                                         connectivity=connectivity)
        elif isinstance(image, dask.array.core.Array):
            layer = (image == val).map_blocks(remove_small_objects,
                                              min_size=min_size,
                                              connectivity=connectivity)
        # Select the values from the image that will remain (filter it).
        filtered = image_da.where(layer) if i == 0 else filtered.combine_first(
            image_da.where(layer))
    # Fill in the removed values with their local modes.
    filtered_nan_mask = xr_nan(filtered).data
    filtered = filtered.where(~filtered_nan_mask, modal_filtered)
    filtered = ((filtered / 255) * (image_max - image_min) +
                image_min).astype(image_dtype)
    return filtered.data
        PredictedTiles = ConvNetmodel.predict(I_tiles,
                                              batch_size=32,
                                              verbose=Chatty)
        #Convert the convnet one-hot predictions to a new class label image
        PredictedTiles[PredictedTiles < RecogThresh] = 0
        PredictedClass = class_prediction_to_image(Class, PredictedTiles, size)
        PredictedClass = SimplifyClass(PredictedClass, ClassKey)
        #Set classes to 0 if they do not have MinTiles detected by the CNN

        #for c in range(0,NClasses+1):
        #    count = np.sum(PredictedClass.reshape(-1,1) == c)
        #    if count <= MinTiles*size*size:
        #        PredictedClass[PredictedClass == c] = 0
        if MinTiles > 0:
            PredictedClass = modal(
                np.uint8(PredictedClass),
                np.ones((2 * MinTiles * size + 1, 2 * MinTiles * size + 1)))
            #PredictedClass = modal(np.uint8(PredictedClass), disk(2*(MinTiles*size*size)+1))

        #Prep the pixel data from the cropped image and new class label image
        print('Processing Entropy and Median filter')
        Entropy = entropy(Im3D[:, :, 0],
                          selem=np.ones([11, 11]),
                          shift_x=3,
                          shift_y=0)
        MedImage = ColourFilter(Im3D)  #Median filter on all 3 bands
        rv = MedImage[:, :, 0].reshape(-1, 1)  #Split and vectorise the bands
        gv = MedImage[:, :, 1].reshape(-1, 1)
        bv = MedImage[:, :, 2].reshape(-1, 1)
        #Vectorise the bands, use the classification prdicted by the CNN
        #m = np.ndarray.flatten(PredictedClass).reshape(-1,1)
def cleanup_mask(mask, n):
    """Eliminate small islands in the mask"""
    m = minify(mask, n).astype(np.uint8)
    m = m & modal(m, ELEMENT)
    return oversample(m, n).astype(bool)
Example #10
0
    def processAlgorithm(self, parameters, context, feedback):

        try:
            import networkx as nx
            from osgeo import gdal as osgdal
            from skimage.io import imread
            from skimage.color import rgb2gray
            from skimage.filters import threshold_local, threshold_otsu
            from skimage.util import invert
            from skimage.morphology import disk
            from skimage.filters.rank import modal, threshold_percentile, otsu
            from skimage.util import img_as_ubyte

        except Exception as e:
            feedback.reportError(
                QCoreApplication.translate('Error', '%s' % (e)))
            feedback.reportError(QCoreApplication.translate('Error', ' '))
            feedback.reportError(
                QCoreApplication.translate(
                    'Error',
                    'Error loading modules - please install the necessary dependencies'
                ))
            return {}

        rlayer = self.parameterAsRasterLayer(parameters, self.Raster, context)
        inv = parameters[self.inv]
        block_size = parameters[self.blocks]
        adaptMethod = parameters[self.adaptMethod]
        mode = parameters[self.blur]
        method = parameters[self.Method]
        p = parameters[self.percent]

        aMethod = {0: "gaussian", 1: "mean", 2: "median"}

        outputRaster = self.parameterAsOutputLayer(parameters, self.outRaster,
                                                   context)

        fname = ''.join(
            random.choice(string.ascii_lowercase) for i in range(10))

        outFname = os.path.join(tempfile.gettempdir(), '%s.tif' % (fname))
        rect = rlayer.extent()
        dp = rlayer.dataProvider()
        raster = dp.dataSourceUri()

        img = imread(raster)

        if dp.bandCount() == 1:
            grayscale = img
        else:
            try:
                grayscale = rgb2gray(img)
            except Exception as e:
                feedback.reportError(
                    QCoreApplication.translate('Error', str(e)))
                feedback.reportError(QCoreApplication.translate('Error', ' '))
                feedback.reportError(
                    QCoreApplication.translate(
                        'Error',
                        'Failed to convert image from RGB to grayscale'))
                return {}

        if inv:
            grayscale = invert(grayscale)

        if block_size > 0 and block_size % 2 == 0:
            block_size += 1
            feedback.reportError(
                QCoreApplication.translate(
                    'Info',
                    'Warning: Algorithm requires an odd value for the block size parameter - selecting a value of %s'
                    % (block_size)))

        nrows, ncols = grayscale.shape
        if method == 0:
            if block_size > 0:
                grayscale = img_as_ubyte(grayscale)
                thresh = otsu(grayscale, disk(block_size))
                binary = (grayscale < thresh).astype(float)
            else:
                thresh = threshold_otsu(grayscale)
                binary = (grayscale < thresh).astype(float)
        else:
            if block_size == 0.0:
                block_size = int((nrows * 0.01) * (ncols * 0.01))
                if block_size % 2 == 0:
                    block_size += 1
                feedback.pushInfo(
                    QCoreApplication.translate(
                        'Info', 'Automatically selecting a block size of %s' %
                        (block_size)))

            if method == 1:
                local_thresh = threshold_local(image=grayscale,
                                               block_size=block_size,
                                               method=aMethod[adaptMethod])
                binary = (grayscale < local_thresh).astype(float)
            else:
                thresh = threshold_percentile(grayscale,
                                              disk(block_size),
                                              p0=p)
                binary = (grayscale > thresh).astype(float)

        if mode > 0:
            binary = modal(binary, disk(mode))
            binary = (binary > 1).astype(float)

        xres = rlayer.rasterUnitsPerPixelX()
        yres = rlayer.rasterUnitsPerPixelY()

        driver = osgdal.GetDriverByName('GTiff')
        dataset = driver.Create(
            outputRaster,
            ncols,
            nrows,
            1,
            osgdal.GDT_Float32,
        )

        dataset.SetGeoTransform(
            (rect.xMinimum(), xres, 0, rect.yMaximum(), 0, -yres))

        wkt_prj = rlayer.crs().toWkt()
        dataset.SetProjection(wkt_prj)
        band = dataset.GetRasterBand(1)
        band.SetNoDataValue(0)
        band.WriteArray(binary)
        dataset, band = None, None

        return {self.outRaster: outputRaster}
        for r in range(0, Im3D.shape[0] - Kernel_size):

            if r % 1000 == 0:
                print("%d: %s" % (r, 'of ' + str(Im3D.shape[0])))
            #print('row '+str(r)+' of '+str(Im3D.shape[0]))
            Irow = Im3D[r:r + Kernel_size, :, :]
            #tile the image
            Tiles = np.squeeze(slide_rasters_to_tiles(
                Irow, Kernel_size)) / NormFactor
            Predicted = model.predict(Tiles, batch_size=25000)

            PredictedSubImage[r, :] = np.argmax(Predicted, axis=1)

    if SmallestElement > 0:
        PredictedSubImage = modal(
            np.uint8(PredictedSubImage),
            disk(2 * SmallestElement))  #clean up the class with a mode filter

    PredictedImage = np.zeros((Im3D.shape[0], Im3D.shape[1]))
    PredictedImage[Kernel_size // 2:Im3D.shape[0] - Kernel_size // 2,
                   Kernel_size // 2:Im3D.shape[1] -
                   Kernel_size // 2] = PredictedSubImage
    Predicted = None
    PredictedSubImage = None
    #close the TF session
    session.close()
    # # =============================================================================
    #'''Detect Calving front from binary morphology operations and active contours'''
    print('Detecting Calving Front')
    try:
        import feather
Example #12
0
def modal_skimage(img):
    img = to_gray(img)
    img = img.astype(np.uint8)
    edges = modal(img, disk(6))

    return edges
Example #13
0
def segmentation(model=None,
                 params=None,
                 src=None,
                 bands=[1, 2, 3],
                 image=None,
                 mask=None,
                 modal_radius=None,
                 sieve_size=250):
    """
    Segment the image.

    Segment the image using an algorithm from sklearn.segmentation.

    Parameters
    ----------
    model: sklearn.segmentation model
        A model from sklearn.segmentation (e.g., slic, slic0, felzenswalb)

    params: sklearn.segmentation model parameters
        The unique parameters for the selected segmentation algorithm. Will be
        passed to the model as the kwargs argument.

    src: Rasterio datasource
        A rasterio-style datasource, created using:
        with rasterio.open('path') as src.
        There must be at least 3 bands of image data. If there are more than
        3 bands, the first three will be used (see 'bands' parameter). This 
        parameter is optional. **If it is not provided, then image and transform
        must be supplied.--really?? Not any more, right?**
    
    bands: array of integers
        The array of 3 bands to read from src as the RGB image for segmentation.
        
    image: numpy.array
        A 3-band (RGB) image used for segmentation. The shape of the image
        must be ordered as follows: (bands, rows, columns).
        This parameter is optional.
    
    mask: numpy.array
        A 1-band image mask. The shape of the mask must be ordered as follows:
        (rows, columns). This parameter is optional.
    
    modal_radius: integer
        Integer representing the radius of a raster disk (i.e., circular
        roving window). Optional. If not set, no modal filter will be applied.
    
    sieve_size: integer
        An integer representing the smallest number of pixels that will be
        included as a unique segment. Segments this size or smaller will be
        merged with the neighboring segment with the most pixels. 

    Returns
    -------
    numpy.array
        A numpy array arranged as rasterio would read it (bands=1, rows, cols)
        so it's ready to be written by rasterio

    """
    if src is not None:
        img = bsq_to_bip(src.read(bands, masked=True))
        mask = src.read_masks(1)
        mask[mask > 0] = 1
    else:
        img = bsq_to_bip(image)
        mask[mask > 255] = 1

    output = model(img, **params).astype('int32')

    while np.ndarray.min(output) < 1:
        output += 1

    if modal_radius != None:
        output = modal(output.astype('int16'),
                       selem=disk(modal_radius),
                       mask=mask)


#    output = features.sieve(output, sieve_size, mask=mask,
#                            connectivity=8) * mask
    output = features.sieve(output, sieve_size, mask=mask) * mask
    #    output = label(output, connectivity=2)
    output = label(output, connectivity=1)

    output = bip_to_bsq(output[:, :, np.newaxis]) * mask

    return output
Example #14
0
original_image = color.rgb2gray(data.camera())
plt.imshow(original_image, cmap=plt.cm.gray)

filtered_images = []
filtered_images.append(sfr.autolevel(original_image, disk(5)))
filtered_images.append(sfr.bottomhat(original_image, disk(5)))
filtered_images.append(sfr.tophat(original_image, disk(5)))
filtered_images.append(sfr.enhance_contrast(original_image, disk(5)))
filtered_images.append(sfr.entropy(original_image, disk(5)))
filtered_images.append(sfr.equalize(original_image, disk(5)))
filtered_images.append(sfr.gradient(original_image, disk(5)))
filtered_images.append(sfr.maximum(original_image, disk(5)))
filtered_images.append(sfr.minimum(original_image, disk(5)))
filtered_images.append(sfr.mean(original_image, disk(5)))
filtered_images.append(sfr.median(original_image, disk(5)))
filtered_images.append(sfr.modal(original_image, disk(5)))
filtered_images.append(sfr.otsu(original_image, disk(5)))
filtered_images.append(sfr.threshold(original_image, disk(5)))
filtered_images.append(sfr.subtract_mean(original_image, disk(5)))
filtered_images.append(sfr.sum(original_image, disk(5)))

name_list = [
    'autolevel', 'bottomhat', 'tophat', 'enhance_contrast', 'entropy',
    'equalize', 'gradient', 'maximum', 'minimum', 'mean', 'median', 'modal',
    'otsu', 'threshold', 'subtract_mean', 'sum'
]

fig, axes = plt.subplots(nrows=4, ncols=4, figsize=(8, 8))
axes = axes.ravel()
for ax, img, name in zip(axes, filtered_images, name_list):
    ax.imshow(img, cmap=plt.cm.gray, interpolation='nearest')
def lone_object_filter(image, min_size=2, connectivity=1, kernel_size=3):
    """
    Replaces isolated, contiguous regions of values in a raster with values
    representing the surrounding pixels.

    More specifically, this reduces noise in a raster by setting
    contiguous regions of values greater than a specified minimum size to
    the modal value in a specified neighborhood.

    The default argument values filter out lone, singular pixels.
    This filter is not idempotent, so it may need to be applied repeatedly
    until the output stops changing or the results are acceptable.

    Args:
        image (numpy.ndarray):
            The image to filter. Must not contain NaNs.
        min_size (int):
            Defines the minimum number of contiguous pixels that will not
            be set to the modal value of their neighborhood. Must be greater than 2.
            Setting this to 1 is pointless, since this function will then do nothing to the raster.
        connectivity (int):
            The maximum distance between any two pixels such that they are
            considered one group. For example, a connectivity of 1 considers
            only adjacent values to be within one group, but a connectivity of 2
            also considers diagonally connected values to be within one group. 
            Must be greater than 0.
        kernel_size (int or float):
            The diameter of the circular kernel to use for the modal filter.
            If there are still contiguous regions of pixels that should be set to the
            modal value of their neighborhood, increase this value to remove them.
            This parameter generally should scale roughly with the square root of the 
            `min_size` parameter. Note that the larger this value is, the more detail 
            may be lost in the image and the slower this function will run.

    Returns:
        The filtered image.

    Authors:
        Andrew Lubawy ([email protected])\n
        John Rattz    ([email protected])
    """
    assert kernel_size % 2 == 1, "The parameter `kernel_size` must be an odd number."
    image_min, image_max = image.min(), image.max()
    image_dtype = image.dtype
    image = np.interp(image, [image_min, image_max], [0, 255]).astype(np.uint8)
    modal_filtered = modal(image, create_circular_mask(kernel_size,
                                                       kernel_size))

    da = xr.DataArray(image)
    for i, val in enumerate(np.unique(image)):
        # Determine the pixels with this value that will be not be filtered (True to keep).
        layer = remove_small_objects(image == val,
                                     min_size=min_size,
                                     connectivity=connectivity)
        # Select the values from the image that will remain (filter it).
        filtered = da.where(layer) if i == 0 else filtered.combine_first(
            da.where(layer))
    # Fill in the removed values with their local modes.
    filtered_nan_mask = np.isnan(filtered.values)
    filtered.values[filtered_nan_mask] = modal_filtered[filtered_nan_mask]
    filtered.values = np.interp(filtered.values, [0, 255],
                                [image_min, image_max]).astype(image_dtype)
    return filtered.values
Example #16
0
def cleanup_mask(mask, n):
    """Eliminate small islands in the mask"""
    m = minify(mask, n).astype(np.uint8)
    m = m & modal(m, ELEMENT)
    return oversample(m, n).astype(bool)