Extract and manipulate raster color tables with GDAL
While working on a project to process and upload raster data to GeoServer, several challenges occurred. One task was to manipulate the color table of raster files for own usage.
Geospatial Data Abstraction Library (GDAL)
GDAL offers a convenient utility to change the look of raster files using color tables. The utility gdaldem color-relief is normally used to colorize a height ramp of a digital elevation model, but can also be used to generally change the appearance of the raster files:
1 |
gdaldem color-relief inputfile color_table.txt outputfile |
To manipulate an already existing color table, we first needed to extract this information. The command gdalinfo can be used in Bash to show the metadata of a raster file, but it is not possible to extract the color table in a convenient way.
GDAL Python utilities
With the GDAL Python utilities one can however use a series of functions to extract this information and save it to a text-file. GetRasterBand(1) retrieves the information of the first band and band.GetRasterColorTable() extracts for you the color table saved along with it. The first band of the raster files be for example of the type Palette and owns an 8-bit color table with 8*8=256 different entries. The function GetColorEnrty() then can read each of the 256 RGB-codes. So we just need to create a new text file and copy the entry-number (i) and the corresponding R-, G-, B-code (sEntry) from it:
1 2 3 4 5 6 7 8 9 10 11 |
fn = gdal.Open(filename) band = fn.GetRasterBand(1) ct = band.GetRasterColorTable() f = open("rgb_color.txt", 'w+') for i in range(ct.GetCount()): sEntry = ct.GetColorEntry(i) f.write( " %3d: %d,%d,%d\n" % ( \ i, \ sEntry[0],\ sEntry[1],\ sEntry[2])) |
color table
This text-file which has been created above contains 256 RGB-entries and looks as follows for our example:
1 2 3 4 5 6 7 |
0: 255,255,255 1: 153,255,179 2: 230,255,204 3: 191,242,128 4: 230,230,204 […] 255: 255,255,255 |
The sed tool
The program sed is a useful tool in Bash to change the color table. With it one can manipulate strings and also text files. To manipulate the colors in the raster file you have to write down the string you want to replace; here as a comma separated RGB-code. A colon “:” is used in this example to distinguish it from the new code. So if you just want to change the color white to black, write down 255,255,255:000,000,000 like in the example below:
1 |
sed -i -e "s:255,255,255:000,000,000:g" rgb_color.txt |
If you want to change more than one color, a for loop would be suitable. Just write down the colors you want to change and save them in a variable, here called rgb_list and use the for to replace the colors with your desired ones:
1 2 3 4 |
rgb_list="191,242,128:034,139,034 255,153,179:255,000,000" for i in ${rgb_list}; do sed -i -e "s:${i}:g" rgb_color.txt done |
gdaldem
In a final step, we use gdaldem to manipulate the raster file with the help of our newly created rgb_color.txt and save it as a virtual dataset or as a GeoTiff:
1 |
gdaldem color-relief -of VRT input.tif rgb_color.txt rgb_output.vrt |
Example using a digital topographic map
The maps show the border region between Germany and Austria near Salzburg. The original digital topographic map (DTK100) is shown on the left side. On the right hand-side, you can see the newly created map. Forests are shown with a darker green (034,139,034) instead of a light one (191.242,128). Urban areas are symbolized with the color red (255,000,000) instead of pink (255,153,179).
The script can be found on GitHub and is available for public usage.
I’m approaching naw in the script and I’m trying to select many multi-band files from a folder and extract a single band from the file, putting everything in an output folder with the single-band transformed files.
Currently I concluded the following script:
rlayer=”C:/…./file.ecw”
rout=”C:/…./folder”
import glob, os
from osgeo import gdal
driver = gdal.GetDriverByName(“rlayer”)
tDs =gdal.Translate()
ds_in = gdal.Open(“.ecw”)
array = ds_in.GetRasterBand(3).ReadAsArray()
band = tDs.GetRasterBand(1)
band.WriteArray(array)
band.FlushCache()
I do not understand where it’s wrong