gdal – Replacing NoData Values by a Constant Using GDAL CLI Tools

gdalnodata

I have a raster DEM file containing 1 band: f='DEM.tif'
It has some NODATA values which I want to replace by a true, actual constant value (i.e. no more nodata stuff), let's say, zero.

Here are all the things I've tested:

  1. gdal_translate; not working:
gdal_translate -of GTiff -a_nodata 0 ${f} ${f%.*}_cleaned.tif

well… it actually replaces the nodata value of 3.399999^38 to a nodata value of 0, but it doesn't replace it by a true 0 (which would be an actual zero value, no a nodata value).

  1. I also tried the accepted answer here using gdalbuildvrt: Redefining nodata value into zero in QGIS? but with no success. Nodata values still show as … well, nodata values.

  2. Also, there is the gdal_fillnodata tool, which seemed promising: https://gdal.org/programs/gdal_fillnodata.html but it actually interpolates values from the closest borders, which doesn't make sense in my case.

  3. Finally, gdalwarp was my last candidate, but it is not working better:

gdalwarp -srcnodata 3.39999995214436425e+38 -dstnodata 0 ${f} ${f%.*}_cleaned.tif

because, here again, it replaces the nodata value by another nodata value, which is not what I would like to achieve.

I've done that successfully in no time with QGIS using the "Fill NoData cells" on my local machine as a test, but I must work on my full dataset on a headless server, without QGIS installed.

So, do you know how to fill nodata values by a constant using any of the GDAL CLI (bash) based tools? I hope I simply missed something obvious…

Edits

  1. Removed as it was a malformed version of @user2856's working answer.

  2. I forgot to mention this when I wrote the post, but I also tried @Mike T's first part of his answer:

gdal_edit.py -unsetnodata ${f}

(Disclaimer: this is a non reversible operation as it's actually working 'inplace', so backup your raster before running this command!)

Here, on the contrary, gdalinfo doesn't report NoData anymore. But do not rejoice too quickly, as a loading into QGIS shows:

QGIS indentify results

The second part of Mike T's answer:

gdal_calc.py -A ${f}.tif --outfile=result.tif --calc="numpy.where(A>=3e34, 0, A)"

is actually giving a result.tif raster with:

gdalinfo result.tif | grep No
  NoData Value=3.40282346600000016e+38

That's funny? Probably some weird numerical issue under the hood.
But the most funny part is that if I first run gdal_edit.py -unsetnodata
and then the latter gdal_calc.py command, the resulting raster has so nodata again (heck, where do these actually come from?)!


General info on my setup just in case:

# gdalinfo --version
GDAL 3.3.0dev-33cf0e31a992be112b3091f012368d15605ed51d, released 2021/03/17

from osgeo/gdal:ubuntu-small-latest Docker image available at https://hub.docker.com/r/osgeo/gdal

Best Answer

One (slightly hacky) way of doing it is to use an intermediate VRT with the gdalbuildvrt command and specifying a new NoData value with the srcnodata and vrtnodata arguments. This does actually change the underlying values.

First, get your actual nodata value from gdalinfo:

$ gdalinfo input.tif | grep No
NoData Value=3.39999995214436425e+38

Assign it to a bash variable: na=3.39999995214436425e+38

Or if you have jq installed (in ubuntu/debian based Linux distros sudo apt install jq):

na=$(gdalinfo input.tif -json | jq '.bands[0].noDataValue')

And use it in the following examples:

gdalbuildvrt -srcnodata ${na} -vrtnodata 0 output.vrt input.tif

However, it also sets those values to NoData in the output, so you need to specify a different value to be considered as NoData when converting to your final GeoTIFF.

gdal_translate -a_nodata ${na} output.vrt output.tif  # original 3.39999995214436425e+38 values from input.tif are now 0

Chaining it together with a pipe so you don't need to clean up any intermediate VRT files:

gdalbuildvrt -srcnodata ${na} -vrtnodata 0 /vsistdout/ input.tif | gdal_translate -a_nodata -9999 /vsistdin/ output.tif