Keeping the pixels aligned with the original raster's is kind of outside the scope of why gdalwarp
exists. It would seem that is more in the territory of gdal_translate
, but gdal_translate
doesn't have an option to clip to a cutline. Regardless, if you can calculate the optimal bounds of the image ahead of time or in this script (aligned to pixel dimensions of course), then these can be passed in to gdalwarp
's te
option. te
specifies the target extent.
import osr
import ogr
import gdal
import subprocess
inraster = 'C:/Users/claudio/workspace/test/inraster.tif'
inshape = 'C:/Users/claudio/workspace/test/country.shp'
# open raster and get its georeferencing information
dsr = gdal.Open(inraster, gdal.GA_ReadOnly)
gt = dsr.GetGeoTransform()
srr = osr.SpatialReference()
srr.ImportFromWkt(dsr.GetProjection())
# open vector data and get its spatial ref
dsv = ogr.Open(inshape)
lyr = dsv.GetLayer(0)
srv = lyr.GetSpatialRef()
# make object that can transorm coordinates
ctrans = osr.CoordinateTransformation(srv, srr)
lyr.ResetReading()
ft = lyr.GetNextFeature()
while ft:
# read the geometry and transform it into the raster's SRS
geom = ft.GetGeometryRef()
geom.Transform(ctrans)
# get bounding box for the transformed feature
minx, maxx, miny, maxy = geom.GetEnvelope()
# compute the pixel-aligned bounding box (larger than the feature's bbox)
left = minx - (minx - gt[0]) % gt[1]
right = maxx + (gt[1] - ((maxx - gt[0]) % gt[1]))
bottom = miny + (gt[5] - ((miny - gt[3]) % gt[5]))
top = maxy - (maxy - gt[3]) % gt[5]
country_name = ft.GetFieldAsString('admin')
outraster = inraster.replace('.tif', '_%s.tif' % country_name.replace(' ', '_'))
subprocess.call([
'gdalwarp', inraster, outraster,
'-cutline', inshape, '-cwhere', "'admin'='%s'" % country_name,
# target resolution
'-tr', str(abs(gt[1])), str(abs(gt[5])),
# target extent
'-te', str(left), str(bottom), str(right), str(top)
])
ft = lyr.GetNextFeature()
ds = None