asp_plot.sensors.rpc#

Derived stereo geometry for RPC-only products (Cartosat-1, Deimos, …).

ASP processes a long tail of products with -t rpc: the camera model is a set of rational polynomial coefficients embedded in the image header (NITF, GeoTIFF) or delivered in a *_RPC.TXT sidecar, and nothing else. There is no ephemeris, no attitude, no acquisition summary — nothing a reader could parse. But as with ASTER (asp_plot.sensors.aster), “nothing to parse” is not “nothing to plot”: an RPC is a camera model, so the geometry can be derived from it (#177).

The derivation rests on one observation: projecting the same pixel to the ground at two different heights traces that pixel’s look ray. From there,

  • the footprint is the image border projected at HEIGHT_OFF;

  • the satellite azimuth/elevation is the centre pixel’s look ray expressed in the local east/north/up frame at its ground point — the DigitalGlobe MEANSATAZ/MEANSATEL convention the pair math (convergence angle, B:H, BIE) already speaks;

  • the perspective centre — where the satellite actually was — is the intersection of two look rays from opposite ends of the same image line, and gives the off-nadir view angle and an approximate position track;

  • the GSD is the ground spacing of one pixel at the scene centre.

Accuracy is not assumed, it is measured. Every derived quantity is pinned in tests/test_sensors.py against the vendor’s own numbers in the committed WorldView camera XMLs, whose RPB blocks carry real RPC00B coefficients for scenes whose MEANSATAZ/MEANSATEL/MEANOFFNADIRVIEWANGLE/ MEANPRODUCTGSD are recorded independently: azimuth matches to 0.01°, elevation and off-nadir to 0.15°, GSD to 1 cm.

Two things are deliberately not derived:

  • meanintrackviewangle / meancrosstrackviewangle. Splitting the off-nadir angle into along- and across-track parts needs a velocity direction, and the only one available here is the drift of the recovered perspective centres — over the ~15 km of track one scene spans, their kilometre-level noise tilts that direction by 8–10° (measured against the vendor ephemeris). The total off-nadir angle needs no velocity and is accurate, so it is reported and the split is left as “not provided” (#163).

  • Time. RPCs carry no timestamps. date is recovered from the image header when the container records one (NITF IDATIM, TIFF DateTime) and is otherwise None, which the pair code renders as “N/A”.

att_df is None (no attitude exists) and eph_gdf, when the perspective centres are recoverable, is indexed by image line rather than time — the same contract ASTER established.

Attributes#

Classes#

RpcMetadata

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

Functions#

read_rpc(image_fn)

Read the RPC camera model and grid size of an image.

Module Contents#

class asp_plot.sensors.rpc.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'#
asp_plot.sensors.rpc.read_rpc(image_fn)#

Read the RPC camera model and grid size of an image.

Tries the image header first (GDAL exposes embedded RPCs, and finds a <stem>_RPC.TXT sidecar on its own), then falls back to parsing a sidecar directly — which is what turns Cartosat-1’s _RPC_ORG.TXT deliveries into readable products.

Rasters that are already map-projected are rejected even when they carry RPCs: an RPC describes the raw image grid, so on an orthorectified product it no longer corresponds to the pixels it would be evaluated against. This is not hypothetical — ASP’s mapproject copies the RPC metadata through, so a *_map.tif carries both a CRS and RPCs and would otherwise be claimed and given a silently wrong footprint.

The mirror-image worry — an ASP stereo product that inherited RPCs but no CRS, and so slipped past that guard — does not arise: across two real RPC-session runs (52 rasters: -L/-R/-D/-F/-RD/-PC, the _sub pyramids, masks, DEM, GoodPixelMap, -stats), not one carries RPCs. Neither does wv_correct’s *_corr.tif. Only the raw delivered images do, which is exactly what this reader wants.

Parameters:

image_fn (str) – Path to an image file.

Returns:

(rpc, width, height, tags) — a rasterio.rpc.RPC, the image’s pixel dimensions and its metadata tags — or None if the file is not an unprojected raster carrying RPCs.

Return type:

tuple or None

asp_plot.sensors.rpc.logger#