2

To reduce noise in a raster file, I aim to eliminate isolated pixels, those surrounded by NoData values in all eight neighboring positions.

I have this code, but it is not removing those isolated pixels, it removes some others, and I do not understand why:

import rasterio
from rasterio.enums import Resampling
from rasterio.fill import fillnodata

# Open the TIFF file
with rasterio.open('input.tif') as src:
    # Read the raster data
    data = src.read(1)
    nodata_value = src.nodata

    # Set the NoData pixels surrounded by 8 NoData pixels to the NoData value
    filled_data = fillnodata(data, mask=data == nodata_value, max_search_distance=1, smoothing_iterations=0)

    # Create a new TIFF file with the filled data
    with rasterio.open('output.tif', 'w', **src.profile) as dst:
        dst.write(filled_data, 1)
1
  • 1
    By the documentation rasterio.readthedocs.io/en/latest/api/rasterio.fill.html fillnodata tries to fill the nodata cells with data that is interpolated from the neighboring cells. Don't you try to do something else # Set the Data pixels surrounded by 8 NoData pixels to the NoData value?
    – user30184
    Commented Aug 28, 2023 at 16:24

1 Answer 1

3

You could use rasterio.features.sieve. Based on the rasterio sieve example

import numpy as np
import rasterio
from rasterio.features import sieve


with rasterio.open('tests/data/shade.tif') as src:

    # Sieve out features 1 pixels or smaller.
    sieved = sieve(src, 1, out=np.zeros(src.shape, src.dtypes[0]))

    # Write out the sieved raster.
    kwargs = src.profile
    with rasterio.open('sieved.tif', 'w', **kwargs) as dst:
        dst.write(sieved, indexes=1)

Original

enter image description here

Sieved on top of original

enter image description here

For floating point data, you could do this:

import numpy as np
import rasterio
from rasterio.features import sieve


with rasterio.open('shade_float32.tif') as src:

    data = src.read(1, masked=True)

    # Invert the mask
    mask = (~data.mask).astype("uint8")

    # Sieve out features 1 pixel or smaller.
    sieved = sieve(mask, 1, out=np.zeros_like(mask))

    # Update the mask
    data.mask = ~(sieved.astype(bool))

    # Write out the sieved raster.
    kwargs = src.profile
    with rasterio.open('sieved.tif', 'w', **kwargs) as dst:
        dst.write(data, indexes=1)
2
  • The datatype of my raster is float32 and I get the following error: ValueError: image dtype must be one of: rasterio.int16, rasterio.int32, rasterio.uint8, rasterio.uint16, even that the documentations says that float32 is a valid datatype: rasterio.readthedocs.io/en/latest/api/…
    – Isa
    Commented Aug 29, 2023 at 10:54
  • Sounds like a doc error. See edit above to handle float32
    – user2856
    Commented Aug 29, 2023 at 21:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.