Skip to content

perf(dataset): batch overview regeneration in recreate_overviews via gdal.RegenerateOverviews #783

Description

@MAfarrag

Context

Dataset.recreate_overviews() rebuilds a raster's existing overviews one level at a time. A long-standing TODO in the
code proposes switching to GDAL's batch gdal.RegenerateOverviews (plural) for speed, but says it was avoided because
"it does not give the option to choose the resampling method."

That premise is outdated. On the GDAL we ship (verified on 3.13.1), the plural function does accept a resampling
method, so the optimization can be taken with no loss of functionality. This issue tracks making that change and
correcting the stale TODO.

TODO location: src/pyramids/dataset/engines/io.py:2922-2926 (inside recreate_overviews).

Problem / Current Behaviour

recreate_overviews() regenerates overviews with the singular gdal.RegenerateOverview in a nested loop — one call
per (band × overview level):

# src/pyramids/dataset/engines/io.py  (recreate_overviews, ~L2917-2931)
for i in range(self._ds.band_count):
    band = self._ds._iloc(i)
    for j in range(self.overview_count[i]):
        ovr = self.get_overview(i, j)
        gdal.RegenerateOverview(band, ovr, resampling_method)   # singular: one overview per call

Each singular call reads the full-resolution band again, so a band with N overview levels triggers N source read passes.
gdal.RegenerateOverviews (plural) reads the source band once and regenerates all levels in that pass — fewer passes,
faster on large multi-band rasters. Correctness is identical; only performance differs.

The inline TODO snippet is also wrong in two ways and should not be copied verbatim:

  • band.RegenerateOverviews(overviews) does not exist — gdal.Band has no such method (hasattr is False).
  • The correct call is the module function gdal.RegenerateOverviews(srcBand, overviewList, resampling).

Affected locations

File Symbol Notes
src/pyramids/dataset/engines/io.py recreate_overviews (~L2917) nested singular-call loop to replace
src/pyramids/dataset/engines/io.py TODO at L2922-2926 stale premise; correct or remove
src/pyramids/dataset/abstract_dataset.py RESAMPLING_METHODS (L49) allowed resampling names, unchanged

Motivation Example

from pyramids.dataset import Dataset
ds = Dataset.read_file("large_multiband.tif", read_only=False)
ds.create_overviews(resampling_method="average")
# rebuild existing overviews — currently N source-read passes per band; should be one
ds.recreate_overviews(resampling_method="average")

Proposed Solution

Replace the inner per-overview loop with a single plural call per band, preserving the resampling method and the
read-only handling:

try:
    for i in range(self._ds.band_count):
        band = self._ds._iloc(i)
        overviews = [band.GetOverview(j) for j in range(band.GetOverviewCount())]
        if overviews:                                            # bands may have no overviews
            gdal.RegenerateOverviews(band, overviews, resampling_method)
except RuntimeError:
    raise ReadOnlyError(
        "The Dataset is opened with a read only. Please read the dataset using read_only=False"
    )

Then update/remove the TODO so it no longer claims the plural form lacks resampling selection.

Verification already done: on GDAL 3.13.1, gdal.RegenerateOverviews(srcBand, [overviewBands...], resampling) accepts
a Python list of overview bands plus a resampling name and returns 0 (success) for both "nearest" and "average".

Out of Scope

  • create_overviews() (initial build via BuildOverviews) — unchanged.
  • Adding new resampling methods or overview levels.
  • Any COG/zarr overview handling.

Effort Estimate

Size: XS (<1h)
Rationale: a localized loop change plus a comment fix and one focused test; no API or behaviour change.

Definition of Done

  • recreate_overviews uses gdal.RegenerateOverviews (plural), one call per band, preserving resampling_method.
  • The stale TODO at L2922-2926 is corrected or removed.
  • Read-only datasets still raise ReadOnlyError (behaviour preserved).
  • A test asserts overviews are regenerated for a multi-band raster with a non-default resampling method
    (e.g. "average"), and that read-only input raises ReadOnlyError.
  • All existing overview tests continue to pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions