Imagery Module

The imagery module provides core functionality for loading, managing, and manipulating multi-frame imagery datasets.

Core Classes

imagery.Imagery

Container for multi-frame imagery datasets with metadata and coordinate conversion capabilities.

The Imagery class is the foundation for working with image data in VISTA. It provides:

  • Loading and saving imagery from various formats

  • Frame-based indexing and slicing

  • Area of interest (AOI) extraction

  • Integration with time and geodetic coordinate systems

  • Support for sensor metadata

Basic Usage

Creating and Loading Imagery

from vista.imagery import Imagery

# Load from file
img = Imagery.from_file('path/to/data.h5')

# Access imagery properties
print(f"Shape: {img.shape}")
print(f"Number of frames: {img.num_frames}")
print(f"Frame rate: {img.frame_rate}")

Slicing and Subsetting

# Get a single frame
frame_10 = img[10]

# Get a range of frames
frames = img[10:20]

# Get an area of interest
aoi = img.get_aoi(x_min=100, x_max=200, y_min=100, y_max=200)

Working with Copies

# Create a deep copy
img_copy = img.copy()

# Modify the copy without affecting the original
img_copy.data *= 2.0

Module Reference

Module that contains the default imagery object

The Imagery object in this class can be subclassed by third-party objects to implement their own logic including file readers and pixel-to-geodetic conversions

class vista.imagery.imagery.Imagery(name, images, frames, sensor, row_offset=None, column_offset=None, times=None, description='', _histograms=None, default_histogram_bounds=None)[source]

Bases: object

Container for multi-frame imagery datasets with metadata and coordinate conversion capabilities.

VISTA’s Imagery class represents a temporal sequence of image frames with associated metadata including timestamps, geodetic coordinate conversion polynomials, and sensor calibration data. This class serves as the foundation for all image-based analysis in VISTA.

Core Attributes

namestr

Human-readable identifier for this imagery dataset

imagesNDArray[np.float32]

3D array of image data with shape (num_frames, height, width). Pixel values are stored as 32-bit floats to support processing operations.

framesNDArray[np.int_]

1D array of frame numbers corresponding to each image. Frame numbers need not be sequential or start at zero.

row_offsetint, optional

Row offset for imagery positioning (default: 0). Used when imagery represents a subset/crop of a larger scene.

column_offsetint, optional

Column offset for imagery positioning (default: 0). Used when imagery represents a subset/crop of a larger scene.

Temporal Metadata

timesNDArray[np.datetime64], optional

Timestamp for each frame with microsecond precision. Enables time-based analysis and temporal coordinate conversion.

Sensor Information

sensorSensor

Sensor object containing projection polynomials and radiometric calibration data. The Sensor provides geodetic coordinate conversion capabilities, sensor positions, and optional point spread function modeling for irradiance estimation.

Internal Attributes

descriptionstr, optional

Long-form description of the imagery (default: “”)

_histogramsdict, optional

Cached histograms for performance. Maps frame_index -> (hist_y, hist_x). Computed lazily via get_histogram() method.

uuidstr

Unique identifier automatically generated for each Imagery instance

__getitem__(slice)[source]

Slice imagery by frame range, preserving metadata

get_aoi(aoi)[source]

Extract spatial subset defined by Area of Interest

pixel_to_geodetic(frame, rows, columns)

Convert pixel coordinates to geodetic (lat/lon/alt)

geodetic_to_pixel(frame, location)

Convert geodetic coordinates to pixel (row/column)

get_histogram(frame_index)[source]

Compute or retrieve cached histogram for a frame

to_hdf5(file)[source]

Save imagery and all metadata to HDF5 file

copy()[source]

Create a shallow copy of the imagery object

Examples

>>> # Create basic imagery
>>> import numpy as np
>>> images = np.random.randn(100, 256, 256).astype(np.float32)
>>> frames = np.arange(100)
>>> imagery = Imagery(name="Test", images=images, frames=frames)
>>> # Create imagery with timestamps
>>> times = np.array([np.datetime64('2024-01-01T00:00:00') +
...                   np.timedelta64(i*100, 'ms') for i in range(100)])
>>> imagery = Imagery(name="Test", images=images, frames=frames, times=times)
>>> # Slice imagery by frame range
>>> subset = imagery[10:50]  # Frames 10-49
>>> # Extract spatial subset via AOI
>>> from vista.aoi import AOI
>>> aoi = AOI(name="Region1", x=50, y=50, width=100, height=100)
>>> cropped = imagery.get_aoi(aoi)

Notes

  • Frame numbers in the frames array need not be contiguous or zero-indexed

  • All optional metadata (times, polynomials, calibration data) is preserved during slicing operations

  • Geodetic conversion requires valid polynomial coefficients for the frame of interest

  • Calibration frame arrays define ranges: frame N applies until frame N+1 starts

name: str
images: ndarray[tuple[Any, ...], dtype[float32]]
frames: ndarray[tuple[Any, ...], dtype[int64]]
sensor: Sensor
row_offset: int = None
column_offset: int = None
times: ndarray[tuple[Any, ...], dtype[datetime64]] | None = None
description: str = ''
default_histogram_bounds: dict | None = None
uuid: str = None
__getitem__(s)[source]
get_frame_index(frame_num)[source]

Get array index for a specific frame number using efficient lookup.

Uses binary search if frames are sorted (O(log n)), otherwise uses cached dictionary lookup (O(1)).

Parameters:

frame_num (int) – Frame number to find

Returns:

Array index for the frame, or None if frame not found

Return type:

int or None

invalidate_caches()[source]

Invalidate cached data structures when imagery data changes.

copy()[source]

Create a (soft) copy of this imagery

get_histogram(frame_index, bins=256, max_rowcol=512)[source]

Get histogram for a specific frame using consistent bin edges.

Computes histogram if not cached, using pre-computed global bin edges for consistency across frames.

Parameters:
  • frame_index (int) – Index of frame to get histogram for

  • bins (int) – Number of histogram bins (default: 256)

  • max_rowcol (int) – Maximum number of rows or columns to search over. Downsamples imagery larger than this for the purpose of computing the histogram.

Returns:

(hist_y, bin_centers) - histogram counts and bin center values

Return type:

tuple

has_cached_histograms()[source]

Check if histograms have been pre-computed

get_aoi(aoi)[source]
to_hdf5(group)[source]

Save imagery data to an HDF5 group.

Parameters:

group (h5py.Group) – HDF5 group to write imagery data to (typically sensors/<sensor_uuid>/imagery/<imagery_uuid>/)

Notes

This method writes only imagery-specific data: - Image arrays (chunked for efficient loading) - Frame numbers - Times (as unix_nanoseconds) - Row/column offsets - Metadata attributes (name, description, uuid)

Sensor data should be written separately using sensor.to_hdf5()

__init__(name, images, frames, sensor, row_offset=None, column_offset=None, times=None, description='', _histograms=None, default_histogram_bounds=None)
vista.imagery.imagery.save_imagery_hdf5(file_path, sensor_imagery_map)[source]

Save imagery data to HDF5 file with hierarchical sensor/imagery structure.

Parameters:
  • file_path (Union[str, pathlib.Path]) – Path to the HDF5 file to create

  • sensor_imagery_map (dict[str, list[Imagery]]) – Dictionary mapping Sensor object names to lists of Imagery objects from that sensor

Notes

The HDF5 file structure created is: ``` root/ ├── [attrs] format_version, created └── sensors/

├── <sensor_uuid>/ │ ├── [attrs] name, uuid, sensor_type │ ├── position/ (SampledSensor only) │ ├── geolocation/ (if can_geolocate) │ ├── radiometric/ (if calibration data exists) │ └── imagery/ │ ├── <imagery_uuid_1>/ │ │ ├── [attrs] name, uuid, description, … │ └── <imagery_uuid_2>/ └── <sensor_uuid_2>/

└── …

```

Examples

>>> sensor = SampledSensor(name="MySensor", ...)
>>> imagery1 = Imagery(name="img1", sensor=sensor, ...)
>>> imagery2 = Imagery(name="img2", sensor=sensor, ...)
>>> save_imagery_hdf5("data.h5", {"MySensor": [imagery1, imagery2]})