Sensors Module¶
The sensors module provides classes for representing sensor metadata and calibration data.
Overview¶
Sensor information is crucial for:
Coordinate transformations
Radiometric calibration
Geometric corrections
Geolocation accuracy
VISTA supports both continuous sensor models and sampled sensor data.
Core Classes¶
Base class for sensor position, line-of-sight, geodetic conversion, and radiometric modeling |
|
Sensor implementation using sampled position data with interpolation/extrapolation. |
Module Reference¶
Sensor¶
Base sensor class for position, line-of-sight, geodetic conversion, and radiometric modeling.
This module defines the Sensor base class which provides a framework for representing sensor platforms and their characteristics. Sensors support position queries, geodetic coordinate conversion, radiometric calibration data (bias, gain, bad pixels), and optional point spread function modeling.
- class vista.sensors.sensor.Sensor(name, bias_images=None, bias_image_frames=None, uniformity_gain_images=None, uniformity_gain_image_frames=None, bad_pixel_masks=None, bad_pixel_mask_frames=None, _instance_count=0)[source]¶
Bases:
objectBase class for sensor position, line-of-sight, geodetic conversion, and radiometric modeling
The Sensor class provides a framework for representing sensor platforms and their associated characteristics including projection polynomials and radiometric calibration data.
- bias_images¶
3D array of bias/dark frames with shape (num_bias_images, height, width).
- Type:
NDArray, optional
- bias_image_frames¶
1D array specifying frame ranges for each bias image.
- Type:
NDArray, optional
- uniformity_gain_images¶
3D array of flat-field/gain correction images.
- Type:
NDArray, optional
- uniformity_gain_image_frames¶
1D array specifying frame ranges for each uniformity gain image.
- Type:
NDArray, optional
- bad_pixel_masks¶
3D array of bad pixel masks.
- Type:
NDArray, optional
- bad_pixel_mask_frames¶
1D array specifying frame ranges for each bad pixel mask.
- Type:
NDArray, optional
Notes
All positions are in Earth-Centered Earth-Fixed (ECEF) Cartesian coordinates
Position units are kilometers
Positions are represented as (3, N) arrays with x, y, z in each column
PSF modeling is optional and can be used for fitting signal blobs to estimate irradiance
Sensor names must be unique within a VISTA session
Class variable _instance_count tracks the total number of Sensor instances created
Examples
>>> # Subclass can implement get_positions >>> class MySensor(Sensor): ... def get_positions(self, times): ... # Return sensor positions for given times ... return np.array([[x1, x2], [y1, y2], [z1, z2]])
- __post_init__()[source]¶
Initialize sensor instance and increment global counter.
Generates a unique UUID for this sensor instance and initializes internal data structures for tracking associated imagery.
- get_imagery_frames_and_times()[source]¶
Get all unique imagery frames and corresponding times in increasing order.
- Returns:
frames (NDArray[np.int_]) – Sorted array of unique frame numbers
times (NDArray[np.datetime64]) – Sorted array of corresponding timestamps
- Return type:
Tuple[ndarray[tuple[Any, …], dtype[_ScalarT]], ndarray[tuple[Any, …], dtype[_ScalarT]]]
Notes
This method aggregates frames and times from all imagery objects that have been registered with this sensor via add_imagery().
- add_imagery(imagery)[source]¶
Register imagery with this sensor and update frame/time tracking.
Adds the imagery’s frames and times to the sensor’s internal registry for coordinate conversion and time-to-frame mapping. Duplicate imagery (by UUID) or imagery without times is ignored.
- Parameters:
imagery (Imagery) – Imagery object to register with this sensor
Notes
Only imagery with non-None times are tracked
Duplicate frame/time pairs are automatically removed
This method is typically called automatically when Imagery is created
- get_positions(times)[source]¶
Return sensor positions in Cartesian ECEF coordinates for given times.
- Parameters:
times (NDArray[np.datetime64]) – Array of times for which to retrieve sensor positions
- Returns:
Sensor positions as (3, N) array where N is the number of times. Each column contains [x, y, z] coordinates in ECEF frame (km).
- Return type:
NDArray[np.float64]
Notes
The default implementation returns None. Subclasses should override this method
- model_psf(sigma=None, size=None)[source]¶
Model the sensor’s point spread function (PSF).
This is an optional method that can be overridden by subclasses to provide PSF modeling capability. The PSF can be used to fit signal pixel blobs in imagery to estimate irradiance.
- Parameters:
- Returns:
2D array representing the point spread function, or None if not implemented
- Return type:
NDArray[np.float64] or None
Notes
The default implementation returns None. Subclasses should override this method to provide specific PSF models (e.g., Gaussian, Airy disk, etc.).
- can_geolocate()[source]¶
Check if sensor can convert pixels to geodetic coordiantes and vice versa.
Notes
The default implementation returns False. Subclasses can override this method.
- Returns:
True if sensor has both forward and reverse geolocation polynomials.
- Return type:
- can_correct_bad_pixel()[source]¶
Check if sensor has radiometric bad pixel masks.
- Returns:
True if sensor has radiometric bad pixel masks.
- Return type:
- can_correct_bias()[source]¶
Check if sensor has bias images
- Returns:
True if sensor has bias images.
- Return type:
- can_correct_non_uniformity()[source]¶
Check if sensor has uniformity gain images
- Returns:
True if sensor has uniformity gain images.
- Return type:
- geodetic_to_pixel(frame, loc)[source]¶
Convert geodetic coordinates to pixel coordinates using polynomial coefficients.
- Parameters:
frame (int) – Frame number for which to perform the conversion
loc (EarthLocation) – Astropy EarthLocation object(s) containing geodetic coordinates
- Returns:
rows (np.ndarray) – Array of row pixel coordinates (NaN for base implementation)
columns (np.ndarray) – Array of column pixel coordinates (NaN for base implementation)
- Return type:
Notes
The default implementation returns NaN arrays. Subclasses should override this method to provide geodetic-to-pixel conversion using their specific projection model (e.g., polynomial coefficients).
- pixel_to_geodetic(frame, rows, columns)[source]¶
Convert pixel coordinates to geodetic coordinates using polynomial coefficients.
- Parameters:
frame (int) – Frame number for which to perform the conversion
rows (np.ndarray) – Array of row pixel coordinates
columns (np.ndarray) – Array of column pixel coordinates
- Returns:
Astropy EarthLocation object(s) with geodetic coordinates (zeros for base implementation)
- Return type:
EarthLocation
Notes
The default implementation returns EarthLocation with zero coordinates. Subclasses should override this method to provide pixel-to-geodetic conversion using their specific projection model.
- to_hdf5(group)[source]¶
Save sensor radiometric calibration data to an HDF5 group.
- Parameters:
group (h5py.Group) – HDF5 group to write sensor data to (typically sensors/<sensor_uuid>/)
Notes
This method writes radiometric calibration data to the HDF5 group: - bias_images and bias_image_frames - uniformity_gain_images and uniformity_gain_image_frames - bad_pixel_masks and bad_pixel_mask_frames
Subclasses should call super().to_hdf5(group) and then add their own data.
- __init__(name, bias_images=None, bias_image_frames=None, uniformity_gain_images=None, uniformity_gain_image_frames=None, bad_pixel_masks=None, bad_pixel_mask_frames=None, _instance_count=0)¶
Sampled Sensor¶
Sampled sensor with interpolated position and geodetic conversion capabilities.
This module defines the SampledSensor class, which extends the base Sensor class to provide position retrieval via interpolation/extrapolation from discrete position samples. It also supports geodetic coordinate conversion using ARF (Attitude Reference Frame) polynomials and radiometric gain calibration.
- class vista.sensors.sampled_sensor.SampledSensor(name, bias_images=None, bias_image_frames=None, uniformity_gain_images=None, uniformity_gain_image_frames=None, bad_pixel_masks=None, bad_pixel_mask_frames=None, _instance_count=0, positions=None, times=None, frames=None, radiometric_gain=None, pointing=None, poly_pixel_to_arf_azimuth=None, poly_pixel_to_arf_elevation=None, poly_arf_to_row=None, poly_arf_to_col=None)[source]¶
Bases:
SensorSensor implementation using sampled position data with interpolation/extrapolation.
SampledSensor stores discrete position samples at known times and provides position estimates at arbitrary times through interpolation (within the time range) or extrapolation (outside the time range). For single-position sensors, the same position is returned for all query times.
- positions¶
Sensor positions as (3, N) array where N is the number of samples. Each column contains [x, y, z] ECEF coordinates in kilometers. Required - will raise ValueError in __post_init__ if not provided.
- Type:
NDArray[np.float64]
- times¶
Times corresponding to each position sample. Must have length N. Required - will raise ValueError in __post_init__ if not provided.
- Type:
NDArray[np.datetime64]
- frames¶
Sensor frames numbers corresponding to each time sample. Must have length N. Required - will raise ValueError in __post_init__ if not provided.
- Type:
NDArray[np.int64]
- radiometric_gain¶
1D array of multiplicative factors for each frame to convert from counts to irradiance in units of kW/km²/sr.
- Type:
NDArray, optional
- pointing¶
Sensor pointing unit vectors in ECEF coordinates. Shape: (3, num_frames). Each column is the direction the sensor is pointing for that frame.
- Type:
NDArray[np.float64], optional
- poly_pixel_to_arf_azimuth¶
Polynomial coefficients for converting (column, row) to ARF azimuth (radians). Shape: (num_frames, num_coeffs) where num_coeffs depends on polynomial order.
- Type:
NDArray[np.float64], optional
- poly_pixel_to_arf_elevation¶
Polynomial coefficients for converting (column, row) to ARF elevation (radians). Shape: (num_frames, num_coeffs) where num_coeffs depends on polynomial order.
- Type:
NDArray[np.float64], optional
- poly_arf_to_row¶
Polynomial coefficients for converting (azimuth, elevation) to row. Shape: (num_frames, num_coeffs) where num_coeffs depends on polynomial order.
- Type:
NDArray[np.float64], optional
- poly_arf_to_col¶
Polynomial coefficients for converting (azimuth, elevation) to column. Shape: (num_frames, num_coeffs) where num_coeffs depends on polynomial order.
- Type:
NDArray[np.float64], optional
Notes
Duplicate times in the input are automatically removed during initialization
For 2+ unique samples: uses linear interpolation within range, linear extrapolation outside
For 1 sample: returns the same position for all query times (stationary sensor)
Positions must be (3, N) arrays with x, y, z in each column
All coordinates are in ECEF Cartesian frame with units of kilometers
ARF (Attitude Reference Frame) is a local coordinate system where the X-axis points along the sensor pointing direction
Examples
>>> import numpy as np >>> # Create sensor with multiple position samples >>> positions = np.array([[1000, 1100, 1200], ... [2000, 2100, 2200], ... [3000, 3100, 3200]]) # (3, 3) array >>> times = np.array(['2024-01-01T00:00:00', ... '2024-01-01T00:01:00', ... '2024-01-01T00:02:00'], dtype='datetime64') >>> sensor = SampledSensor(positions=positions, times=times)
>>> # Get interpolated position >>> query_times = np.array(['2024-01-01T00:00:30'], dtype='datetime64') >>> pos = sensor.get_positions(query_times) >>> pos.shape (3, 1)
>>> # Create stationary sensor with single position >>> positions_static = np.array([[1000], [2000], [3000]]) # (3, 1) array >>> times_static = np.array(['2024-01-01T00:00:00'], dtype='datetime64') >>> sensor_static = SampledSensor(positions=positions_static, times=times_static) >>> # Returns same position for any query time >>> pos = sensor_static.get_positions(query_times)
- __post_init__()[source]¶
Validate inputs and remove duplicate times.
Ensures positions and times have compatible shapes and removes any duplicate time entries along with their corresponding positions.
- Raises:
ValueError – If positions or times are not provided, or if they have incompatible shapes.
- can_geolocate()[source]¶
Check if sensor can convert pixels to geodetic coordinates and vice versa.
- Returns:
True if sensor has all required ARF geolocation data: pointing vectors and both forward (pixel→ARF) and reverse (ARF→pixel) polynomials.
- Return type:
- get_positions(times)[source]¶
Return sensor positions for given times via interpolation/extrapolation.
- Parameters:
times (NDArray[np.datetime64]) – Array of times for which to retrieve sensor positions
- Returns:
Sensor positions as (3, N) array where N is the number of query times. Each column contains [x, y, z] coordinates in ECEF frame (km).
- Return type:
NDArray[np.float64]
Notes
For sensors with 1 sample: returns the single position for all times
For sensors with 2+ samples: uses linear interpolation within the time range and linear extrapolation outside the range
- pixel_to_geodetic(frame, rows, columns)[source]¶
Convert pixel coordinates to geodetic coordinates using ARF polynomials.
Uses ARF (Attitude Reference Frame) polynomials to map (row, column) pixel coordinates to geodetic coordinates by ray-casting to the Earth’s surface. Pixels that do not intersect Earth will have NaN coordinates.
- Parameters:
frame (int) – Frame number for which to perform the conversion
rows (np.ndarray) – Array of row pixel coordinates
columns (np.ndarray) – Array of column pixel coordinates
- Returns:
Astropy EarthLocation object(s) with geodetic coordinates. Returns NaN coordinates for pixels that do not intersect Earth. Returns zero coordinates if polynomials are not available or frame not found.
- Return type:
EarthLocation
Notes
Requires ARF polynomials and pointing vectors to be defined
Frame must exist in self.frames array
Off-Earth pixels will have NaN lat/lon/height values
- geodetic_to_pixel(frame, loc)[source]¶
Convert geodetic coordinates to pixel coordinates using ARF polynomials.
Uses ARF (Attitude Reference Frame) polynomials to map geodetic coordinates (latitude, longitude, altitude) to (row, column) pixel coordinates. This method properly handles targets at any altitude, not just ground level.
- Parameters:
frame (int) – Frame number for which to perform the conversion
loc (EarthLocation) – Astropy EarthLocation object(s) containing geodetic coordinates
- Returns:
rows (np.ndarray) – Array of row pixel coordinates (zeros if polynomials unavailable)
columns (np.ndarray) – Array of column pixel coordinates (zeros if polynomials unavailable)
- Return type:
Notes
Requires ARF polynomials and pointing vectors to be defined
Frame must exist in self.frames array
Returns zero coordinates if polynomials are not available or frame not found
Properly handles targets at any altitude (not limited to ground level)
- to_hdf5(group)[source]¶
Save sampled sensor data to an HDF5 group.
- Parameters:
group (h5py.Group) – HDF5 group to write sensor data to (typically sensors/<sensor_name>/)
Notes
This method extends the base Sensor.to_hdf5() by adding: - Position data (positions, times) in position/ subgroup - Geolocation polynomials in geolocation/ subgroup - Radiometric gain values in radiometric/ subgroup
- __init__(name, bias_images=None, bias_image_frames=None, uniformity_gain_images=None, uniformity_gain_image_frames=None, bad_pixel_masks=None, bad_pixel_mask_frames=None, _instance_count=0, positions=None, times=None, frames=None, radiometric_gain=None, pointing=None, poly_pixel_to_arf_azimuth=None, poly_pixel_to_arf_elevation=None, poly_arf_to_row=None, poly_arf_to_col=None)¶
Basic Usage¶
Creating a Sensor¶
from vista.sensors import Sensor
# Create a sensor with calibration data
sensor = Sensor(
name="My Sensor",
focal_length=50.0,
pixel_size=5.0e-6,
width=1024,
height=768
)
Using Sensor Data¶
# Access sensor properties
print(f"Focal length: {sensor.focal_length} mm")
print(f"Field of view: {sensor.fov} degrees")
# Use sensor for transformations
from vista.transforms import sensor_to_ground
ground_point = sensor_to_ground(pixel_x, pixel_y, sensor)