Skip to content

Add morphological raster operators (erode, dilate, open, close) #949

@brendancol

Description

@brendancol

Reason or Problem

There's no way to do morphological operations (erosion, dilation, opening, closing) in xarray-spatial. These are basic raster operations used to clean up classification outputs, remove salt-and-pepper noise, and extract features from binary masks. The library has focal statistics and apply, but those aren't the same thing. scipy.ndimage and scikit-image can do morphology, but neither supports CuPy/Dask backends or xarray DataArrays.

Proposal

Design:

New module xrspatial/morphology.py with four functions:

  • erode(raster, kernel) -- minimum filter over kernel footprint
  • dilate(raster, kernel) -- maximum filter over kernel footprint
  • opening(raster, kernel) -- erosion then dilation (removes small bright features)
  • closing(raster, kernel) -- dilation then erosion (fills small dark gaps)

Kernels can be rectangular, circular, or user-defined 2D arrays. NumPy/Dask backends use the map_overlap + @ngjit pattern from focal.py. CuPy backend uses CUDA kernels with shared memory tiling.

Usage:

from xrspatial import erode, dilate, opening

# Clean up a classification mask
cleaned = opening(binary_mask, kernel=np.ones((3, 3)))

# Grayscale morphology on elevation
eroded_dem = erode(elevation, kernel=np.ones((5, 5)))

Value:

Anyone doing raster classification or feature extraction hits this gap eventually. There's currently no GDAL-free Python library that provides these operations with GPU and Dask support on xarray DataArrays.

Stakeholders and Impacts

GIS analysts doing classification post-processing, land cover mapping, feature extraction from binary masks. No impact on existing modules.

Drawbacks

  • For pure NumPy workflows, scipy.ndimage already covers this. The point is CuPy/Dask support.
  • Opening and closing compose two passes of erode/dilate, so they cost 2x a single operator.

Alternatives

  • scipy.ndimage.binary_erosion/binary_dilation: NumPy-only, no Dask or CuPy.
  • cupyx.scipy.ndimage: CuPy-only, no Dask integration.
  • Wrapping either loses multi-backend dispatch.

Unresolved Questions

  • Whether to include morphological gradient (dilate - erode) and top-hat transforms initially, or defer.
  • Circular kernels: helper function, or just accept a radius parameter?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions