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
Context
Dataset.recreate_overviews()rebuilds a raster's existing overviews one level at a time. A long-standingTODOin thecode 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(insiderecreate_overviews).Problem / Current Behaviour
recreate_overviews()regenerates overviews with the singulargdal.RegenerateOverviewin a nested loop — one callper (band × overview level):
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.Bandhas no such method (hasattrisFalse).gdal.RegenerateOverviews(srcBand, overviewList, resampling).Affected locations
src/pyramids/dataset/engines/io.pyrecreate_overviews(~L2917)src/pyramids/dataset/engines/io.pysrc/pyramids/dataset/abstract_dataset.pyRESAMPLING_METHODS(L49)Motivation Example
Proposed Solution
Replace the inner per-overview loop with a single plural call per band, preserving the resampling method and the
read-only handling:
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)acceptsa 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 viaBuildOverviews) — unchanged.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_overviewsusesgdal.RegenerateOverviews(plural), one call per band, preservingresampling_method.ReadOnlyError(behaviour preserved).(e.g.
"average"), and that read-only input raisesReadOnlyError.