Search code examples
pythongeospatialgdal

Converting a 16bit GeoTiff file as an 8bit JPEG file using python


I am trying to convert a 16 bit 3-band RGB GeoTIFF file into an 8 bit 3-band JPEG file. It seems like the gdal library should work well for this. My question is how do I specify the conversion to 8-bit output in the python gdal API, and how do I scale the values in that conversion? Also, how do I check to tell whether the output is 8-bit or 16-bit?

The gdal.Translate() function should serve the purpose. However, the only example that I found which will rescale the values to 8 bit involves the C interface. The two posts below provide examples of this, but again they do not suit my purpose because they are not using the Python interface.

https://gis.stackexchange.com/questions/26249/how-to-convert-qgis-generated-tiff-images-into-jpg-jpeg-using-gdal-command-line/26252

https://gis.stackexchange.com/questions/206537/geotiff-to-16-bit-tiff-png-or-bmp-image-for-heightmap/206786

The python code that I came up with is:

from osgeo import gdal
gdal.Translate(destName='test.jpg', srcDS='test.tif')

This will work, but I don't think the output is coverted to 8-bit or that the values are rescaled. Does anyone know how to apply those specific settings?

Note that this post below is very similar, but uses the PIL package. However the problem is that apparently PIL has trouble ingesting 16 bit images. When I tried this code I got errors about reading the data. Hence, I could not use this solution.

converting tiff to jpeg in python


Solution

  • You could use options like this

    from osgeo import gdal
    
    scale = '-scale min_val max_val'
    options_list = [
        '-ot Byte',
        '-of JPEG',
        scale
    ] 
    options_string = " ".join(options_list)
    
    gdal.Translate('test.jpg',
                   'test.tif',
                   options=options_string)
    

    Choose the min and max values you find suitable for your image as min_val and max_val

    If you like to expand scaling to the entire range, you can simply skip min and max value and just use scale = '-scale'