Fast and direct raster I/O for use with Numpy and SciPy
—
Affine transformations for converting between pixel and geographic coordinates. Supports creating transforms from bounds, origins, ground control points, and provides coordinate conversion utilities.
The core transformation class from the affine library, integrated into rasterio for geospatial coordinate transformations.
class Affine:
"""6-parameter affine transformation matrix."""
def __init__(self, a, b, c, d, e, f):
"""
Initialize affine transformation.
Parameters (coefficients for the transformation):
- a (float): x-scale factor
- b (float): x-shear factor
- c (float): x-translation
- d (float): y-shear factor
- e (float): y-scale factor
- f (float): y-translation
Transformation: x' = a*x + b*y + c, y' = d*x + e*y + f
"""
# Properties
a: float # x-scale
b: float # x-shear
c: float # x-translation
d: float # y-shear
e: float # y-scale
f: float # y-translation
@classmethod
def identity(cls):
"""Create identity transformation."""
@classmethod
def translation(cls, x, y):
"""Create translation transformation."""
@classmethod
def scale(cls, x, y=None):
"""Create scaling transformation."""
@classmethod
def rotation(cls, angle):
"""Create rotation transformation."""
def __mul__(self, other):
"""Compose with another transformation."""
def __invert__(self):
"""Get inverse transformation."""
def determinant(self):
"""Calculate transformation determinant."""
def is_identity(self):
"""Test if identity transformation."""
def is_conformal(self):
"""Test if conformal (preserves angles)."""
def is_orthonormal(self):
"""Test if orthonormal (preserves distances and angles)."""
def is_rectilinear(self):
"""Test if rectilinear (axes aligned)."""Utilities for creating affine transformations from various geographic parameters.
def from_bounds(west, south, east, north, width, height):
"""
Create transform from geographic bounds and raster dimensions.
Parameters:
- west (float): Left (minimum x) coordinate
- south (float): Bottom (minimum y) coordinate
- east (float): Right (maximum x) coordinate
- north (float): Top (maximum y) coordinate
- width (int): Raster width in pixels
- height (int): Raster height in pixels
Returns:
Affine: Transformation matrix
"""
def from_origin(west, north, xsize, ysize):
"""
Create transform from origin point and pixel sizes.
Parameters:
- west (float): Left (minimum x) coordinate
- north (float): Top (maximum y) coordinate
- xsize (float): Pixel width (x-direction)
- ysize (float): Pixel height (y-direction, usually negative)
Returns:
Affine: Transformation matrix
"""
def from_gcps(gcps):
"""
Create transform from ground control points.
Parameters:
- gcps (sequence): Ground control points as (row, col, x, y) tuples
Returns:
Affine: Transformation matrix
"""Usage examples:
from rasterio.transform import from_bounds, from_origin, Affine
# Create transform from bounds
transform = from_bounds(-180, -90, 180, 90, 360, 180)
print(transform) # Affine(1.0, 0.0, -180.0, 0.0, -1.0, 90.0)
# Create transform from origin and pixel size
transform = from_origin(-180, 90, 1.0, -1.0) # 1-degree pixels
# Create transform from ground control points
gcps = [
(0, 0, -180, 90), # top-left
(0, 360, 180, 90), # top-right
(180, 0, -180, -90), # bottom-left
(180, 360, 180, -90) # bottom-right
]
transform = from_gcps(gcps)
# Manual transform creation
transform = Affine(1.0, 0.0, -180.0, # x-scale, x-shear, x-offset
0.0, -1.0, 90.0) # y-shear, y-scale, y-offsetFunctions for converting between pixel and geographic coordinate systems.
def xy(transform, rows, cols, offset='center'):
"""
Convert pixel coordinates to geographic coordinates.
Parameters:
- transform (Affine): Geospatial transformation
- rows (array-like): Row coordinates (y-axis, 0-based)
- cols (array-like): Column coordinates (x-axis, 0-based)
- offset (str): Pixel offset ('center', 'ul', 'ur', 'll', 'lr')
Returns:
tuple: (x_coords, y_coords) in geographic space
"""
def rowcol(transform, xs, ys, op=math.floor, precision=None):
"""
Convert geographic coordinates to pixel coordinates.
Parameters:
- transform (Affine): Geospatial transformation
- xs (array-like): X coordinates in geographic space
- ys (array-like): Y coordinates in geographic space
- op (callable): Rounding operation (math.floor, math.ceil, round)
- precision (int): Decimal places for rounding
Returns:
tuple: (rows, cols) in pixel space
"""Usage examples:
import rasterio
from rasterio.transform import xy, rowcol
import numpy as np
# Load dataset with transform
with rasterio.open('example.tif') as dataset:
transform = dataset.transform
# Convert pixel coordinates to geographic
rows, cols = np.array([100, 200]), np.array([150, 250])
x_coords, y_coords = xy(transform, rows, cols)
print(f"Geographic coords: {list(zip(x_coords, y_coords))}")
# Convert geographic coordinates to pixels
x_geo, y_geo = [-120.5, -119.8], [45.2, 44.9]
pixel_rows, pixel_cols = rowcol(transform, x_geo, y_geo)
print(f"Pixel coords: {list(zip(pixel_rows, pixel_cols))}")
# Different pixel offset options
x_center, y_center = xy(transform, [100], [150], offset='center')
x_corner, y_corner = xy(transform, [100], [150], offset='ul') # upper-leftUtilities for calculating bounds and working with transformed arrays.
def array_bounds(height, width, transform):
"""
Calculate geographic bounds of raster array.
Parameters:
- height (int): Array height in pixels
- width (int): Array width in pixels
- transform (Affine): Geospatial transformation
Returns:
BoundingBox: Geographic bounds (west, south, east, north)
"""
def guard_transform(transform):
"""
Validate transformation matrix.
Parameters:
- transform (Affine): Transformation to validate
Returns:
Affine: Validated transformation
Raises:
TransformError: If transform is invalid
"""Usage examples:
from rasterio.transform import array_bounds, guard_transform
# Calculate bounds from array dimensions
height, width = 1000, 2000
transform = from_bounds(-180, -90, 180, 90, width, height)
bounds = array_bounds(height, width, transform)
print(f"Bounds: {bounds}") # BoundingBox(left=-180, bottom=-90, right=180, top=90)
# Validate transformation
try:
valid_transform = guard_transform(transform)
except TransformError as e:
print(f"Invalid transform: {e}")Advanced transformation operations for specific use cases.
def tasseledcap(array, coeffs):
"""
Apply Tasseled Cap transformation to multispectral data.
Parameters:
- array (numpy.ndarray): Input multispectral array
- coeffs (numpy.ndarray): Transformation coefficients
Returns:
numpy.ndarray: Transformed array
"""Usage example:
# Landsat Tasseled Cap transformation
landsat_coeffs = np.array([
[0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863], # Brightness
[-0.2848, -0.2435, -0.5436, 0.7243, 0.0840, -0.1800], # Greenness
[0.1509, 0.1973, 0.3279, 0.3406, -0.7112, -0.4572] # Wetness
])
# Apply transformation to 6-band Landsat data
transformed = tasseledcap(landsat_bands, landsat_coeffs)Transformation operations can raise specific exceptions for invalid matrices or operations:
class TransformError(RasterioError):
"""Transformation related errors."""Common error scenarios:
from rasterio.errors import TransformError
try:
# Invalid transformation matrix (zero determinant)
invalid_transform = Affine(0, 0, 0, 0, 0, 0)
guard_transform(invalid_transform)
except TransformError as e:
print(f"Invalid transform: {e}")
# Check transform validity
if transform.determinant() == 0:
raise TransformError("Singular transformation matrix")Install with Tessl CLI
npx tessl i tessl/pypi-rasterio