Transforms Module

The transforms module provides coordinate transformation functionality for converting between pixel, geodetic, and sensor coordinate systems.

Overview

VISTA supports various coordinate transformations needed for geospatial imagery analysis:

  • Pixel to geodetic coordinates (lat/lon)

  • Geodetic to pixel coordinates

  • Sensor to ground plane transformations

  • Altitude/Range/Frame (ARF) transformations

  • Polynomial-based transformations

These transformations are essential for working with imagery from calibrated sensors and for integrating VISTA with geospatial tools.

Module Reference

Transforms

General transform support functions

vista.transforms.transforms.spherical_to_cartesian(azimuth, elevation)[source]

Convert spherical angle(s) to Cartesian vector(s)

Parameters:
  • azimuth (Tuple[float, NDArray]) – Angle(s) in radians in the x-y plane

  • elevation (Tuple[float, NDArray]) – Angle(s) in radians coming off the x-y plane toward the z-axis

Returns:

Cartesian unit-vector(s) pointing in the direction of the given anglees

Return type:

NDArray

vista.transforms.transforms.cartesian_to_spherical(unit_vector)[source]

Convert Cartesian vector(s) to spherical angle(s)

Parameters:

unit_vector (NDArray) – Unit vector or vector (as array of column vectors)

Returns:

  • NDArray – Angle(s) in radians in the x-y plane

  • NDArray – Angle(s) in radians coming off the x-y plane toward the z-axis

Return type:

Tuple[ndarray[tuple[Any, …], dtype[_ScalarT]], ndarray[tuple[Any, …], dtype[_ScalarT]]]

Earth Intersection

vista.transforms.earth_intersection.los_to_earth(position, pointing)[source]

Find the intersection of a pointing vector with the Earth

Finds the intersection of a pointing vector u and starting point s with the WGS-84 geoid

Parameters:
  • position (NDArray) – Length 3 or (3 X N) array defining the starting point location(s) in kilometers

  • pointing (NDArray) – Length 3 or (3 X N) array defining the pointing vector(s) (must be a unit vector)

Returns:

  • NDArray – Distance(s) to the Earth’s surface

  • NDArray – Length 3 or (3 X N) array of point(s) of intersection with the Earth in kilometers. NaN’s represent non-intersection

Return type:

Tuple[ndarray[tuple[Any, …], dtype[_ScalarT]], ndarray[tuple[Any, …], dtype[_ScalarT]]]

ARF Transforms

Attitude Reference Frame support functions

vista.transforms.arf.get_arf_transform(sensor_pos, sensor_pointing)[source]

Create a matrix to transform vectors in a global reference frame into the Attitude Reference Frame (ARF)

Note

The purpose of the ARF and it’s definition are described and illustrated in detail in notebooks/attitude_reference_frame.ipynb

Parameters:
  • sensor_pos (NDArray) – Sensor position vector in global reference frame in kilometers

  • sensor_pointing (NDArray) – Sensor pointing unit-vector in global reference frame

Returns:

A matrix to transform vectors in the global reference frame into the ARF. Use this matrix like arf_vectors = transformation_matrix @ vectors.

Return type:

NDArray

Polynomial Transforms

vista.transforms.polynomials.fit_2d_polynomial(x, y, f, order)[source]

Fit a 2D polynomial to data using least squares.

Given arrays of x, y coordinates and corresponding function values f, finds the polynomial coefficients that minimize the squared error.

Parameters:
  • x (np.ndarray) – X coordinates of data points (1D array)

  • y (np.ndarray) – Y coordinates of data points (1D array)

  • f (np.ndarray) – Function values at each (x, y) point (1D array)

  • order (int) – Order of the polynomial to fit

Returns:

  • coeffs (np.ndarray) – Array of fitted polynomial coefficients, length (order+1)*(order+2)/2

  • residuals (float) – Sum of squared residuals

  • rank (int) – Rank of the design matrix

  • singular_values (np.ndarray) – Singular values of the design matrix

Raises:

ValueError – If input arrays have inconsistent shapes or if there are insufficient data points

Examples

>>> # Fit a linear function f(x,y) = 1 + 2*x + 3*y
>>> x = np.array([0, 1, 0, 1, 2])
>>> y = np.array([0, 0, 1, 1, 1])
>>> f = 1 + 2*x + 3*y
>>> coeffs, _, _, _ = fit_2d_polynomial(x, y, f, order=1)
>>> # coeffs should be approximately [1, 2, 3]
>>> # Fit with noisy data
>>> x = np.random.rand(100)
>>> y = np.random.rand(100)
>>> f_true = 1 + 2*x + 3*y + x*y
>>> f_noisy = f_true + 0.1 * np.random.randn(100)
>>> coeffs, residuals, _, _ = fit_2d_polynomial(x, y, f_noisy, order=2)

Notes

The polynomial terms follow the same ordering as evaluate_2d_polynomial: ordered by total degree, then by decreasing powers of x.

vista.transforms.polynomials.evaluate_2d_polynomial(coeffs, x, y, order=None)[source]

Evaluate a 2D polynomial of arbitrary order.

The polynomial terms are ordered by total degree, then by decreasing powers of x: - Order 0: c0 - Order 1: c1*x + c2*y - Order 2: c3*x^2 + c4*x*y + c5*y^2 - Order 3: c6*x^3 + c7*x^2*y + c8*x*y^2 + c9*y^3 - etc.

For a polynomial of order n, there are (n+1)*(n+2)/2 coefficients.

Parameters:
  • coeffs (np.ndarray) – Array of polynomial coefficients, length must be (n+1)*(n+2)/2 for some integer n

  • x (np.ndarray or float) – X coordinates (can be scalar or array)

  • y (np.ndarray or float) – Y coordinates (can be scalar or array)

  • order (int, optional) – Order of the polynomial. If None, inferred from length of coeffs.

Returns:

Evaluated polynomial values with same shape as input x and y

Return type:

np.ndarray or float

Raises:

ValueError – If the length of coeffs doesn’t correspond to a valid polynomial order

Examples

>>> # Evaluate f(x,y) = 1 + 2*x + 3*y (order 1)
>>> coeffs = np.array([1, 2, 3])
>>> evaluate_2d_polynomial(coeffs, 1.0, 2.0)
9.0
>>> # Evaluate f(x,y) = 1 + x + y + x^2 + xy + y^2 (order 2)
>>> coeffs = np.array([1, 1, 1, 1, 1, 1])
>>> evaluate_2d_polynomial(coeffs, 2.0, 3.0, order=2)
24.0

Basic Usage

Pixel ↔ Geodetic Conversion via Sensor

Pixel-to-geodetic and geodetic-to-pixel conversions are performed through the sensor object associated with the imagery, not through standalone functions in this module. See Custom Sensors for the full sensor API.

import numpy as np
from astropy.coordinates import EarthLocation
import astropy.units as u

# Convert pixel coordinates to geodetic (lat/lon/alt)
# frame can be a single int or an array of per-point frame numbers
location = sensor.pixel_to_geodetic(
    frame=0,
    rows=np.array([100.0, 200.0]),
    columns=np.array([300.0, 400.0]),
)
print(location.lat.deg, location.lon.deg)

# Convert geodetic coordinates to pixel
loc = EarthLocation(lat=40.7128 * u.deg, lon=-74.0060 * u.deg, height=0 * u.m)
rows, columns = sensor.geodetic_to_pixel(frame=0, loc=loc)

Low-Level Transforms

The vista.transforms module provides lower-level building blocks used internally by sensor geolocation pipelines:

from vista.transforms import (
    spherical_to_cartesian,
    cartesian_to_spherical,
    los_to_earth,
    get_arf_transform,
)

# Convert spherical angles to a Cartesian unit vector
vec = spherical_to_cartesian(azimuth=0.1, elevation=0.3)

# Find where a line-of-sight vector intersects the Earth (WGS-84)
distance, intersection = los_to_earth(position_ecef_km, pointing_unit_vec)