Choosing Overview Levels and Resampling for Archived Imagery
Overviews are the reason a COG can answer a zoomed-out question cheaply, and the two parameters that govern them — how many levels, and how pixels are combined at each — are set once at conversion and cannot be changed without rewriting the object. This walkthrough is for the archivist or engineer specifying those parameters for a raster collection, and it covers the case that catches people out: categorical rasters, where the default resampling method invents land-cover classes that do not exist in the source.
How Far Down to Build
The rule that works for archives is to build until the whole scene fits inside roughly one internal tile. Stopping early leaves a gap where a zoomed-out request must decode full-resolution data; going further adds levels nobody reads.
Step-by-Step Procedure
Step 1 — Derive the level count from the scene dimensions
# Levels needed so the smallest overview fits within one 512-px tile
python3 - <<'PY'
import math
w, h, tile = 24000, 18000, 512
levels = math.ceil(math.log2(max(w, h) / tile))
print(f"{w}x{h} with {tile}px tiles -> {levels} overview levels")
PY
# 24000x18000 with 512px tiles -> 6 overview levels
Step 2 — Choose resampling from what the pixels mean
This is the decision that produces silently wrong data when it is made by default. Averaging a land-cover raster whose values are class codes produces new codes: average a pixel of class 3 (grassland) with one of class 7 (water) and the overview shows class 5 (industrial).
# Continuous data — elevation, reflectance, temperature
gdal_translate dem_n5432.tif dem_cog.tif -of COG \
-co OVERVIEW_RESAMPLING=AVERAGE -co PREDICTOR=3 -co COMPRESS=DEFLATE
# Categorical data — land cover, classification masks, zoning
gdal_translate landcover_2024.tif landcover_cog.tif -of COG \
-co OVERVIEW_RESAMPLING=NEAREST -co PREDICTOR=2 -co COMPRESS=DEFLATE
# Categorical where the dominant class should survive the zoom-out
gdal_translate landcover_2024.tif landcover_mode_cog.tif -of COG \
-co OVERVIEW_RESAMPLING=MODE -co PREDICTOR=2 -co COMPRESS=DEFLATE
Step 3 — Verify what the overviews actually contain
Do not trust the parameter; read the pixels back. For a categorical raster, the set of distinct values in the overview must be a subset of the source’s legend.
from osgeo import gdal
import numpy as np
ds = gdal.Open("landcover_cog.tif")
band = ds.GetRasterBand(1)
legend = set(np.unique(band.ReadAsArray()).tolist())
for i in range(band.GetOverviewCount()):
ov = set(np.unique(band.GetOverview(i).ReadAsArray()).tolist())
invented = ov - legend
print(f"overview {i}: {len(ov)} classes, invented={sorted(invented) or 'none'}")
Expected output reports invented=none at every level. Any invented value means the resampling method was wrong for this raster, and the file must be rewritten — the overviews cannot be replaced in place without disturbing the COG layout.
Validation & Verification
gdalinfo -json landcover_cog.tif \
| jq '{overviews: (.bands[0].overviews | map(.size)), block: .bands[0].block}'
Expected output lists overview sizes halving at each step down to a level smaller than the tile size, and a block size matching the conversion’s setting. Sizes that stop halving early indicate the pyramid was truncated; a single overview far smaller than the rest usually means a pre-existing pyramid was inherited rather than regenerated.
Troubleshooting
| Symptom | Root cause | Fix |
|---|---|---|
| Overview shows classes absent from the legend | AVERAGE used on categorical data |
Rewrite with MODE; verify with the distinct-value check |
| Halo of odd values along scene edges | Nodata averaged into real pixels | Declare nodata before conversion so resampling excludes it |
| Elevation overviews look terraced | NEAREST used on continuous data |
Use AVERAGE; nearest discards the smoothing zoom-out needs |
| Only two overview levels present | Level count derived from a default, not the dimensions | Compute levels from the scene size and pass them explicitly |
| Smallest overview still 8,000 px wide | Pyramid stopped short of the tile size | Add levels; the marginal size cost past level 2 is under 1% |
Operational Execution Checklist
What the Overview Choice Costs a Mosaic
Overviews are read far more often than full-resolution pixels, because most viewing happens zoomed out. That makes the resampling choice a visible property of the archive rather than an internal detail — it is what a user sees on first contact with almost every scene.
Where a collection is mosaicked routinely, review a zoomed-out render of two adjacent scenes as part of accepting the conversion. It takes a minute, it catches the resampling mistake immediately, and it catches it before the whole collection has been written with the wrong setting.
Frequently Asked Questions
Do overviews need to be rebuilt if the source data is corrected?
Yes — overviews are derived data and become stale the moment the full-resolution pixels change. Because a COG’s layout puts them before the image data, updating them means rewriting the file, which is one more reason corrections should be applied before the object is tiered and locked rather than after.
Is there a case for storing overviews as a separate file?
External overviews in a .ovr sidecar were the norm before COG and still work, but they reintroduce the multi-file problem that lifecycle rules handle badly — the sidecar and the raster can be tiered separately and land in different classes. For archival use, internal overviews inside a single self-contained object are the better trade.
How much do overviews cost in a compressed archive?
Roughly a third of the full-resolution size, and slightly less in practice because overviews compress better than the source: they are smoother, so a predictor plus DEFLATE finds more redundancy. Against the read savings, it is the least contentious storage overhead in an imagery archive.
Can different bands of one raster need different resampling?
Occasionally, and it is worth checking on multi-band products that mix continuous and categorical layers — a stack carrying reflectance bands plus a quality-assurance mask, for instance. Where the tooling cannot apply per-band methods, splitting the categorical band into its own file is cleaner than compromising on one method for both.
Do overviews affect how the file is validated?
They are part of what a structural check looks at: a COG validator reports both their presence and whether they are correctly ordered relative to the full-resolution data. A scene with overviews that were appended after the fact often fails the layout check even though the pyramid itself is fine, which is one of the commonest advisory findings in inherited collections.
Should the number of levels be uniform across a collection?
The depth should follow each scene’s dimensions, which means the level count varies with scene size — a uniform count would leave large scenes short and small ones with pointless extra levels. What should be uniform is the rule: build until the smallest overview fits within one internal tile.
Should overviews be validated separately from the full-resolution data?
Yes, for categorical rasters, where the distinct-value check on each level is the only thing that catches a wrong resampling method. For continuous data the presence and count of levels is sufficient, since averaging cannot produce values outside the source range. The asymmetry is worth encoding in the gate rather than applying the stricter check everywhere.
What happens if a scene is too small to need overviews?
Nothing needs to be built, and the validator should not require them. A scene whose full resolution already fits within one or two internal tiles is its own overview, and forcing levels onto it adds metadata for no benefit. Deriving the level count from the dimensions handles this automatically, which is another reason not to fix it as a constant.
Can overviews be added to an existing archived COG?
Not without rewriting the file, because a COG’s layout places them before the image data. External overviews in a sidecar are technically possible and reintroduce the multi-file problem lifecycle rules handle badly. For an archived scene the practical answer is to record the gap and address it at the next rewrite.
Is bilinear resampling ever the right choice?
For continuous data where averaging softens edges too much — a hillshade, for instance. It is a reasonable middle ground and is not appropriate for categorical data for the same reason averaging is not.
Related
- Cloud-Optimized GeoTIFF Conversion Pipelines — the parent topic where overview policy sits alongside tiling and compression.
- Converting GeoTIFF to Cloud-Optimized GeoTIFF at Scale — the fleet job that applies these parameters per scene.
- Tuning COG Internal Tile Size for Range Requests — the other half of the layout decision.
- Validating GeoTIFF Structure After a Cold Restore — the check that catches missing overviews years later.
Up one level: Cloud-Optimized GeoTIFF Conversion Pipelines.