msi_processor.computing.georeference package#

Geo-referencing / orthorectification stage (C-PU-GEO; DPM-M-GEO; ALG-GEO-*).

Viewing-model geolocation + GSD, ground-control refinement against a geolocated reference, DEM orthorectification, and resampling onto the profile cartographic grid/CRS, emitting the L1C product. The stage is a pure core plus a thin GeoreferenceUnit wrapper. The rigorous viewing-model/DEM collinearity bodies are private/deferred [impl] (ATBD <5.7> open point 2); the PDR-operational path is the reference-image homography (ALG-GEO-GCP) plus cartographic resampling (ALG-GEO-RESAMP).

Submodules#

msi_processor.computing.georeference.core module#

Pure geo-referencing / orthorectification core (C-PU-GEO; ALG-GEO-*).

CPM-free, I/O-free functions implementing the geo-referencing algorithms of ATBD <5.7>, ported faithfully from the heritage georeferencing_v1.py (getSatelliteInfo.get_satellite_info GSD, geoReferencing.band_registration reference matching, reprojection.projection GDAL geotransform/CRS; RD-10). The GPL pyorbital/skyfield TLE fetch and the Earth-Engine Sentinel-2 reference download of the heritage are dropped (SRF; non-redistributable): the orbit/ephemeris state comes from L0c telemetry / a viewing-model ADF and the geolocated reference comes from a GCP ADF, never from a network fetch.

Library policy. The cartographic-grid resampling (ALG-GEO-RESAMP) is defined by the GDAL/PROJ affine-geotransform + reprojection machinery in the baselined design (ATBD <5.7>, SDD <5.4.7>); it is realised here with rasterio/affine (the maintained GDAL Python binding; rasterio is already an eopf transitive dependency). The ground-control refinement (ALG-GEO-GCP) reuses the OpenCV feature/homography machinery of core against a geolocated reference, exactly as the SDD prescribes (“reuse coregistration.core”).

Implementation status. Two bodies are private/deferred and left as clean, well-typed [impl] stubs (they require the proprietary sensor model and are the CDR target, ATBD <5.7> open point 2):

  • orbit_state() – orbit/ephemeris propagation engine (the dropped GPL TLE path); and

  • orthorectify() – the rigorous per-pixel collinearity / DEM line-of-sight intersection (SDD geolocate; ALG-GEO-ORTHO).

The PDR-operational path realised here is the heritage reference-image homography (gcp_refine()) plus the profile cartographic-grid assignment/resampling (build_geotransform(), assign_grid(), resample_to_grid()); a proprietary sensor model is not fabricated.

Geometry convention. Image arrays are 2-D; up to the GCP refinement they are in instrument geometry (line, detector); from the cartographic grid they are (y, x) (DPM <8.6>). A GDAL geotransform [ulx, xres, 0, uly, 0, -yres] places the grid; pixel (col, row) upper-left maps to (ulx + col*xres, uly - row*yres) and the cell centre to (ulx + (col+0.5)*xres, uly - (row+0.5)*yres) (ATBD <5.7> ALG-GEO-RESAMP).

Trace: REQ-F-GEO-01..04; DPM-M-GEO; ALG-GEO-ORBIT/GSD/GCP/ORTHO/RESAMP.

class msi_processor.computing.georeference.core.GcpRefinement(n_gcp, rms_residual_px, homography)#

Bases: object

Outcome of a ground-control refinement (ALG-GEO-GCP; ICD-IF-DIAG).

Parameters:
n_gcp:

Number of inlier ground-control tie points supporting the correction.

rms_residual_px:

Root-mean-square inlier reprojection residual in pixels.

homography:

The 3x3 image -> reference planimetric correction (float64).

homography: ndarray[tuple[Any, ...], dtype[float64]]#
n_gcp: int#
rms_residual_px: float#
class msi_processor.computing.georeference.core.GeoreferenceParams(resolution, crs_wkt='', resampling='bilinear', use_gcp=True, min_gcp=8, coreg=<factory>)#

Bases: object

Tunable geo-referencing parameters (SDD <5.4.7>; DPM-PRM-GEO-01..03).

Parameters:
resolution:

Output cartographic grid resolution (GSD) in map units (DPM-PRM-GEO-01; heritage ~6.5 m).

crs_wkt:

Target CRS as WKT (DPM-PRM-GEO-01); empty string inherits the CRS of the geolocated GCP reference (heritage behaviour).

resampling:

Cartographic resampling kernel (ALG-GEO-RESAMP; default bilinear).

use_gcp:

Enable the ground-control refinement against the geolocated reference (DPM-PRM-GEO-03). When False the rigorous viewing-model/DEM geolocation (orthorectify()) is required, which is [impl].

min_gcp:

Minimum number of inlier ground-control tie points required to accept a refinement (the GEO_CE90 acceptance gate, DPM-PRM-GEO-03, private budget); below it the refinement is rejected fail-stop.

coreg:

Feature-matching parameters for the GCP homography (reuses CoregParams; its reference_band is unused on the two-image GCP path).

coreg: CoregParams#
crs_wkt: str = ''#
min_gcp: int = 8#
resampling: Literal['nearest', 'bilinear', 'cubic'] = 'bilinear'#
resolution: float#
use_gcp: bool = True#
class msi_processor.computing.georeference.core.Geotransform(ulx, xres, uly, yres, crs_wkt)#

Bases: object

North-up GDAL affine geotransform + CRS (ALG-GEO-RESAMP; SDD <5.4.7>).

Stores the GDAL 6-tuple [ulx, xres, 0, uly, 0, -yres] decomposed for a north-up grid (zero rotation). xres/yres are stored as positive pixel sizes; the south-ward row step -yres is applied by to_affine().

Parameters:
ulx, uly:

Map coordinates of the upper-left corner of the upper-left pixel.

xres, yres:

Pixel size in map units (positive); the grid is north-up so the row direction decreases Y by yres per row.

crs_wkt:

Target CRS as a WKT string (PROJ/osr encoding).

Attributes:
gdal_tuple

Return the GDAL 6-tuple (ulx, xres, 0, uly, 0, -yres).

Methods

to_affine()

Return the equivalent affine.Affine (north-up GDAL order).

crs_wkt: str#
property gdal_tuple: tuple[float, float, float, float, float, float]#

Return the GDAL 6-tuple (ulx, xres, 0, uly, 0, -yres).

to_affine()#

Return the equivalent affine.Affine (north-up GDAL order).

Return type:

Affine

ulx: float#
uly: float#
xres: float#
yres: float#
class msi_processor.computing.georeference.core.GridSpec(geo, x, y)#

Bases: object

A placed cartographic grid: its geotransform and cell-centre axes.

The 1-D x/y axes are the cell-centre coordinates the wrapper writes to /conditions/geolocation/{x,y} (the CRS is Geotransform.crs_wkt, written to /conditions/geolocation/spatial_ref); REQ-F-GEO-04.

Parameters:
geo:

The Geotransform placing the grid.

x, y:

Cell-centre coordinate axes, float64 of length width / height.

Attributes:
shape

Return the grid (height, width) = (len(y), len(x)).

geo: Geotransform#
property shape: tuple[int, int]#

Return the grid (height, width) = (len(y), len(x)).

x: ndarray[tuple[Any, ...], dtype[float64]]#
y: ndarray[tuple[Any, ...], dtype[float64]]#
class msi_processor.computing.georeference.core.PlatformState(lat, lon, altitude_m, ground_velocity_ms)#

Bases: object

Platform / orbit state at acquisition (ALG-GEO-ORBIT; SDD <5.4.7>).

Parameters:
lat, lon:

Sub-satellite point latitude/longitude in degrees at acquisition.

altitude_m:

Platform altitude above the ellipsoid in metres (drives ALG-GEO-GSD).

ground_velocity_ms:

Ground-track velocity in m/s (line-timing kinematics, ATBD <5.7>).

altitude_m: float#
ground_velocity_ms: float#
lat: float#
lon: float#
msi_processor.computing.georeference.core.ResamplingMethod#

Supported cartographic resampling kernels (ATBD <5.7> ALG-GEO-RESAMP).

alias of Literal[‘nearest’, ‘bilinear’, ‘cubic’]

msi_processor.computing.georeference.core.assign_grid(shape, geo)#

ALG-GEO-RESAMP – derive the cell-centre axes of a placed grid.

For a grid of shape = (height, width) placed by geo the cell-centre coordinates are :rtype: GridSpec

\[x_c = \mathrm{ulx} + (c + 0.5)\,\mathrm{xres},\qquad y_r = \mathrm{uly} - (r + 0.5)\,\mathrm{yres},\]

the /conditions/geolocation/{x,y} layers of the L1C product (REQ-F-GEO-04).

Parameters:
shape:

Target grid (height, width).

geo:

The Geotransform placing the grid.

Returns:
GridSpec

The geotransform and the float64 cell-centre x/y axes.

msi_processor.computing.georeference.core.build_geotransform(ulx, uly, resolution, crs_wkt)#

ALG-GEO-RESAMP – build a north-up cartographic geotransform.

Assembles the GDAL affine [ulx, xres, 0, uly, 0, -yres] with square pixels xres = yres = resolution (heritage reprojection.projection built [ulx, 6.5, 0, uly, 0, -6.5] and inherited the reference CRS).

Return type:

Geotransform

Parameters:
ulx, uly:

Upper-left corner map coordinates of the target grid.

resolution:

Target pixel size (GSD) in map units; must be strictly positive.

crs_wkt:

Target CRS as WKT.

Raises:
GeolocationError

If resolution is not strictly positive.

msi_processor.computing.georeference.core.compute_gsd(altitude_m, pixel_pitch_m, focal_length_m)#

ALG-GEO-GSD – ground sampling distance from the pinhole relation. :rtype: float

\[\mathrm{GSD} = \dfrac{H\,p}{f},\]

with platform altitude \(H\) (altitude_m), detector pitch \(p\) (pixel_pitch_m) and focal length \(f\) (focal_length_m); heritage getSatelliteInfo.get_satellite_info. The interior geometry \(p, f\) is private viewing-model content supplied by the wrapper from the viewing_model ADF, never embedded (REQ-AD-01).

Raises:
GeolocationError

If focal_length_m is not strictly positive.

msi_processor.computing.georeference.core.gcp_refine(image, reference, params)#

ALG-GEO-GCP – refine geolocation against a geolocated reference.

Reuses the co-registration feature/homography machinery (estimate_homography()): CLAHE -> SIFT -> FLANN -> RANSAC fits the planimetric homography \(H\) mapping the image to the geolocated reference (heritage geoReferencing.band_registration matching a band against a Sentinel-2 reference), then warps the image onto the reference pixel grid. The number of inlier tie points is gated against GeoreferenceParams.min_gcp.

Return type:

tuple[ndarray[tuple[Any, ...], dtype[Any]], GcpRefinement]

Parameters:
image:

2-D band to be refined (instrument geometry).

reference:

2-D geolocated reference image (its CRS/geotransform come from the GCP ADF and are applied to the output by the wrapper).

params:

Geo-referencing parameters; GeoreferenceParams.coreg supplies the matching tuning and GeoreferenceParams.min_gcp the gate.

Returns:
tuple

(refined_image, GcpRefinement)refined_image is image resampled onto the reference grid (reference (rows, cols) extent), and the GcpRefinement carries the inlier count, residual and H.

Raises:
GeolocationError

If the feature matching cannot fit a homography (wraps the underlying CoregistrationError) or if the inlier count is below GeoreferenceParams.min_gcp (fail-stop, REQ-F-GEO-03).

msi_processor.computing.georeference.core.orbit_state(viewing_model, acq_time)#

ALG-GEO-ORBIT – propagate the orbit/ephemeris to the acquisition epoch.

Returns the sub-satellite point, altitude and ground-track velocity at acq_time from the platform ephemeris referenced by viewing_model.

[impl] – deferred. The heritage propagation used the GPL pyorbital/skyfield TLE path, which is dropped (SRF; non-redistributable); the operational engine consumes L0c telemetry / a private ephemeris ADF and is the CDR target. This stub raises so callers do not silently rely on a fabricated orbit; the wrapper sources the altitude/sub-point from telemetry kwargs and feeds compute_gsd() directly this increment.

Return type:

PlatformState

Raises:
GeolocationError

Always, until the ephemeris-propagation engine is wired in.

msi_processor.computing.georeference.core.orthorectify(image, state, viewing_model, dem)#

ALG-GEO-ORTHO – rigorous collinearity / DEM orthorectification.

The rigorous target model intersects each detector line-of-sight with the ellipsoid + DEM via the collinearity relation (ATBD <5.7>): for ground point \(\mathbf X\), platform position \(\mathbf X_0\), attitude \(R(\omega,\varphi,\kappa)\) and interior geometry, :rtype: ndarray[tuple[Any, ...], dtype[Any]]

\[\begin{split}\begin{bmatrix}x\\y\\-f\end{bmatrix} = \lambda\,R^{\!\top}\big(\mathbf X-\mathbf X_0\big),\qquad Z=\mathrm{DEM}(X,Y),\end{split}\]

solved per pixel so terrain-induced displacement is removed (SDD geolocate).

[impl] – deferred. The rigorous sensor model and the DEM line-of-sight intersection require the proprietary viewing-model coefficients and are the CDR target (ATBD <5.7> open point 2). A proprietary model is not fabricated here; the PDR-operational geolocation is the reference-image homography of gcp_refine() followed by resample_to_grid(). This stub raises so the no-GCP path fails loudly rather than emitting an un-orthorectified product as if it were rigorous.

Raises:
GeolocationError

Always, until the rigorous collinearity/DEM model is wired in.

msi_processor.computing.georeference.core.resample_to_grid(image, src_geo, dst_geo, dst_shape, resampling='bilinear')#

ALG-GEO-RESAMP – resample a band onto the profile cartographic grid.

Warps image from its source geotransform/CRS to the destination cartographic grid via rasterio.warp.reproject (the maintained GDAL/PROJ binding), the operational realisation of ATBD <5.7> ALG-GEO-RESAMP.

Return type:

ndarray[tuple[Any, ...], dtype[Any]]

Parameters:
image:

2-D source band; its dtype is preserved on output.

src_geo:

Source geotransform + CRS (e.g. the GCP-reference grid).

dst_geo:

Target cartographic geotransform + CRS (profile grid).

dst_shape:

Output (height, width). Required because reproject writes into a pre-allocated destination (deviation from the SDD sketch, which elides the explicit extent); the wrapper derives it from the source extent and the target resolution.

resampling:

Resampling kernel ("nearest" | "bilinear" | "cubic").

Returns:
numpy.ndarray

The resampled band, dtype-preserving, of shape dst_shape.

msi_processor.computing.georeference.unit module#

Thin EOProcessingUnit wrapper for geo-referencing / ortho (C-PU-GEO).

Adapts the pure core to the EOPF CPM runtime following the wrapper template of SDD <5.4.1>/<5.4.7>: read parameters, extract the co-registered bands, load/validate ADFs, orchestrate the pure-core functions, propagate QA, and build the output L1C EOProduct on the profile cartographic grid. No algorithm lives here.

Input convention. The upstream stage is the coregistration unit; its cor product carries the band-aligned measurements under measurements/<rep>/<band> (rep = radiance and/or reflectance) and QA under quality/mask/<band> (IF-PROD-03). Every present measurement representation is geo-referenced with the same planimetric correction so the stack stays consistent; L1C is the orthorectified TOA reflectance on the cartographic grid (DPM <8.6>).

ADF data convention (this increment). ADF content is read from the AuxiliaryDataFile.data_ptr mapping (the CPM data_ptr holds the opened data):

  • viewing_model -> {"pixel_pitch_m": float, "focal_length_m": float, ...} (mandatory; interior geometry for ALG-GEO-GSD and the rigorous LOS model, ICD <5.3.2>A). The rigorous viewing-model body is [impl]; presence/coverage is enforced here (REQ-F-GEO-01, fail-stop on absence).

  • dem -> {"elevation": ndarray2d, "geotransform": [6], "crs_wkt": str} (mandatory; consumed by the rigorous orthorectification, which is [impl]; presence/coverage is enforced here, REQ-F-GEO-02).

  • gcp -> {"image": ndarray2d, "geotransform": [ulx,xres,0,uly,0,-yres], "crs_wkt": str} (optional; required when use_gcp is set: the geolocated reference for ALG-GEO-GCP).

Implementation status (ATBD <5.7> open point 2). The rigorous viewing-model + DEM collinearity geolocation (orthorectify()) is the CDR target and is left [impl]. The PDR-operational path realised here is the heritage reference-image homography (ALG-GEO-GCP) plus profile cartographic-grid resampling (ALG-GEO-RESAMP); it therefore requires use_gcp=True and the gcp ADF. With use_gcp=False the unit invokes the [impl] rigorous path, which fail-stops with a clear GeolocationError.

Fail-stop (REQ-F-GEO-03). Missing DEM/viewing-model coverage, a missing GCP reference when refinement is enabled, or too few ground-control points raise GeolocationError; it propagates to the chain runner so no mis-geolocated product is emitted.

Mandatory inputs/ADFs are declared by the CPM computing-model JSON (models/msi_georeference_1.0.0.json), not by overriding the list methods.

Trace: REQ-F-GEO-01..04; DPM-M-GEO; ALG-GEO-*; ICD IF-PROD-03, REQ-IF-OUT-02.

class msi_processor.computing.georeference.unit.GeoreferenceUnit(identifier='')#

Bases: EOProcessingUnit

Geo-referencing / orthorectification processing unit (C-PU-GEO; SDD <5.4.7>).

Attributes:
identifier

Identifier of the processing step

Methods

run:

Geolocate the co-registered stack (GCP refinement against the geolocated reference, then cartographic-grid resampling) and emit the L1C product with CRS + geolocation layers and QA. The rigorous viewing-model/DEM orthorectification is [impl] (ATBD <5.7> open point 2).

PROCESSOR_LEVEL = 'L1C'#
PROCESSOR_MODEL = True#
PROCESSOR_NAME = 'msi_georeference'#
PROCESSOR_VERSION = '1.0.0'#
run(inputs, adfs=None, mode=None, **kwargs)#

Run the geo-referencing.

Return type:

Mapping[str, Union[EOProduct, EOContainer, DataTree, Iterable[Union[EOProduct, EOContainer, DataTree]]]]

Parameters:
inputs:

{"cor": EOProduct} with co-registered bands under measurements/<rep>/<band> and optional QA under quality/mask/<band>.

adfs:

viewing_model (mandatory), dem (mandatory), gcp (optional; required when use_gcp is set).

mode:

"nominal" (the only supported mode).

**kwargs:

GeoreferenceParams fields – resolution (mandatory), crs (target CRS WKT; empty inherits the GCP-reference CRS), resampling, use_gcp, min_gcp – plus GCP matching tuning (match_fraction, ransac_tau, min_keypoints, seed), an optional gcp_reference_band, and an optional name for the output product.

Returns:
Mapping[str, DataType]

{"l1c": EOProduct} with gridded measurements/<rep>/<band>, conditions/geolocation/{x,y,spatial_ref} and quality/mask/<band>.

Raises:
GeolocationError

On missing DEM/viewing-model coverage, a missing GCP reference when refinement is enabled, too few ground-control points, or the [impl] rigorous path (use_gcp=False) – fail-stop (REQ-F-GEO-03).