asp_plot.sensors#

Sensor-specific metadata readers for stereo scenes.

This package isolates the sensor-specific work of discovering scene files and extracting per-scene metadata from the sensor-agnostic stereo-pair geometry math in asp_plot.stereopair_metadata_parser.

The goal is flexibility: WorldView (and other DigitalGlobe-heritage) XML camera files, the Airbus DIMAP v2 family (Pléiades 1A/1B and Neo, SPOT 6/7, PeruSat-1), the DIMAP v1 family (SPOT 5, ALOS PRISM), ASTER gen_aster camera files, and RPC-only products (Cartosat-1, Deimos, anything ASP runs with -t rpc) are supported, and adding a new sensor is a matter of writing a new SensorMetadata subclass in its own module and registering it in SENSORS — no changes to the pair-level geometry code are required.

Most readers parse metadata a vendor wrote down; asp_plot.sensors.aster and asp_plot.sensors.rpc instead derive their scene dicts (footprint, view angles, GSD, satellite positions) from look vectors, because their camera files record no summary geometry at all. Both kinds fill the same schema.

Most readers also claim XML files; the RPC reader claims images, because that is where an RPC-only product keeps its camera model. It is therefore marked fallback and consulted only after every XML reader has declined, since a WorldView or Pléiades delivery ships images alongside its camera XMLs.

Each reader is responsible for turning a directory of camera/metadata files into a list of scene dicts, one per scene, each containing the sensor-agnostic keys the geometry code consumes:

xml_fn, catid, sensor, date, scandir, tdi, geom (a Shapely polygon footprint in EPSG:4326), the mean view-angle/GSD/sun attributes (meansataz, meansatel, meanoffnadirviewangle, meanintrackviewangle, meancrosstrackviewangle, meanproductgsd, meansunaz, meansunel, cloudcover), and — when geteph is True — eph_gdf (ephemeris GeoDataFrame in EPSG:4978), att_df (attitude DataFrame), and fp_gdf (footprint GeoDataFrame in EPSG:4326).

eph_gdf and fp_gdf are the trajectory block’s own optional members: fp_gdf is always provided, while eph_gdf is omitted entirely by a reader that can recover no satellite positions at all (an RPC-only product whose look rays do not converge). Consumers use d.get("eph_gdf") and plot the footprint alone when it is absent.

att_df comes in one of two shapes, depending on what the sensor reports: quaternions (q1..q4, scalar-last) or the vendor’s own roll/pitch/yaw (roll/pitch/yaw in degrees, with attrs["rpy_frame"] naming the frame they are defined in). Both carry NaN-filled cov_* columns when the format has no covariance. Consumers dispatch on which columns are present, and must tolerate att_df being None: a sensor whose camera files record no attitude at all (ASTER) reports it that way rather than inventing one.

eph_gdf is time-indexed for every sensor that timestamps its trajectory; ASTER and RPC-only products, which timestamp nothing, index it by image line number instead.

Layout: asp_plot.sensors.base holds the SensorMetadata ABC and shared helpers; each sensor family lives in its own module (asp_plot.sensors.worldview, asp_plot.sensors.dimap, asp_plot.sensors.dimap_v1, asp_plot.sensors.aster, asp_plot.sensors.rpc); this __init__ holds the SENSORS registry and the detection entry points, and re-exports every public name so from asp_plot.sensors import ... is stable across the package split.

Submodules#

Attributes#

Classes#

AsterMetadata

Metadata reader for ASP gen_aster ASTER camera XMLs.

PleiadesMetadata

Metadata reader for Airbus-family DIMAP v2 camera files.

PrismMetadata

Metadata reader for ALOS PRISM DIMAP-style scene metadata.

RpcMetadata

Metadata reader for images whose only camera model is an RPC.

SensorMetadata

Abstract base class for a single sensor's metadata reader.

Spot5Metadata

Metadata reader for SPOT 5 DIMAP v1 scene metadata.

WorldViewMetadata

Metadata reader for WorldView satellite XML camera files.

Functions#

resolve_camera_inputs(inputs[, recursive])

Expand inputs into every candidate camera file: XMLs and images.

resolve_xml_inputs(inputs[, recursive])

Expand files, directories, and glob patterns into XML file paths.

sensor_for_directory(directory)

Detect and instantiate the appropriate sensor reader for a directory.

sensor_for_inputs(inputs)

Detect and instantiate the appropriate sensor reader for explicit inputs.

Package Contents#

class asp_plot.sensors.AsterMetadata(directory=None, image_list=None)#

Bases: asp_plot.sensors.base.SensorMetadata

Metadata reader for ASP gen_aster ASTER camera XMLs.

One scene per band file, so a 3N/3B pair goes through the existing N-choose-2 pair machinery with no special-casing: the derived view angles reproduce ASTER’s nadir/backward stereo geometry (~31° convergence at the ground for the nominal 27.6° backward pointing).

See the module docstring for what is derived and what is unavailable. In short: footprint, view angles, GSD and a positions-only trajectory are derived; attitude does not exist (att_df is None), sun angles and cloud cover are absent, and the date comes from a neighbouring L1A granule name if there is one.

get_scene_dict(xml, geteph=True)#

Get a dictionary of metadata for one ASTER band.

Parameters:
  • xml (str) – Path to the gen_aster camera XML.

  • geteph (bool, optional) – Whether to include the trajectory block, default is True.

Returns:

Sensor-agnostic scene dict (see the package docstring).

Return type:

dict

get_scene_dicts()#

Return one sensor-agnostic scene dict per camera XML.

name = 'ASTER'#
class asp_plot.sensors.PleiadesMetadata(directory=None, image_list=None)#

Bases: asp_plot.sensors.base.SensorMetadata

Metadata reader for Airbus-family DIMAP v2 camera files.

Parses DIMAP v2 primary-product metadata (DIM_*.XML, root tag Dimap_Document) as delivered with Pléiades 1A/1B, Pléiades Neo, SPOT 6/7, and PeruSat-1 SEN(sor) products. Each scene is delivered as a single DIM XML, so unlike WorldView there is no tile mosaicking step. The sidecar RPC_*.XML files share the DIMAP root but carry no ephemeris, attitude, or acquisition-angle information, so discovery keeps only files whose METADATA_SUBPROFILE is PRODUCT and whose METADATA_PROFILE is one of SUPPORTED_DIMAP_PROFILES (products from other DIMAP profiles are skipped with an explanatory warning). Profiles in SPEC_ONLY_DIMAP_PROFILES are implemented from ASP’s reader spec but not yet validated against real deliveries (#168).

Notes

  • Airbus quaternions are scalar-first (Q0 is the scalar part). They are reordered to the scalar-last q1..q4 layout shared with WorldView, as consumed by the roll/pitch/yaw computation in asp_plot.stereo_geometry.StereoGeometryPlotter._compute_roll_pitch_yaw().

  • Attitude comes in two shapes: tabulated quaternion samples (Quaternion_List; Pléiades Neo, SPOT 6/7, PeruSat-1) or one degree-3 polynomial per quaternion component (Polynomial_Quaternions; Pléiades 1A/1B), which is evaluated at the ephemeris timestamps so both shapes yield the same tabulated att_df downstream.

  • DIMAP reports no ephemeris/attitude covariance and no scan direction or TDI level: the cov_* columns are filled with NaN and scandir / tdi are None. Consumers treat those as “not provided”.

  • The mean view/sun angles and GSD are averaged over the Located_Geometric_Values blocks — nine for Pléiades/SPOT (corners, edge midpoints, center), a single center block for PeruSat-1. meansatel is derived as 90° minus the mean target incidence angle, matching the WorldView MEANSATEL convention.

getAtt_df(root)#

Create an attitude DataFrame from a parsed DIMAP document.

Pléiades Neo, SPOT 6/7, and PeruSat-1 products tabulate quaternion samples in a Quaternion_List; Pléiades 1A/1B products instead provide one polynomial per quaternion component (Polynomial_Quaternions), which is evaluated at the ephemeris timestamps so both shapes come out as the same tabulated DataFrame.

Parameters:

root (xml.etree.ElementTree.Element) – Parsed Dimap_Document root element.

Returns:

Time-indexed DataFrame with scalar-last quaternions q1..q4 (Airbus Q0 is the scalar part and lands in q4), plus NaN cov_* columns (DIMAP provides no attitude covariance).

Return type:

pandas.DataFrame

getEphem_gdf(root)#

Create an ephemeris GeoDataFrame from a parsed DIMAP document.

Parameters:

root (xml.etree.ElementTree.Element) – Parsed Dimap_Document root element.

Returns:

Time-indexed GeoDataFrame with x, y, z positions (m) and dx, dy, dz velocities (m/s) in ECEF (EPSG:4978), plus NaN cov_* columns (DIMAP provides no ephemeris covariance).

Return type:

geopandas.GeoDataFrame

get_scene_dict(xml, geteph=True)#

Get a dictionary of metadata for one DIMAP scene.

Parameters:
  • xml (str) – Path to the DIM_*.XML product metadata file.

  • geteph (bool, optional) – Whether to extract ephemeris/attitude data, default is True.

Returns:

Sensor-agnostic scene dict (see package docstring).

Return type:

dict

get_scene_dicts()#

Return one sensor-agnostic scene dict per DIMAP product XML.

name = 'Pleiades'#
class asp_plot.sensors.PrismMetadata(directory=None, image_list=None)#

Bases: DimapV1Metadata

Metadata reader for ALOS PRISM DIMAP-style scene metadata.

Parses the ALOS PRISM *.DIMA/*.XML metadata that ASP’s PRISM_XML.cc reads (used by prism2asp to build CSM linescan cameras). A PRISM triplet delivers one file per view (forward, nadir, backward), each of which is one scene here.

Notes

  • Attitude is tabulated as roll/pitch/yaw in degrees under Satellite_Attitudes/Angles_List/Angles/Angle; ASP applies them with rollPitchYaw(), which converts degrees to radians.

  • Those angles are the satellite’s attitude relative to the nominal (along, across, down) orbital frame, composed as Rz(yaw) Ry(pitch) Rx(roll) — the same frame and Euler convention as the roll/pitch/yaw this package derives from quaternion sensors’ attitude, so PRISM curves are directly comparable to those. The fixed per-view mounting rotation ASP applies on top (cam2sat) is camera geometry, not satellite attitude, and is deliberately not folded in here.

  • PRISM reports no view or GSD summary angles in the metadata header, so those degrade to NaN; the sun angles are filled when present.

getAtt_df(root)#

Create an attitude DataFrame from a parsed PRISM document.

Parameters:

root (xml.etree.ElementTree.Element) – Parsed Dimap_Document root element.

Returns:

Time-indexed DataFrame with roll, pitch, yaw in degrees (as delivered) and NaN cov_* columns.

Return type:

pandas.DataFrame

get_scene_dict(xml, geteph=True)#

Get a dictionary of metadata for one ALOS PRISM scene.

Parameters:
  • xml (str) – Path to the PRISM DIMAP-style metadata file.

  • geteph (bool, optional) – Whether to extract ephemeris/attitude data, default is True.

Returns:

Sensor-agnostic scene dict (see the package docstring).

Return type:

dict

name = 'PRISM'#
rpy_frame = 'orbital frame (along, across, down)'#
class asp_plot.sensors.RpcMetadata(directory=None, image_list=None)#

Bases: asp_plot.sensors.base.SensorMetadata

Metadata reader for images whose only camera model is an RPC.

Covers everything ASP runs with -t rpc — Cartosat-1, Deimos, and the tail of commercial products delivered with rational polynomials and nothing else — as one reader, because the camera model is the format.

Unlike every other reader in this package, the file it claims is the image, not a sidecar XML. That makes it a fallback reader: a WorldView or Pléiades delivery ships images alongside its camera XMLs and those images carry RPCs too, so this reader is only consulted once every XML-based reader has declined the input at every search depth.

See the module docstring for what is derived and what is unavailable.

get_scene_dict(image_fn, geteph=True)#

Get a dictionary of metadata for one RPC image.

Parameters:
  • image_fn (str) – Path to the image carrying the RPC camera model.

  • geteph (bool, optional) – Whether to include the trajectory block, default is True.

Returns:

Sensor-agnostic scene dict (see the package docstring).

Return type:

dict

Raises:

ValueError – If image_fn carries no usable RPC camera model.

get_scene_dicts()#

Return one sensor-agnostic scene dict per image.

fallback = True#
name = 'RPC-only'#
class asp_plot.sensors.SensorMetadata(directory)#

Bases: abc.ABC

Abstract base class for a single sensor’s metadata reader.

A concrete reader discovers the scene files for one sensor in a directory and extracts a list of sensor-agnostic scene dicts (see the package docstring for the schema) that the stereo-pair geometry code can consume without knowing which sensor produced them.

Subclasses must implement _is_camera_file() (the content check that decides which files the sensor claims; discovery and detection are built on it here) and get_scene_dicts().

name#

Human-readable sensor name (e.g. "WorldView").

Type:

str

fallback#

Whether this reader is a last-resort match, tried only after every other reader has failed at every search depth. Set on readers that claim files a more specific reader’s delivery also contains — the RPC reader claims images, and every WorldView or Pléiades delivery ships images next to its camera XMLs (issue #177).

Type:

bool

directory#

Path to the directory containing the sensor’s metadata files.

Type:

str

classmethod detect(directory, recursive=True)#

Return True if this reader can handle the files in directory.

Parameters:
  • directory (str) – Path to directory to inspect.

  • recursive (bool, optional) – If True (default), also match metadata files nested in subdirectories. asp_plot.sensors.sensor_for_directory() first asks every sensor to detect shallowly and only then recursively, so a sensor matching at the top level wins over one matching a nested delivery.

Returns:

Whether this sensor’s metadata files are present.

Return type:

bool

classmethod detect_files(image_list)#

Return True if this reader can handle the files in image_list.

The file-list counterpart of detect(), used when the sensor must be chosen from an explicit list of inputs rather than a directory.

Parameters:

image_list (list of str) – Candidate metadata file paths.

Returns:

Whether this sensor’s metadata files are present in the list.

Return type:

bool

abstractmethod get_scene_dicts()#

Return a list of per-scene metadata dictionaries.

Returns:

One sensor-agnostic scene dict per scene (see package docstring).

Return type:

list of dict

directory#
fallback = False#
name = 'sensor'#
class asp_plot.sensors.Spot5Metadata(directory=None, image_list=None)#

Bases: DimapV1Metadata

Metadata reader for SPOT 5 DIMAP v1 scene metadata.

Parses the METADATA.DIM / *.XML scene metadata delivered with SPOT 5 HRG/HRS products, mirroring ASP’s SPOT_XML.cc (the spot5 session). Ephemeris and attitude both live in Data_Strip; the scene footprint comes from Dataset_Frame.

Notes

  • Attitude is tabulated as yaw/pitch/roll in radians under Corrected_Attitudes/Corrected_Attitude/Angles and converted to degrees here. ASP feeds the raw values straight to sin/cos in get_look_rotation_matrix, which is what fixes the unit.

  • The angles are defined in the SPOT 123-4-5 Geometry Handbook navigation frame, relative to its local orbital frame (X across-track, Y along-track, Z up), composed as Mp*Mr*My. That is a different axis assignment from the (along, across, down) frame the quaternion sensors’ roll/pitch/yaw are computed in, so the values are reported as delivered and labeled with their own frame rather than silently mixed with the others.

  • DIMAP v1 reports no satellite azimuth, so meansataz stays NaN and the pair convergence angle degrades to NaN; the incidence, viewing and sun angles that are in Scene_Source are filled.

getAtt_df(root)#

Create an attitude DataFrame from a parsed SPOT 5 document.

Parameters:

root (xml.etree.ElementTree.Element) – Parsed Dimap_Document root element.

Returns:

Time-indexed DataFrame with roll, pitch, yaw in degrees (converted from the radians on disk) and NaN cov_* columns.

Return type:

pandas.DataFrame

get_scene_dict(xml, geteph=True)#

Get a dictionary of metadata for one SPOT 5 scene.

Parameters:
  • xml (str) – Path to the SPOT 5 DIMAP v1 scene metadata file.

  • geteph (bool, optional) – Whether to extract ephemeris/attitude data, default is True.

Returns:

Sensor-agnostic scene dict (see the package docstring).

Return type:

dict

name = 'SPOT5'#
rpy_frame = 'SPOT Geometry Handbook navigation frame'#
class asp_plot.sensors.WorldViewMetadata(directory=None, image_list=None)#

Bases: asp_plot.sensors.base.SensorMetadata

Metadata reader for WorldView satellite XML camera files.

Parses WorldView (and other DigitalGlobe-heritage products that share the same XML format, e.g. GeoEye-1, QuickBird, IKONOS) satellite XML files to extract per-scene metadata, handling both single XML files and multiple XML tiles per scene (mosaicked with dg_mosaic).

This class is named for the sensor family (the stable WorldView name) and governs which reader parses the XML. It is intentionally distinct from the attribution check asp_plot.utils.detect_vantor_satellite(), which is named for the rights-holder (Vantor) and decides whether the “© Vantor” overlay applies. The two concerns use different names on purpose; see #137.

directory#

Path to directory containing XML files.

Type:

str

image_list#

List of XML files found in the directory.

Type:

list

getAtt(xml)#

Extract attitude data from XML file.

Retrieves satellite attitude (orientation quaternion and covariance) data from the XML file.

Parameters:

xml (str) – Path to the XML file

Returns:

Array of shape (N, 15) containing attitude data with columns: point_num, q1, q2, q3, q4, and 10 covariance matrix elements (upper triangle of 4x4 matrix)

Return type:

numpy.ndarray

getAtt_df(xml)#

Create a DataFrame from attitude data.

Converts attitude data to a DataFrame with time index.

Parameters:

xml (str) – Path to the XML file

Returns:

DataFrame with attitude quaternions and covariance, time-indexed

Return type:

pandas.DataFrame

getEphem(xml)#

Extract ephemeris data from XML file.

Retrieves satellite ephemeris (position and velocity) data from the XML file.

Parameters:

xml (str) – Path to the XML file

Returns:

Array containing ephemeris data with columns: point_num, Xpos, Ypos, Zpos, Xvel, Yvel, Zvel, and covariance matrix elements

Return type:

numpy.ndarray

Notes

All coordinates are in Earth-Centered Fixed (ECF) reference frame. Units are meters for positions, meters/sec for velocities, and m^2 for covariance.

getEphem_gdf(xml)#

Create a GeoDataFrame from ephemeris data.

Converts ephemeris data to a GeoDataFrame with time index and Point geometry.

Parameters:

xml (str) – Path to the XML file

Returns:

GeoDataFrame with ephemeris data and Point geometries in EPSG:4978

Return type:

geopandas.GeoDataFrame

Notes

The GeoDataFrame uses EPSG:4978 (Earth-Centered Earth-Fixed) CRS and has a time index corresponding to the acquisition times.

get_catid_xmls()#

Get a single representative XML file for each catalog ID.

Groups the discovered XML files by their catalog ID (read from the XML content, not the filename) and resolves each scene to one XML: a scene delivered as a single XML is used as-is, while a scene tiled across multiple XMLs is mosaicked into one with dg_mosaic.

Returns:

Dictionary mapping catalog IDs to a single XML file path.

Return type:

dict

Raises:

ValueError – If none of the discovered XML files contain a CATID tag.

Notes

Mosaicking is decided per catalog ID, so a directory holding many distinct single-tile scenes is not mosaicked just because it contains more than two XML files. Mosaicking a tiled scene requires dg_mosaic from the NASA Ames Stereo Pipeline on the system path.

get_id_dict(catid, xml, geteph=True)#

Get a dictionary of metadata for a specific catalog ID.

Extracts metadata from XML file for a given catalog ID, including satellite parameters, acquisition angles, and geometry.

Parameters:
  • catid (str) – Catalog ID for the satellite image

  • xml (str) – Path to the XML file

  • geteph (bool, optional) – Whether to extract ephemeris data, default is True

Returns:

Dictionary containing metadata for the catalog ID

Return type:

dict

Notes

The dictionary includes satellite ID, acquisition date, scan direction, TDI level, geometry information, and various mean angles and parameters. If geteph is True, also includes ephemeris and footprint GeoDataFrames.

The identity core (xml_fn, catid, sensor, date, geom) is read strictly — a camera XML without those is an error. The summary fields degrade to “not provided” (None/NaN) when their tags are absent (issue #163): dg_mosaic can strip image tags, and Multi products carry per-band TDI instead of a single TDILEVEL.

get_scene_dicts()#

Get dictionaries of metadata for each catalog ID.

Builds dictionaries of metadata for each catalog ID found in the XML files.

Returns:

List of dictionaries, one for each catalog ID, containing metadata

Return type:

list

xml2poly(xml)#

Convert XML corner coordinates to Shapely Polygon.

Reads XML file and converts corner coordinates to a Shapely Polygon geometry.

Parameters:

xml (str) – Path to the XML file

Returns:

Polygon geometry representing the image footprint

Return type:

shapely.geometry.Polygon

xml2wkt(xml)#

Convert XML corner coordinates to WKT polygon string.

Extracts corner coordinates from XML file and converts them to a Well-Known Text (WKT) polygon string.

Parameters:

xml (str) – Path to the XML file

Returns:

WKT polygon string representation of image footprint

Return type:

str

Notes

Uses ULLON/ULLAT, URLON/URLAT, LRLON/LRLAT, LLLON/LLLAT tags (Upper-Left, Upper-Right, Lower-Right, Lower-Left corners).

name = 'WorldView'#
asp_plot.sensors.resolve_camera_inputs(inputs, recursive=True)#

Expand inputs into every candidate camera file: XMLs and images.

resolve_xml_inputs() covers the readers whose camera model is a sidecar XML; RPC-only products carry theirs inside the image (issue #177), so directory inputs also contribute candidate rasters here. Explicitly named files are included whatever their extension, so stereo_geom fore.tif aft.tif works.

Mixing the two kinds in one list is safe: every reader filters the list through its own SensorMetadata._is_camera_file() content check, so a WorldView delivery’s images are ignored by the WorldView reader and its XMLs by the RPC reader.

Parameters:
  • inputs (str or os.PathLike or iterable of those) – One or more files, directories, and/or glob patterns.

  • recursive (bool, optional) – Passed through to directory discovery and ** glob expansion. Default True.

Returns:

Sorted, de-duplicated candidate camera file paths.

Return type:

list of str

asp_plot.sensors.resolve_xml_inputs(inputs, recursive=True)#

Expand files, directories, and glob patterns into XML file paths.

Lets a user point the tools at messy inputs without a fixed directory structure — e.g. geom_plot *.XML (already expanded by the shell), geom_plot scene1.xml scene2.xml, geom_plot delivery_dir/, or a mix.

Each item of inputs may be:

Results are de-duplicated (by absolute path) and returned sorted. Directory inputs get only the generic basename filter (README.XML, ortho products); the sensor-specific content checks are applied by the readers, not here.

Parameters:
  • inputs (str or os.PathLike or iterable of those) – One or more files, directories, and/or glob patterns.

  • recursive (bool, optional) – Passed through to directory discovery and ** glob expansion. Default True.

Returns:

Sorted, de-duplicated XML file paths.

Return type:

list of str

asp_plot.sensors.sensor_for_directory(directory)#

Detect and instantiate the appropriate sensor reader for a directory.

Iterates the SENSORS registry and returns an instance of the first reader whose SensorMetadata.detect() matches the directory contents.

Parameters:

directory (str) – Path to directory containing camera/metadata files.

Returns:

An initialized reader for the detected sensor.

Return type:

SensorMetadata

Raises:

ValueError – If no registered sensor reader matches the directory contents.

asp_plot.sensors.sensor_for_inputs(inputs)#

Detect and instantiate the appropriate sensor reader for explicit inputs.

The file-list counterpart of sensor_for_directory(). Resolves inputs (files, directories, and/or globs) into a list of candidate camera files, then returns an instance of the first registered reader whose SensorMetadata.detect_files() matches — fallback readers last, so a delivery’s images cannot outrank its own camera XMLs.

Parameters:

inputs (str or os.PathLike or iterable of those) – One or more files, directories, and/or glob patterns.

Returns:

An initialized reader for the detected sensor.

Return type:

SensorMetadata

Raises:

ValueError – If no candidate files are found, or no registered sensor reader matches them.

asp_plot.sensors.SENSORS#