Hillshaded Color Relief Map Using Drone Images

This document walks you how to create a hillshaded, color relief map that shows elevation and feature details of your land using drone captured images. This builds on the drone map doc and assumes you've already captured the requisite images.

Generate DSM

The first step is to generate the Digital Surface Model using OpenDroneMap. We can do this with the same tool we used to stitch the orthomosaic, we just need to tweak the parameters slightly by adding the --dsm flag. You can also add the --dtm flag to create a Digital Terrain Model. The DSM shows all features while the DTM attempts to remove buildings and other objects. I prefer the look of the DSM.

As a reminder, we've set SCRATCH_DIR to the working directory containing our images/ folder.

docker run -ti --rm -v $SCRATCH_DIR:/datasets/code opendronemap/odm \
  --project-path /datasets --max-concurrency $CONCURRENCY --dsm

You'll find the results in SCRATCH_DIR/odem_dem once the command has finished. If you open dsm.tif you'll notice it doesn't look like much, it's all white. That's because the file encodes elevation data and not color.

The tool gdalinfo is useful for working with GeoTIFF files and I've used it when debugging GIS workflows. We can use it to inspect a file with the following command.

docker run -ti --rm -v $SCRATCH_DIR:/datasets/code ghcr.io/osgeo/gdal:alpine-normal-latest \
  gdalinfo /datasets/code/odm_dem/dsm.tif

At the end of the result you'll see information about the photo bands.

Band 1 Block=512x512 Type=Float32, ColorInterp=Gray
  Min=269.860 Max=316.080 
  Minimum=269.860, Maximum=316.080, Mean=292.287, StdDev=7.192
  NoData Value=-9999

The DSM file has only a single band that represents elevation. The min/max are the range of the photo elevation in meters. Keep this in mind as this may come in handy while styling the color relief map.

Create Hillshade Map

The first step is to create the texture map using the GDAL's hillshade tool. There are a lot options for rendering the hillshade map, such as exaggerating the height and changing the light source, but I find the defaults work well.

Let's create a temporary directory and then use gdaldem to create the hillshade map.

mkdir $SCRATCH_DIR/tmp
docker run -ti --rm -v $SCRATCH_DIR:/datasets/code ghcr.io/osgeo/gdal:alpine-normal-latest \
  gdaldem hillshade /datasets/code/odm_dem/dsm.tif /datasets/code/tmp/hillshade.tif

Create Color Relief Map

Next we'll create the color relief map. While the defaults work well for hillshading, for color relief we are forced to make some creative choices. The tool requires a color gradient for the relief map. This gradient is defined in a file with the following format.


Where E is the elevation, either absolute or as a percentage of the map's elevation range, and RGB are the color values (in the range of 0-255). You can use an online tool like colorbrewer2 or viridis palette generator to create a sensible color gradient for you, or you if you're feeling artistic you can create your own. I think the six color spectral gradient is a good default.

0% 50 136 189
20% 153 213 148
40% 230 245 152
60% 254 224 139
80% 252 141 89
100% 213 62 79

Or if you are using absolute elevation (informed by the numbers from gdalinfo above) you would make a file like this.

285 50 136 189
290 153 213 148
295 230 245 152
300 254 224 139
305 252 141 89
310 213 62 79

Once you've selected your pallette write the color gradient to a file and then create the color relief map.

echo "0% 50 136 189
20% 153 213 148
40% 230 245 152
60% 254 224 139
80% 252 141 89
100% 213 62 79" > $SCRATCH_DIR/colors.txt

docker run -ti --rm -v $SCRATCH_DIR:/datasets/code ghcr.io/osgeo/gdal:alpine-normal-latest \
  gdaldem color-relief /datasets/code/odm_dem/dsm.tif /datasets/code/colors.txt /datasets/code/tmp/relief.tif

Combine Hillshade and Color Relief

Finally you'll want to combine the two images into a single result. This command scales the color relief pixels by the corresponding pixel in the hillshade map.

docker run -ti --rm -v $SCRATCH_DIR:/datasets/code ghcr.io/osgeo/gdal:alpine-normal-latest \
  gdal_calc.py -A /datasets/code/tmp/hillshade.tif --A_band 1 \
  -B /datasets/code/tmp/relief.tif  --B_band 1 \
  -C /datasets/code/tmp/relief.tif  --C_band 2 \
  -D /datasets/code/tmp/relief.tif  --D_band 3 \
  --outfile=/datasets/code/hillshade_relief.tif \
  --calc="B*(A/255)" --calc="C*(A/255)" --calc="D*(A/255)"

This command runs per-pixel math on the two images to create the final result. You have to import each band individually. The hillscale map is greyscale but the color relief map is RGB so you'll have to import each of its three bands separately.

The result usually looks decent with these default settings, but I recommend playing around with the gradient to find one that suits your property. In our case the Montanoso color scheme was chosen to match the website and also roughly match the terrain and vegetation of the actual property.