Short answer
Reprojecting a raster does not just relabel coordinates — it resamples the pixel grid onto new cell centres, and every output value is interpolated from the input. You "damage" resolution when you choose the wrong resampling method for the data type, or set an output cell size that is coarser than the source (losing real detail) or finer than the source (faking detail). To reproject cleanly: know the source CRS, pick the resampling method that matches whether the data is continuous or categorical, set the output resolution explicitly to match the true ground sampling distance, and verify the result against the original.
Why reprojection changes pixels at all
A raster is a regular grid in one coordinate system. Reproject it to another, and the grid no longer lines up — the new CRS warps the cell positions. GDAL therefore builds a fresh output grid and, for each output cell, looks back into the input and computes a value. That look-back is resampling, and it is where quality is won or lost.
This is fundamentally different from assigning a CRS. Assigning (gdal_edit.py -a_srs) only writes a label and is correct only when the pixels are already in that CRS but lost their metadata. Reprojecting (gdalwarp -t_srs) recomputes coordinates and pixel values. Confusing the two is the classic error: assigning a wrong CRS to "make it fit" silently corrupts the georeferencing.
Choose the resampling method by data type
The single most important decision is the resampling algorithm, and it depends on whether your raster is continuous or categorical.
- Continuous data (DEM, reflectance, temperature): use
bilinear(4-neighbour) orcubic(16-neighbour). These interpolate smoothly, which is physically reasonable for an elevation surface.cubicsplineandlanczosare smoother still but can overshoot near sharp edges. - Categorical data (land cover, lithology codes, classified rasters): use
near(nearest-neighbour). Averaging class code 3 and class code 7 to get 5 is meaningless — bilinear on a categorical raster invents classes that do not exist. If you must downsample categories, usemode(most frequent value within the window) rather than an averaging method.
Getting this wrong is the most common way to "damage" a raster: bilinear-resampled land cover looks plausible at a glance but the class boundaries are now contaminated with fictional intermediate codes.
Set the output resolution deliberately
gdalwarp will pick an output resolution for you if you omit -tr, and its guess often does not match the source. Two failure modes:
- Too coarse: you discard real detail the source contained.
- Too fine (oversampling): you create a bigger file whose extra pixels are pure interpolation — no new information, just disk and processing cost, plus a false impression of precision.
Compute the input ground sampling distance first (gdalinfo input.tif reports pixel size in the source CRS units), then choose an output -tr in the target CRS units that keeps the same effective resolution. For a 30 m DEM going from EPSG:4326 to EPSG:32633 (UTM, metres), 30 m is the honest output size:
gdalwarp -s_srs EPSG:4326 -t_srs EPSG:32633 \
-r bilinear -tr 30 30 -tap \
-dstnodata -9999 \
-co TILED=YES -co COMPRESS=DEFLATE \
dem_geographic.tif dem_utm.tif
-tap (target-aligned pixels) snaps the grid to clean coordinate multiples, which keeps tiles and repeated runs consistent. Remember that in geographic CRS the cell size is in degrees (0.000277° ≈ 30 m at the equator, less elsewhere), so resolution numbers are not comparable across CRS without converting units.
Worked example: reproject a DEM and check it survived
- Inspect the source:
gdalinfo dem_geographic.tifto confirm the declared CRS, pixel size (degrees), NoData value and data type. - Pick method and resolution: continuous elevation →
bilinear; UTM target → output-tr 30 30in metres. - Warp with the command above, carrying the NoData value so void cells are not interpolated into the surface.
- Compare statistics:
gdalinfo -statson input and output. Min/max should be essentially unchanged; if the max jumped, an overshoot or NoData leak occurred. - Visual check in QGIS: load both, generate a hillshade from each (Raster ▸ Analysis ▸ Hillshade, or
gdaldem hillshade), and confirm ridgelines and drainage match. Smearing or stair-stepping signals the wrong method or resolution. - Measure a known feature (a dam crest length, a survey baseline) in the reprojected raster's CRS to confirm planar units behave.
In QGIS the same operation is Raster ▸ Projections ▸ Warp (Reproject), which exposes the resampling method and target resolution fields — set both rather than accepting defaults. ArcGIS Pro's Project Raster tool offers the equivalent Resampling Technique and Output Cell Size parameters.
DEMs need extra care
Elevation rasters are unforgiving because downstream products amplify errors:
- Slope and aspect are derivatives; resampling artefacts in the DEM become exaggerated ridges and pits in
gdaldem slope. Reproject once, early, and derive slope/aspect/hillshade from the reprojected DEM rather than reprojecting those derived products. - Vertical datum and units are separate from the horizontal CRS.
gdalwarpdoes not transform vertical datums by default; if your DEM is orthometric (e.g. EGM2008) and your workflow expects ellipsoidal heights, that is a distinct correction. Keep vertical units (metres vs feet) explicit. - NoData / voids: always carry
-dstnodata. Without it, void cells get interpolated and create phantom terrain.
Common pitfalls and the reason behind them
- Bilinear on categorical rasters — happens because bilinear is the eye-pleasing default; it fabricates class codes. Use
near/mode. - Accepting the default output resolution — happens because
-tris optional; it silently coarsens or oversamples. Set it from the measured input GSD. - Reprojecting derived products — reprojecting a slope raster instead of the DEM compounds interpolation error. Reproject the source, then derive.
- Assign vs reproject confusion — assigning a CRS to "move" a layer corrupts georeferencing. Reproject from the true source CRS.
- Repeated reprojection — each warp resamples again and accumulates blur. Reproject from the original source, not from a previously warped copy.
Quality control
Before the reprojected raster is trusted:
- Confirm output CRS, pixel size and NoData with
gdalinfo. - Compare min/max/mean statistics against the source; large shifts mean trouble.
- Overlay against a known-good reference layer and check alignment at corners and high relief, not just the centre.
- For DEMs, hillshade both and compare terrain features.
- Keep the source untouched so you can re-derive if a parameter was wrong.
Bathyl perspective
We treat the coordinate chain as part of the deliverable, not a hidden step. Every reprojected raster we ship records its source CRS, target CRS, resampling method and output resolution, so another analyst can judge whether the grid was preserved — and re-run it from the original if they disagree.
Related reading
- Datum Transformations for GIS Teams
- Why Buffers Are Wrong in Degrees
- Slope, Aspect, and Hillshade From DEM Data
- Reproducible GIS Pipelines
- GIS and spatial analysis