Skip to content

COG cubic overview poisoned by nodata sentinel #1623

@brendancol

Description

@brendancol

to_geotiff(cog=True, overview_resampling='cubic', nodata=<finite>) produces overview pixels with bad ringing artefacts near nodata regions on float rasters.

Same root cause as #1613, but for the cubic branch of _block_reduce_2d. The writer rewrites NaN to the finite sentinel before reduction. Then _block_reduce_2d(method='cubic') ignores the nodata argument and hands the sentinel-poisoned array straight to scipy.ndimage.zoom(order=3). The cubic spline blends the sentinel into neighbouring cells.

Repro:

import numpy as np, xarray as xr, tempfile, os
from xrspatial.geotiff import to_geotiff, open_geotiff

arr = np.ones((16, 16), dtype=np.float32) * 100.0
arr[:4, :4] = np.nan
da = xr.DataArray(arr, dims=['y', 'x'])

with tempfile.TemporaryDirectory() as tmp:
    path = os.path.join(tmp, 'cog_cubic.tif')
    to_geotiff(da, path, compression='deflate', tile_size=8, tiled=True,
               cog=True, nodata=-9999.0, overview_levels=[1],
               overview_resampling='cubic')
    ov = open_geotiff(path, overview_level=1)
    print(ov.values)

The overview should hold only 100.0, NaN at the masked pixels, and the sentinel. Instead bordering cells read 1133.44, -10290.08, 177.26, 104.70.

The mean, min, max, and median methods already handle this via the nan* reducers after a sentinel-to-NaN mask (#1613). nearest and mode are fine on their own semantics. Only cubic is broken.

Scope:

  • CPU: _block_reduce_2d cubic branch at xrspatial/geotiff/_writer.py:164-171.
  • GPU: _block_reduce_2d_gpu does not implement cubic and raises ValueError. The GPU helper can defer to the CPU cubic path the same way it already does for mode.

Severity HIGH (Cat 2 NaN propagation + Cat 5 backend divergence). The failure mode is quiet: a downstream consumer reading overview tiles for preview sees the ringing as real data.

Found by deep-sweep-accuracy 2026-05-11.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions