2

I have a GeoTIFF file of cropped agricultural plots that I am trying to rotate so that they are perpendicular to the image edges. The source image looks like this:

Unrotated image

However, when I rotate the image using the Affine functions, the dimensions of the source image are retained, thereby cutting off part of the image as shown:

rotated image

I have been unable to find a solution that adjusts the dimensions of the output image so that parts are not cut off. Is there a method for resolving this?

My code used is as follows:

import rasterio
from rasterio.plot import show
import rasterio.warp
from affine import Affine
from pprint import pprint
from rasterio.warp import calculate_default_transform, reproject, Resampling

# Takes GeoTIFF file and outputs center pixels
def get_center_pixel(img):
    height, width = img.height, img.width
    x_mid_pixel = width // 2
    y_mid_pixel = height // 2
    return x_mid_pixel, y_mid_pixel

raster = "clip.tif"
angle = 65
scale = 1

with rasterio.open(raster) as src:
    assert src.crs == 'EPSG:32617', 'Raster must have CRS=EPSG:4326'
    pivot = get_center_pixel(src)
    show(src)

    dst_transform = src.transform * Affine.rotation(angle, pivot) * Affine.scale(1)
    dst_meta = src.meta
    dst_meta['transform'] = dst_transform

    with rasterio.open("rotate.tif", 'w', **dst_meta) as dst:
        for i in range(1, src.count + 1):
            reproject(
                source=rasterio.band(src,i),
                destination=rasterio.band(dst, i),
                src_transform=src.transform,
                src_crs=src.crs,
                dst_transform=dst_transform,
                dst_crs=src.crs,
                resampling=Resampling.nearest
            )

1 Answer 1

1

The issue was that the dst image file was maintaining the same resolution. However, if the resolution of the output file is changed, an Affine.translation must be added to re-center the source image onto the new dimensions. Additionally, I added code to calculate the optimal dimensions of the output file based on the dimensions. The new script results in a rotated image that maintains its projection:

rotated image

import rasterio
from rotate import get_center_pixel
from affine import Affine
from rasterio.warp import reproject, Resampling
import numpy as np

# Set the file path for the input and output GeoTIFF files
raster = r"raster path"
angle = -88

with rasterio.open(raster) as src:
    pivot = get_center_pixel(src)

    rows, cols = src.shape

    # Calculate the dimensions of the output raster based on the rotated dimensions of the input raster
    cos_theta = abs(np.cos(np.radians(angle)))
    sin_theta = abs(np.sin(np.radians(angle)))
    new_rows = int(cols * sin_theta + rows * cos_theta)
    new_cols = int(rows * sin_theta + cols * cos_theta)


    dst_transform = src.transform * Affine.rotation(angle, pivot=pivot) * Affine.scale(1) * Affine.translation(pivot[0] - new_cols//2,pivot[1] - new_rows // 2)

    kwargs = src.meta.copy()
    # kwargs['transform'] = dst_transform
    kwargs.update({
        'width': new_cols,
        'height': new_rows,
        'transform': dst_transform
    })

    with rasterio.open("output.tif", 'w', **kwargs) as dst:
        for i in range(1, src.count + 1):
            reproject(
                source=rasterio.band(src, i),
                destination=rasterio.band(dst, i),
                src_transform=src.transform,
                src_crs=src.crs,
                dst_transform=dst_transform,
                dst_crs=src.crs,
                resampling=Resampling.bilinear)
1
  • Interesting dataset, must be fun working with this info
    – aldo_tapia
    Mar 30 at 11:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.