curryer.correction.pairing¶
Utilities for pairing L1A images with nearby GCP chips.
The routines in this module describe each image footprint using the
NamedImageGrid metadata, convert the corners to a local East-North-Up frame,
and compute the distance between a GCP center point and the nearest edge of
each L1A footprint. The core entry point is find_l1a_gcp_pairs(), which
returns a many-to-many mapping between the supplied L1A and GCP collections.
File-based utilities (discover_gcp_files, pair_files) provide higher-level
wrappers for working with .mat or NetCDF .nc files on disk.
Attributes¶
Classes¶
Metadata describing an image footprint. |
|
Metadata describing a GCP image footprint. |
|
Relationship between an L1A image and a GCP chip. |
|
Container for the output of |
Functions¶
|
Return the rotation matrix from ECEF deltas to local ENU |
|
Convert geodetic coordinates to local ENU (East–North–Up) coordinates. |
|
Find all L1A/GCP pairs within a distance threshold. |
|
Find all GCP files in a directory matching a pattern. |
|
Find L1A-GCP pairs based on spatial overlap and return as file path tuples. |
Find GCP chip files that spatially overlap an in-memory geolocated dataset. |
Module Contents¶
- curryer.correction.pairing.logger¶
- curryer.correction.pairing.enu_rotation_matrix(lat_deg: float, lon_deg: float) numpy.ndarray¶
Return the rotation matrix from ECEF deltas to local ENU (East–North–Up, local tangent-coordinate frame).
- Parameters:
lat_deg (float) – Geodetic latitude of the origin in degrees.
lon_deg (float) – Geodetic longitude of the origin in degrees.
- Returns:
Matrix that converts an ECEF delta vector into east, north, and up components with respect to the specified origin.
- Return type:
ndarray, shape (3, 3)
- curryer.correction.pairing.geodetic_to_enu(lat_deg: numpy.ndarray, lon_deg: numpy.ndarray, h_m: numpy.ndarray, origin_lat_deg: float, origin_lon_deg: float, origin_h_m: float = 0.0) numpy.ndarray¶
Convert geodetic coordinates to local ENU (East–North–Up) coordinates.
- Parameters:
lat_deg (array_like) – Geodetic latitude and longitude (degrees) of the points to convert.
lon_deg (array_like) – Geodetic latitude and longitude (degrees) of the points to convert.
h_m (array_like) – Heights above the WGS-84 ellipsoid (meters) for each point.
origin_lat_deg (float) – Geodetic latitude/longitude of the ENU frame origin in degrees.
origin_lon_deg (float) – Geodetic latitude/longitude of the ENU frame origin in degrees.
origin_h_m (float, optional) – Height of the origin point in meters. Defaults to
0.
- Returns:
East, north, and up coordinates (meters) of the input points relative to the specified origin.
- Return type:
ndarray, shape (…, 3)
- class curryer.correction.pairing.ImageMetadata¶
Metadata describing an image footprint.
- Parameters:
index – Position of the image inside the original input list.
name – Identifier associated with the image (e.g., filename).
corners – Four corner latitude/longitude tuples ordered clockwise.
center – Latitude/longitude of the image center pixel.
bbox – Bounding box expressed as
(lat_min, lat_max, lon_min, lon_max).
- index: int¶
- name: str¶
- corners: list[tuple[float, float]]¶
- center: tuple[float, float]¶
- bbox: tuple[float, float, float, float]¶
- corner_array() numpy.ndarray¶
Return the corner coordinates as a
(4, 2)NumPy array.
- class curryer.correction.pairing.GCPMetadata¶
Bases:
ImageMetadataMetadata describing a GCP image footprint.
Extends
ImageMetadatawith the ECEF coordinates of the GCP center point to simplify subsequent distance calculations.- center_point_ecef: numpy.ndarray¶
- class curryer.correction.pairing.PairMatch¶
Relationship between an L1A image and a GCP chip.
The
distance_mfield stores the signed margin between the GCP center and the closest edge of the L1A footprint in meters. Positive values indicate the center lies inside the footprint, while negative values mean it lies outside.- l1a_index: int¶
- gcp_index: int¶
- distance_m: float¶
- class curryer.correction.pairing.PairingResult¶
Container for the output of
find_l1a_gcp_pairs().- l1a_images: list[ImageMetadata]¶
- gcp_images: list[GCPMetadata]¶
- curryer.correction.pairing.find_l1a_gcp_pairs(l1a_images: collections.abc.Iterable[curryer.correction.grid_types.NamedImageGrid], gcp_images: collections.abc.Iterable[curryer.correction.grid_types.NamedImageGrid], max_distance_m: float) PairingResult¶
Find all L1A/GCP pairs within a distance threshold.
- Parameters:
l1a_images – Iterable of
NamedImageGridinstances representing L1A imagery.gcp_images – Iterable of
NamedImageGridinstances representing GCP chips.max_distance_m – Minimum margin (meters) required between the GCP center and the nearest L1A edge. Only pairs with
margin >= max_distance_mare returned.
- Returns:
Metadata for the supplied images together with any pairs that fall within
max_distance_m.- Return type:
- curryer.correction.pairing.discover_gcp_files(gcp_directory: pathlib.Path, pattern: str = '*_resampled.mat') list[pathlib.Path]¶
Find all GCP files in a directory matching a pattern.
- Parameters:
gcp_directory – Directory to search
pattern – Glob pattern for GCP files (default: “*_resampled.mat”)
- Returns:
Sorted list of Path objects for GCP files
Example
>>> gcp_files = discover_gcp_files(Path("tests/data/clarreo/image_match")) >>> print(f"Found {len(gcp_files)} GCP files")
- curryer.correction.pairing.pair_files(l1a_files: list[pathlib.Path], gcp_directory: pathlib.Path, max_distance_m: float = 0.0, l1a_key: str = 'subimage', gcp_key: str = 'GCP', gcp_pattern: str = '*_resampled.mat') list[tuple[pathlib.Path, pathlib.Path]]¶
Find L1A-GCP pairs based on spatial overlap and return as file path tuples.
Both
.matand NetCDF (.nc) files are supported for L1A observations and GCP chips. The format is detected automatically from the file extension byload_named_image_grid().- Parameters:
l1a_files – List of L1A (or observation) file paths to pair. Supports
.matand.ncfiles.gcp_directory – Directory containing GCP reference files.
max_distance_m – Minimum margin for valid pairing (default: 0.0) - 0.0: Requires GCP center inside L1A footprint (strict) - >0: Allows GCP center up to this distance inside footprint - <0: Allows GCP center outside footprint (loose)
l1a_key – MATLAB struct key for L1A data (default: “subimage”). Ignored for NetCDF files.
gcp_key – MATLAB struct key for GCP data (default: “GCP”). Ignored for NetCDF files.
gcp_pattern – File pattern for GCP discovery (default: “*_resampled.mat”; use “*_regridded.nc” for NetCDF chips).
- Returns:
List of (l1a_file, gcp_file) tuples for all valid spatial pairs. One L1A can pair with multiple GCPs (many-to-many).
- Raises:
FileNotFoundError – If gcp_directory doesn’t exist.
ValueError – If no valid pairs found.
Example
>>> # .mat subimages paired with .mat GCPs (original behaviour) >>> pairs = pair_files(mat_files, Path("gcp_chips"))
>>> # NetCDF observations paired with regridded NetCDF GCP chips >>> pairs = pair_files( ... nc_obs_files, Path("gcp_chips"), ... gcp_pattern="*_regridded.nc", ... )
- curryer.correction.pairing.pair_geolocated_dataset_with_gcp_files(geolocated_data: xarray.Dataset, gcp_files: list[pathlib.Path], max_distance_m: float = 0.0, gcp_key: str = 'GCP') list[pathlib.Path]¶
Find GCP chip files that spatially overlap an in-memory geolocated dataset.
This is the in-memory-observation counterpart of
pair_files(). Both delegate to the same core spatial-pairing algorithm (find_l1a_gcp_pairs()) with proper ENU-distance polygon containment, ensuring a single implementation for all GCP pairing.- Parameters:
geolocated_data (xr.Dataset) – Already-geolocated observation dataset with
latitudeandlongitudevariables.gcp_files (list[Path]) – GCP chip file paths to test for spatial overlap.
max_distance_m (float, optional) – Minimum signed margin (meters) required between the GCP chip center and the nearest observation footprint edge.
0.0(default) means the GCP center must fall strictly inside the footprint; negative values allow the center to lie outside the footprint by up toabs(max_distance_m)meters.gcp_key (str, optional) – MATLAB struct key used when loading
.matGCP chips. Defaults to"GCP". Ignored for NetCDF files.
- Returns:
Subset of gcp_files whose center-points overlap the observation footprint, ordered by their original position in gcp_files. Empty when no overlap is found or when gcp_files is empty.
- Return type:
list[Path]
Notes
Files that cannot be loaded are silently skipped with a DEBUG log entry. This mirrors the behaviour of
pair_files()for individual files.Examples
>>> gcp_dir = Path("data/gcp_chips") >>> all_chips = sorted(gcp_dir.glob("*_regridded.nc")) >>> matched = pair_geolocated_dataset_with_gcp_files(geo_ds, all_chips, max_distance_m=-500.0) >>> print(f"{len(matched)}/{len(all_chips)} chips overlap the observation footprint")