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 MATLAB .mat files on disk.
Attributes¶
Classes¶
Protocol for GCP pairing functions in Correction pipeline. |
|
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¶
|
Validate that GCP pairing output conforms to expected format. |
|
Return the rotation matrix from ECEF deltas to local ENU |
|
Convert geodetic coordinates to local ENU (East–North–Up) coordinates. |
|
Return the four corner latitude/longitude pairs of |
|
Return the latitude, longitude, and height of the center pixel. |
|
Return the latitude/longitude bounding box of |
|
Return |
|
Return the minimum distance from |
|
Return the distance from a point to a polygon in meters. |
|
Construct |
|
Construct |
|
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. |
Module Contents¶
- curryer.correction.pairing.logger¶
- class curryer.correction.pairing.GCPPairingFunc¶
Bases:
ProtocolProtocol for GCP pairing functions in Correction pipeline.
Pairing functions determine which science observations (L1A images) overlap with which ground control points (GCP reference images).
- Standard Signature:
def pair_gcps(science_keys: List[str]) -> List[Tuple[str, str]]
- Returns:
List of (science_key, gcp_reference_path) tuples, one per valid pair
Note
This is a simplified interface for Correction compatibility. Real implementations (like find_l1a_gcp_pairs below) may use more sophisticated spatial algorithms internally, but must return results in this simple tuple format.
Examples
# Real spatial pairing def spatial_gcp_pairing(science_keys):
l1a_images = load_images(science_keys) gcp_images = discover_gcps() pairs = find_spatial_overlaps(l1a_images, gcp_images) return [(l1a.name, gcp.path) for l1a, gcp in pairs]
# Test/synthetic pairing def synthetic_gcp_pairing(science_keys):
- return [(key, f”synthetic_gcp_{i}.tif”)
for i, key in enumerate(science_keys)]
- __call__(science_keys: list[str]) list[tuple[str, str]]¶
Find GCP pairs for given science observations.
- curryer.correction.pairing.validate_pairing_output(pairs: list[tuple[str, str]]) None¶
Validate that GCP pairing output conforms to expected format.
- Parameters:
pairs – List of (science_key, gcp_path) tuples
- Raises:
TypeError – If structure is invalid
ValueError – If tuple elements have wrong types
Example
>>> pairs = gcp_pairing_func(["sci_001", "sci_002"]) >>> validate_pairing_output(pairs)
- 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._image_corners(image: curryer.correction.data_structures.ImageGrid) list[tuple[float, float]]¶
Return the four corner latitude/longitude pairs of
image.
- curryer.correction.pairing._image_center(image: curryer.correction.data_structures.ImageGrid) tuple[float, float, float]¶
Return the latitude, longitude, and height of the center pixel.
- curryer.correction.pairing._image_bbox(image: curryer.correction.data_structures.ImageGrid) tuple[float, float, float, float]¶
Return the latitude/longitude bounding box of
image.
- curryer.correction.pairing._point_in_polygon(point_xy: numpy.ndarray, polygon_xy: numpy.ndarray) bool¶
Return
Trueifpoint_xylies insidepolygon_xy.Uses the winding-number algorithm with a ray cast along the positive x-axis.
- curryer.correction.pairing._distance_point_to_segment(point_xy: numpy.ndarray, a_xy: numpy.ndarray, b_xy: numpy.ndarray) float¶
Return the minimum distance from
point_xyto segmentab.
- curryer.correction.pairing._distance_point_to_polygon_m(point_lat: float, point_lon: float, point_h: float, polygon_latlon: collections.abc.Sequence[tuple[float, float]]) float¶
Return the distance from a point to a polygon in meters.
- Parameters:
point_lat – Geodetic coordinates of the query location.
point_lon – Geodetic coordinates of the query location.
point_h – Geodetic coordinates of the query location.
polygon_latlon – Sequence of latitude/longitude tuples describing polygon corners.
- Returns:
Signed distance between the point and the polygon boundary. Positive values indicate the point is inside the polygon and represent the margin to the nearest edge. Negative values indicate the point lies outside the polygon and represent the distance to the closest edge.
- Return type:
float
- curryer.correction.pairing._build_image_metadata(index: int, image: curryer.correction.data_structures.NamedImageGrid) ImageMetadata¶
Construct
ImageMetadataforimage.
- curryer.correction.pairing._build_gcp_metadata(index: int, image: curryer.correction.data_structures.NamedImageGrid) GCPMetadata¶
Construct
GCPMetadataforimage.
- curryer.correction.pairing.find_l1a_gcp_pairs(l1a_images: collections.abc.Iterable[curryer.correction.data_structures.NamedImageGrid], gcp_images: collections.abc.Iterable[curryer.correction.data_structures.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.
This is the production replacement for placeholder_gcp_pairing(). Uses the find_l1a_gcp_pairs() algorithm for spatial matching.
- Parameters:
l1a_files – List of L1A file paths to pair
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”)
gcp_key – MATLAB struct key for GCP data (default: “GCP”)
gcp_pattern – File pattern for GCP discovery (default: “*_resampled.mat”)
- Returns:
List of (l1a_file, gcp_file) tuples for all valid spatial pairs Note: 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
>>> l1a_files = [Path("test1.mat"), Path("test2.mat")] >>> pairs = pair_files(l1a_files, Path("gcp_chips"), max_distance_m=0.0) >>> print(f"Found {len(pairs)} valid L1A-GCP pairs") >>> for l1a, gcp in pairs: ... print(f" {l1a.name} → {gcp.name}")