How to replace pixel values in a single band DEM?
You can do something similar using gdal_calc.py
, e.g.:
gdal_calc.py -A dtm.tif --calc='((A>=100)*(A<=200))*A+((A<100)*0)+((A>200)*0)' --outfile=dtm_reclass.tif --NoDataValue=-32767
This calc expression would:
- Assign a value of 0 to all pixel values less than 100
((A<100)*0)
- Assign a value of 0 to all pixel values greater than 200
((A>200)*0)
- Keep existing pixel values greater than or equal to 100 and less than or equal to 200
((A>=100)*(A<=200))*A
I'm not sure if you can do this with any of the gdal cli tools, but I wrote something in python which accomplishes it:
from osgeo import gdal
from osgeo.gdalconst import GDT_Float32
import sys
import numpy as np
def fix_dem_nodata(raster_input, raster_output, nodata=0, threshold=-900):
try:
in_data, out_data = None, None
# open input raster
in_data = gdal.Open(raster_input)
if in_data is None:
print 'Unable to open %s' % raster_input
return None
# read in data from first band of input raster
band1 = in_data.GetRasterBand(1)
rows = in_data.RasterYSize
cols = in_data.RasterXSize
vals = band1.ReadAsArray(0, 0, cols, rows)
# create single-band float32 output raster
driver = in_data.GetDriver()
out_data = driver.Create(raster_output, cols, rows, 1, GDT_Float32)
if out_data is None:
print 'Could not create output file %s' % raster_output
return None
# set values below nodata threshold to nodata
dem_data = np.array(vals)
dem_data[dem_data < threshold] = nodata
# write the data to output file
out_band = out_data.GetRasterBand(1)
out_band.WriteArray(dem_data, 0, 0)
# flush data to disk, set the NoData value and calculate stats
out_band.FlushCache()
out_band.SetNoDataValue(nodata)
# georeference the image and set the projection
out_data.SetGeoTransform(in_data.GetGeoTransform())
out_data.SetProjection(in_data.GetProjection())
return raster_output
except Exception as e:
print "Failure to set nodata values on %s: %s" % raster_input, repr(e)
return None
finally:
del in_data
del out_data
if __name__ == "__main__":
infile = sys.argv[1]
outfile = sys.argv[2]
print fix_dem_nodata(infile, outfile)
I set the threshold to -900 as it seemed a reasonable limit for realistic dems, but you can tune for your dataset. N.b. you may want to use a value other than 0 for your nodata, as 0 is a realistic elevation.