Python GDAL – How to Trim NoData Values in TIFF Using Python and GDAL

gdalpython

There is a TIFF file, 3 channel. RGB channels contain a frame, with a value of 0.

File

I have set nodata values for all channels, now I need to crop the snapshot to remove these nodata. How to completely remove nodata values from a tiff?
The original size is 10534 x 7034. The frame is 25 pixels.

python code for writing nodata to a file:

from osgeo import gdal
from osgeo.gdalconst import GDT_Float32, GDT_Byte
import sys
import numpy as np

path = r"C:\Test\file.tif"
path_output = r"C:\Test\file_res.tif"

def fix_dem_nodata(raster_input, raster_output, nodata=0, threshold=0):
    try:
        in_data, out_data = None, None
        
        in_data = gdal.Open(raster_input)
        if in_data is None:
            print('Unable to open %s' % raster_input)
            return None
        
        print('Raster bands count: %s' % in_data.RasterCount)
        
        file_data = list()
        
        for i in range(1, in_data.RasterCount+1):
            file_data.append(in_data.GetRasterBand(i))
            
        raster_datatype = gdal.GetDataTypeName(file_data[1].DataType)
        if raster_datatype == 'Byte':
            raster_datatype = GDT_Byte
        
        print('File band type: %s' % raster_datatype)
        
        driver = in_data.GetDriver()
        
        print('File driver: %s' % driver)
        
        rows = in_data.RasterYSize
        cols = in_data.RasterXSize
        
        geo_transfrom = in_data.GetGeoTransform()
        geo_projection = in_data.GetProjection()
        
        print('File geo transfrom: %s' % repr(geo_transfrom))
        
        print('File geo projection: %s' % repr(geo_projection))
        
        out_data = driver.Create(raster_output, cols, rows, in_data.RasterCount, raster_datatype)
        if out_data is None:
            print ('Could not create output file %s' % raster_output)
            return None
        
        for i in range(0, len(file_data)):
            dem_data = np.array(file_data[i].ReadAsArray(0, 0, cols, rows))
            dem_data[dem_data < threshold] = nodata
            
            out_band = out_data.GetRasterBand(i+1)
            out_band.WriteArray(dem_data, 0, 0)
            
            out_band.FlushCache()
            out_band.SetNoDataValue(nodata)
            
            print(i)
            
        out_data.SetGeoTransform(geo_transfrom)
        out_data.SetProjection(geo_projection)
        
        return raster_output
        
    except Exception as e:
        print("Error: %s" % repr(e))
        return None
    finally:
        del in_data
        del out_data

fix_dem_nodata(path, path_output)

Update

Test file

Best Answer

If the aim is to trim away 25 pixels from all sides, I would do it with gdal_translate, either the binary or Python library version.

https://gdal.org/programs/gdal_translate.html#cmdoption-gdal_translate-srcwin

-srcwin <xoff> <yoff> <xsize> <ysize>

Selects a subwindow from the source image for copying based on pixel/line location.

With a 10534 x 7034 sized image the offsets would be 25 and 25, width (10534-50)=10484, and height (7034-50)=6984.

gdal_translate -srcwin 25 25 10484 6984 input.tif trimmed_output.tif

With Python it would be like

ds = gdal.Open("input tif")
ds = gdal.Translate("trimmed_output.tif", ds, srcWin=[25, 25, 10484, 6984])