Imagery Module¶
The imagery module provides core functionality for loading, managing, and manipulating multi-frame imagery datasets.
Core Classes¶
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:
Frame-based indexing and slicing
Area of interest (AOI) extraction
Integration with time and geodetic coordinate systems
Sensor metadata association
Incremental loading support
Optional GPU acceleration via PyTorch
Basic Usage¶
Creating Imagery¶
Imagery objects are created directly using the constructor. Images are loaded from HDF5 files via
DataLoaderThread or constructed programmatically:
import numpy as np
from vista.imagery.imagery import Imagery
from vista.sensors.sensor import Sensor
sensor = Sensor(name="My Sensor")
images = np.random.randn(100, 256, 256).astype(np.float32)
frames = np.arange(100)
img = Imagery(name="Test", images=images, frames=frames, sensor=sensor)
# Access imagery properties
print(f"Shape: {img.images.shape}") # (100, 256, 256)
print(f"Number of frames: {len(img)}") # 100
Slicing and Subsetting¶
# Get a range of frames (returns a new Imagery)
subset = img[10:20]
# Get an area of interest
from vista.aoi import AOI
aoi = AOI(name="Region", x=100, y=100, width=100, height=100)
cropped = img.get_aoi(aoi)
Working with Copies¶
# Create a shallow copy (images array is shared by reference)
img_copy = img.copy()
# Modify the copy without affecting the original
img_copy.images = img_copy.images * 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:
objectContainer 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
- pixel_to_geodetic(frame, rows, columns)¶
Convert pixel coordinates to geodetic (lat/lon/alt)
- (frame, location)
Convert geodetic coordinates to pixel (row/column)
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
- property is_fully_loaded¶
Return True if all frames have been loaded (or if imagery was created programmatically).
- property loaded_frames¶
Return the subset of frame numbers that have been loaded so far.
- property has_gpu_images¶
Return True if a GPU tensor copy of the images exists.
- property gpu_device¶
0’) if a GPU copy exists, or None.
- Type:
Return the GPU device string (e.g. ‘cuda
- property gpu_device_name¶
Return the human-readable GPU device name (e.g. ‘NVIDIA RTX 4090’) if a GPU copy exists, or None.
- property gpu_images¶
Return the GPU tensor copy of images, creating it lazily if needed.
Uses the GPU device configured in application settings, or ‘cuda:0’ as default. Requires imagery to be fully loaded.
- Returns:
GPU tensor with shape (num_frames, height, width) and dtype float32
- Return type:
torch.Tensor
- Raises:
RuntimeError – If PyTorch is not installed, no CUDA device is available, or imagery is not fully loaded
- to_gpu(device=None)[source]¶
Explicitly upload images to a specific GPU device.
- Parameters:
device (str, optional) – PyTorch device string (e.g. ‘cuda:0’, ‘cuda:1’). If None, uses the device configured in application settings, or ‘cuda:0’ as default.
- Returns:
GPU tensor with shape (num_frames, height, width) and dtype float32
- Return type:
torch.Tensor
- Raises:
RuntimeError – If PyTorch is not installed, no CUDA device is available, or imagery is not fully loaded
- 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)).
- copy()[source]¶
Create a (soft) copy of this imagery.
The numpy images array and GPU tensor (if present) are shared by reference, not copied.
- 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:
- Returns:
(hist_y, bin_centers) - histogram counts and bin center values
- Return type:
- 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:
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]})