aws.osml.image_processing

Pixel-level operations on overhead imagery. This package covers reading and stitching blocks from tiled sources, resampling between resolutions, display range adjustment (DRA), SAR complex-to-display remap, image pyramid construction, warping and orthorectification, chipping with associated metadata, and map tile generation. It does not include sensor model math (see photogrammetry), metadata/TRE parsing (see metadata), or feature geolocation (see features).

Package dependencies

image_processing imports photogrammetry for sensor model interfaces used in orthorectification and warping operations. It imports formats for SICD/SIDD XML updaters that keep chip metadata consistent after sub-setting. It does not depend on metadata, elevation, or features.

Design abstractions

ImageAssetProvider (duck-typed protocol) is the universal source contract. Any object that exposes get_block(row, col, resolution_level, bands), num_rows, num_columns, num_bands, pixel_value_type, block_grid_size, and metadata satisfies the protocol. All adapters produce and consume this interface so they compose freely.

Adapter/Decorator pattern. Providers wrap other providers to layer behavior — caching, retiling, downsampling, applying a function, or warping. Pipelines are built by stacking adapters; no inheritance hierarchy is required.

ProcessingChain is a composable sequence of ndarray -> ndarray callables with output metadata. Chains are callable, nestable via compose(), and applied to pixels after reading.

TiledImagePyramid groups providers into a multi-resolution stack (level 0 = full resolution). It is the read-side entry point for resolution-aware access.

GridBuilder (ABC) defines how output tile grids map back to source pixel coordinates.

Block-oriented I/O. All pixel access flows through get_block(). Random-access windows are assembled from blocks internally. Arrays are always CHW (channels, height, width).

Adapter composition

        flowchart LR
    A[Source Asset] --> B[RetiledProvider]
    B --> C[CachedProvider]
    C --> D[MappedProvider]
    D --> E[TiledImagePyramid]
    E --> F[WarpedImageProvider]
    F --> G[ChipFactory]
    

Display pipeline

        flowchart LR
    A[raw CHW pixels] --> B[ProcessingChain]
    B --> C[band_select]
    C --> D["DRA / LUT"]
    D --> E[uint8 display output]
    

Contributor rules

New pixel operations should be implemented as an ndarray -> ndarray function usable as a ProcessingChain step, or as a new ImageAssetProvider adapter wrapping an existing provider. New output formats require a ChipMetadataBuilder subclass. Maintain the duck-typed provider protocol — do not introduce a base class import requirement.

Chip Factory

class aws.osml.image_processing.ChipFactory(source, sensor_model=None, output_format='nitf', processing_chain=None, metadata_builder=None, metadata_overrides=None)

Bases: object

Orchestrator for extracting and encoding image chips.

Selects the appropriate pyramid level, reads pixels via read_window(), optionally applies a processing chain, resizes to the requested output dimensions, and encodes the result.

Thread-safe for concurrent create_chip() calls.

create_chip(src_window, output_size=None)

Extract and encode a chip.

Parameters:
  • src_window (PixelWindow) – Pixel window in R0 coordinates.

  • output_size (Optional[ImageSize]) – Optional output dimensions. When different from src_window dimensions, the best pyramid level is selected and a final resize is applied after the processing chain.

Return type:

Optional[bytearray]

Returns:

Encoded image bytes, or None when the window region contains no pixel data (sparse/empty blocks).

Raises:

ValueError – Invalid window dimensions (negative or zero), or SICD source with scaled output requested in NITF format.

Map Tile Sets

class aws.osml.image_processing.MapTileSetFactory

Bases: object

This class provides a means to construct / access the implementation of well known tile sets using their name. It allows clients to easily work with the TileSet abstraction independent of any implementation details associated with specific tile sets.

static get_for_id(tile_matrix_set_id)

Constructs a tile set matching the requested id.

Parameters:

tile_matrix_set_id (str) – the tile set id

Return type:

Optional[MapTileSet]

Returns:

the TileSet or None if not available

class aws.osml.image_processing.WellKnownMapTileSet(value)

Bases: str, Enum

A partial list of well known tile sets used by this library.

WEB_MERCATOR_QUAD = 'WebMercatorQuad'
WEB_MERCATOR_QUAD_X2 = 'WebMercatorQuadx2'
class aws.osml.image_processing.MapTileSet

Bases: ABC

This class provides an abstract interface to a well known set of map tiles.

abstract property tile_matrix_set_id: str

Get the identifier for this map tile set. This is the tile matrix set ID in the OGC definitions.

Returns:

the tile matrix set ID

abstract property crs_id: str

Authority identifier for this tile set’s native CRS.

Examples: “EPSG:3857”, “EPSG:4326”, “EPSG:32637”.

abstract get_tile(tile_id)

Get a description of the tile identified by a specific map tile ID.

Parameters:

tile_id (TildId) – the tile ID

Return type:

MapTile

Returns:

the tile description

abstract get_tile_for_location(world_coordinate, tile_matrix)

Get a description of the tile containing a specific world location.

Parameters:
  • world_coordinate (GeodeticWorldCoordinate) – the location in the world

  • tile_matrix (int) – the tile_matrix or zoom level of interest

Return type:

MapTile

Returns:

the tile description

get_tile_matrix_limits_for_area(boundary_coordinates, tile_matrix)

Get the tile limits that intersect a specific area.

Parameters:
Return type:

tuple[int, int, int, int]

Returns:

the (min_row, min_col, max_row, max_col) limits of tiles containing all points

class aws.osml.image_processing.MapTile(id, size, bounds, native_bounds=(0.0, 0.0, 0.0, 0.0))

Bases: object

This dataclass provides a description of a map tile that is part of a well known tile set.

id: TildId
size: MapTileSize
bounds: MapTileBounds
native_bounds: Tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0)
aws.osml.image_processing.MapTileId

alias of TildId

Complex Imagery Remap

aws.osml.image_processing.is_complex(source)

Check if an ImageAssetProvider contains complex-valued pixel data.

Uses definitive indicators from the image subheader only — no false positives on SAR-derived display products (SIDD, detected ISAR). Checks are ordered first-match-wins by reliability.

Checks:
  1. pixel_value_type contains “COMPLEX” → True

  2. ICAT == “SARIQ” → True

  3. Band subcategories contain both “I” and “Q” → True

  4. Band subcategories contain “M” and “P” with ICAT in (“SAR”, “SARIQ”, “ISAR”) → True

  5. IREP == “POLAR” and ICAT == “SAR” → True

Does NOT trigger on:
  • ICAT=SAR alone (SIDD and other SAR-derived products)

  • IREP=POLAR with ICAT in (CCD, WIND, CURRENT)

Parameters:

source (Any) – An ImageAssetProvider with pixel_value_type, num_bands, and metadata attributes.

Return type:

bool

Returns:

True if the source contains complex-valued pixel data.

class aws.osml.image_processing.ComplexRemapFactory

Bases: object

Builds MappedImageProviders that convert complex pixels to scalar magnitude.

static build(source, band_interpretation=None, amplitude_table=None, remap='quarter_power', cache=None)

Wrap a complex-valued asset with a domain transform.

Parameters:
  • source (Any) – ImageAssetProvider with complex pixel data.

  • band_interpretation (Optional[Sequence[str]]) – Per-band semantic role list. Length must equal source.num_bands. Valid roles: “real”, “imaginary”, “magnitude”, “phase”, “amplitude_index”. When None, inferred from source: complex dtype → native complex path; 2-band numeric → defaults to [“real”, “imaginary”].

  • amplitude_table (Optional[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]]) – Lookup table for “amplitude_index” bands. Required when “amplitude_index” appears in band_interpretation; must be None otherwise.

  • remap (Union[str, Callable[[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]], ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]]]) – Remap preset name (“quarter_power”, “magnitude”) or a custom callable. Custom callables receive normalized float I/Q as (2, H, W) float32 and must return (1, H, W) float32.

  • cache (Optional[Any]) – Optional shared TileCache for caching remapped blocks.

Return type:

Any

Returns:

A MappedImageProvider reporting num_bands=1, pixel_value_type=”FLOAT32”.

Raises:

ValueError – If parameters are internally inconsistent.

aws.osml.image_processing.load_complex_remap(reader, asset_key=None, remap='quarter_power', cache=None)

Extract metadata from reader and build a complex remap provider.

Iterates all DES assets, identifies SICD XML by DESSHTN namespace (”urn:SICD:*”), extracts PixelType and AmpTable. Falls back to NITF image subheader fields (ICAT, IREP, ISUBCAT, PVTYPE) when no SICD DES is present. Maps all metadata to a band_interpretation list and delegates to ComplexRemapFactory.build().

Parameters:
Return type:

Any

Returns:

A MappedImageProvider reporting num_bands=1, pixel_value_type=”FLOAT32”.

Raises:

ValueError – If a valid band_interpretation cannot be determined.

aws.osml.image_processing.quarter_power_remap(block)

Normalized float I/Q → fourth root of power (sqrt(sqrt(I² + Q²))).

Produces a roughly Gaussian distribution suitable for DRA.

Parameters:

block (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Canonical (2, H, W) float32 I/Q array.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

(1, H, W) float32 scalar magnitude.

aws.osml.image_processing.magnitude_remap(block)

Normalized float I/Q → sqrt(I² + Q²).

Linear magnitude — preserves relative intensity relationships.

Parameters:

block (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Canonical (2, H, W) float32 I/Q array.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

(1, H, W) float32 scalar magnitude.

aws.osml.image_processing.decode_to_iq(data, band_interpretation=None, amplitude_table=None)

Normalize raw pixel data to canonical (2, H, W) float32 I/Q form.

Handles all supported complex encodings: real/imaginary pairs, amplitude-index/phase (with lookup table), magnitude/phase (polar), and native complex dtypes.

Parameters:
  • data (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Raw pixel block. Shape must be (2, H, W) for two-band interpretations or (1, H, W) / (H, W) for native complex dtypes.

  • band_interpretation (Optional[Sequence[str]]) – Per-band semantic role list. Valid roles: “real”, “imaginary”, “magnitude”, “phase”, “amplitude_index”. When None, inferred from dtype (complex → native complex path; 2-band numeric → defaults to [“real”, “imaginary”]).

  • amplitude_table (Optional[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]]) – Lookup table for “amplitude_index” bands. Required when “amplitude_index” appears in band_interpretation.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

Canonical (2, H, W) float32 array with [0]=real, [1]=imaginary.

Raises:

ValueError – If parameters are inconsistent or data shape is invalid.

aws.osml.image_processing.complex_to_power(data)

Compute pixel power (intensity) from complex or I/Q data.

For native complex dtypes: real² + imag² For (2, H, W) I/Q layout: +

Parameters:

data (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Either a native complex array or (2, H, W) float/int array.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

Real-valued power array. Shape is (H, W) for complex input, (H, W) for (2, H, W) input.

aws.osml.image_processing.power_to_decibels(power)

Convert power values to decibels: 10 * log10(power).

Zeros and negative values produce -inf; use with caution.

Parameters:

power (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Real-valued power array.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

Power in decibels (float32).

SICD/SIDD Updaters

aws.osml.image_processing.sicd_updater.update_sicd_for_chip(xml_str, chip_bounds, output_size=None)

Update SICD XML metadata for a chipped region (stateless).

Parses the provided SICD XML, updates ImageData fields for the chip bounds, and returns the serialized updated XML. Does not mutate any shared state — safe for concurrent calls.

Parameters:
  • xml_str (str) – the SICD XML metadata to update

  • chip_bounds (List[int]) – the [col, row, width, height] of the chip boundary

  • output_size (Optional[Tuple[int, int]]) – the [width, height] of the output chip

Return type:

str

Returns:

updated SICD XML string

Raises:

ValueError – if output_size differs from chip dimensions (SICD does not support decimation)

aws.osml.image_processing.sidd_updater.chipped_coordinate_to_full(chip_coordinate, chip_size, original_corner_coordinates)

Convert pixel locations in a chip to pixel locations in the full image.

Uses a bi-linear interpolation method described in section 5.1.1 of the Sensor Independent Derived Data (SIDD) specification v3.0 Volume 1.

Parameters:
  • chip_coordinate (Tuple[float, float]) – the (col, row) coordinate of the pixel in the chip

  • chip_size (Tuple[int, int]) – the size of the chip (width, height)

  • original_corner_coordinates (List[Tuple[float, float]]) – the (col, row) location of the UL, UR, LR, LL corners in the original image

Return type:

Tuple[float, float]

Returns:

the (col, row) coordinate of the pixel in the original image

aws.osml.image_processing.sidd_updater.update_sidd_for_chip(xml_str, chip_bounds, output_size=None)

Update SIDD XML metadata for a chipped region (stateless).

Parses the provided SIDD XML, updates the GeometricChip structure for the chip bounds, and returns the serialized updated XML. Does not mutate any shared state — safe for concurrent calls.

Parameters:
  • xml_str (str) – the SIDD XML metadata to update

  • chip_bounds (List[int]) – the [col, row, width, height] of the chip boundary

  • output_size (Optional[Tuple[int, int]]) – the [width, height] of the output chip if different from the chip boundary

Return type:

str

Returns:

updated SIDD XML string

Resampling Functions

OpenCV-based resampling functions for image pyramid generation.

This module defines the ResampleFunc type alias, which describes the common signature for every pluggable resampler used by the image pyramid operations (PyramidBuilder, DownsampledImageProvider, build_pyramid_levels). It also provides four thin wrappers around cv2.resizenearest_neighbor_resample(), bilinear_resample(), area_resample(), and lanczos_resample() — covering OpenCV’s most common interpolation modes.

All resamplers in this module follow the same contract:

  • Input and output are in CHW (bands, height, width) layout for 3-D arrays, or (H, W) for 2-D single-band arrays. The returned array preserves the input layout.

  • The input dtype is preserved.

  • The input array is never mutated — a new array is always returned (the identity case returns the input itself, which is still element-wise equal to the input).

  • target_rows and target_cols must be strictly positive.

  • The input must be 2-D (H, W) or 3-D (C, H, W); any other ndim raises ValueError.

For SIPS-compliant downsampling (NGA.STND.0014 v2.4 Section 2.2), see the companion aws.osml.image_processing.sips_resample module.

aws.osml.image_processing.resample.ResampleFunc

Type alias for any resampler. A ResampleFunc takes a CHW (or HW) array and target (rows, cols) dimensions and returns a new array at the target size with the same dtype and layout.

alias of Callable[[ndarray[tuple[int, …], dtype[_ScalarType_co]], int, int], ndarray[tuple[int, …], dtype[_ScalarType_co]]]

aws.osml.image_processing.resample.nearest_neighbor_resample(image, target_rows, target_cols)

Nearest-neighbor resampling via cv2.INTER_NEAREST.

Parameters:
  • image (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Input array in CHW (bands, height, width) layout or single-band (H, W) layout.

  • target_rows (int) – Target number of rows. Must be > 0.

  • target_cols (int) – Target number of columns. Must be > 0.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A new NDArray with the target dimensions, same dtype and layout as the input. Returns the input unchanged when target dimensions match the source dimensions.

Raises:

ValueError – If the input is not 2-D or 3-D, or if either target dimension is <= 0.

aws.osml.image_processing.resample.bilinear_resample(image, target_rows, target_cols)

Bilinear interpolation via cv2.INTER_LINEAR.

Parameters:
  • image (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Input array in CHW (bands, height, width) layout or single-band (H, W) layout.

  • target_rows (int) – Target number of rows. Must be > 0.

  • target_cols (int) – Target number of columns. Must be > 0.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A new NDArray with the target dimensions, same dtype and layout as the input. Returns the input unchanged when target dimensions match the source dimensions.

Raises:

ValueError – If the input is not 2-D or 3-D, or if either target dimension is <= 0.

aws.osml.image_processing.resample.area_resample(image, target_rows, target_cols)

Area-based resampling via cv2.INTER_AREA.

OpenCV’s recommended interpolation for decimation — reduces aliasing compared to nearest-neighbor or bilinear while being cheaper than Lanczos.

Parameters:
  • image (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Input array in CHW (bands, height, width) layout or single-band (H, W) layout.

  • target_rows (int) – Target number of rows. Must be > 0.

  • target_cols (int) – Target number of columns. Must be > 0.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A new NDArray with the target dimensions, same dtype and layout as the input. Returns the input unchanged when target dimensions match the source dimensions.

Raises:

ValueError – If the input is not 2-D or 3-D, or if either target dimension is <= 0.

aws.osml.image_processing.resample.lanczos_resample(image, target_rows, target_cols)

Lanczos interpolation via cv2.INTER_LANCZOS4 (8x8 neighborhood).

Parameters:
  • image (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Input array in CHW (bands, height, width) layout or single-band (H, W) layout.

  • target_rows (int) – Target number of rows. Must be > 0.

  • target_cols (int) – Target number of columns. Must be > 0.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A new NDArray with the target dimensions, same dtype and layout as the input. Returns the input unchanged when target dimensions match the source dimensions.

Raises:

ValueError – If the input is not 2-D or 3-D, or if either target dimension is <= 0.

SIPS RRDS Resampler

SIPS-compliant Reduced Resolution Dataset (RRDS) resampling.

This module implements the SIPS RRDS 2x downsampling algorithm defined in NGA.STND.0014 v2.4 Section 2.2. The pipeline is:

  1. Anti-alias filter — convolve with the 7x7 kernel in Table 2.2 using the SIPS “Mirror Edge - Odd” boundary convention.

  2. LaGrange interpolation — correlate with the 4x4 separable kernel formed from Table 2.7 LaGrange coefficients at sub-pixel offset (0.5, 0.5).

  3. 2x subsample — keep every other pixel in both dimensions.

The public API:

  • SIPS_ANTIALIAS_KERNEL_7x7 — the 7x7 anti-alias kernel constant.

  • compute_lagrange_coefficients() — 4-element LaGrange polynomial coefficients for any sub-pixel spacing in [0, 1).

  • compute_compromise_coefficients() — 4-element “compromise” coefficients from SIPS Table 2.8 (LaGrange variant with reduced ringing near high-contrast edges).

  • build_lagrange_kernel_2d() — 4x4 separable kernel as the outer product of two coefficient vectors.

  • sips_rrds_resample()ResampleFunc-compatible 2x downsampler used as the default resampler for pyramid generation. Accepts an optional keyword-only bit_depth argument that switches to the integer-intermediate pipeline used by the published SIPS reference values.

All array-level functions follow the toolkit conventions: CHW (or HW) layout, no input mutation, and dtype preserved through the operation.

aws.osml.image_processing.sips_resample.SIPS_ANTIALIAS_KERNEL_7x7: ndarray[tuple[int, ...], dtype[_ScalarType_co]] = array([[ 0.00694389,  0.        , -0.0277764 , -0.041665  , -0.0277764 ,          0.        ,  0.00694389],        [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,          0.        ,  0.        ],        [-0.0277764 ,  0.        ,  0.111109  ,  0.166665  ,  0.111109  ,          0.        , -0.0277764 ],        [-0.041665  ,  0.        ,  0.166665  ,  0.25      ,  0.166665  ,          0.        , -0.041665  ],        [-0.0277764 ,  0.        ,  0.111109  ,  0.166665  ,  0.111109  ,          0.        , -0.0277764 ],        [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,          0.        ,  0.        ],        [ 0.00694389,  0.        , -0.0277764 , -0.041665  , -0.0277764 ,          0.        ,  0.00694389]])

SIPS Table 2.2 — 7x7 anti-alias kernel (NGA.STND.0014 v2.4 Section 2.2).

The kernel is 4-fold symmetric and sums to 1.0 (within the rounding precision of the published table). Rows/columns 1 and 5 are zero by design (the kernel is supported on a 5x5 lattice inside the 7x7 footprint).

aws.osml.image_processing.sips_resample.compute_lagrange_coefficients(spacing)

Compute the 4-element LaGrange interpolation coefficients.

These are the cubic LaGrange polynomial weights from SIPS Section 2.3.5 (equations 2.3-2.6), parameterized by the sub-pixel offset d = spacing. The four coefficients apply to a 4-sample window centered one sample to the left of the fractional-offset sample being interpolated.

The coefficients sum to 1.0 for any spacing in [0, 1) (exact identity for the LaGrange polynomial form).

Parameters:

spacing (float) – Sub-pixel offset in [0, 1).

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A shape-(4,) float64 array [C1, C2, C3, C4].

Raises:

ValueError – If spacing is outside [0, 1).

aws.osml.image_processing.sips_resample.compute_compromise_coefficients(spacing)

Compute the 4-element compromise interpolation coefficients.

The compromise coefficients are SIPS Table 2.8 — a LaGrange variant that trades a small amount of interpolation accuracy for reduced ringing near high-contrast edges. This implementation returns the tabulated row at the quantized index int(spacing * 64).

Parameters:

spacing (float) – Sub-pixel offset in [0, 1).

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A new shape-(4,) float64 array [C1, C2, C3, C4].

Raises:

ValueError – If spacing is outside [0, 1).

aws.osml.image_processing.sips_resample.build_lagrange_kernel_2d(row_spacing, col_spacing)

Build a separable 4x4 LaGrange interpolation kernel.

The kernel is the outer product of the row- and column-direction LaGrange coefficient vectors. For (0.5, 0.5) this matches SIPS Table 2.3.

Parameters:
  • row_spacing (float) – Row sub-pixel offset in [0, 1).

  • col_spacing (float) – Column sub-pixel offset in [0, 1).

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A shape-(4, 4) float64 kernel.

Raises:

ValueError – If either spacing is outside [0, 1).

aws.osml.image_processing.sips_resample.sips_rrds_resample(image, target_rows, target_cols, *, bit_depth=None)

SIPS-compliant Reduced Resolution Dataset (RRDS) 2x downsampler.

Conforms to the ResampleFunc type alias in aws.osml.image_processing.resample. Implements the three-step pipeline defined in NGA.STND.0014 v2.4 Section 2.2:

  1. Anti-alias filter via sips_convolve with SIPS_ANTIALIAS_KERNEL_7x7.

  2. LaGrange interpolation via sips_correlate with the 4x4 separable kernel at sub-pixel offset (0.5, 0.5).

  3. 2x subsample (drop odd rows and columns).

Only exact 2x downsampling is supported. target_rows and target_cols must equal (src_rows + 1) // 2 and (src_cols + 1) // 2 respectively (the SIPS even/odd rounding rule: odd-sized sources round up by 1).

Precision options:

  • By default (bit_depth=None), the entire pipeline runs in the input dtype (typically float32 or float64) and returns a float array. This is the fastest path because cv2.filter2D has SIMD-optimized float kernels; float32 is 3-4x faster than uint16 for the same operation. Use this mode when feeding the output into further float pipelines or when approximate SIPS compliance is acceptable.

  • When bit_depth is an integer n, the intermediate produced by the anti-alias convolution is rounded and clipped to [0, 2**n - 1] before the LaGrange correlation. This matches the SIPS reference exactly (as published in Tables 2.5 and 2.6), which assumed integer-valued raster imagery at each stage. Typical values: bit_depth=8 for 8-bit panchromatic or RGB, bit_depth=11 for 11-bit EO, bit_depth=16 for 16-bit multispectral.

SIPS reference compliance notes:

Passing bit_depth matching the source’s dynamic range is required to reproduce the Table 2.5 and Table 2.6 verification matrices in SIPS Section 2.2.7. The reference values were computed on an 11-bit source (R0) with the anti-alias output stored as integers before the LaGrange step; the published standard is scoped to “integer-valued raster image data” (Section 1.2). A pure-float pipeline propagates unclipped values through the LaGrange correlation and can differ from the reference by up to ~50 digital counts at cells whose neighborhood contains pixels clipped to the source’s max value (e.g. 2047 for 11-bit).

Even with bit_depth=11 the second cascade stage (R1 -> R2) retains a small residual discrepancy of <=2 digital counts at a handful of boundary cells, due to how the 513 -> 257 odd-dimension subsample interacts with the 7-pixel-wide anti-alias kernel at the image edge. The underlying primitives (sips_convolve, sips_correlate) match their own SIPS verification tables (2.15, 2.25, 2.26) exactly.

Parameters:
  • image (ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]) – Input array in CHW (bands, height, width) layout or single-band (H, W) layout. The input is not mutated.

  • target_rows (int) – Target number of output rows. Must equal (src_rows + 1) // 2.

  • target_cols (int) – Target number of output columns. Must equal (src_cols + 1) // 2.

  • bit_depth (Optional[int]) – If provided, round and clip the intermediate post-anti-alias result to [0, 2**bit_depth - 1] before the LaGrange correlation. Reproduces the SIPS reference values in Tables 2.5 and 2.6 when set to the source’s bit depth. Must be a positive integer when specified.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A new NDArray with the SIPS-rounded half dimensions and the same dtype and layout as the input.

Raises:

ValueError – If the input is not 2-D or 3-D, if the target dimensions do not match the SIPS-rounded half of the source dimensions, or if bit_depth is not a positive integer.

Pyramid Builder

class aws.osml.image_processing.PyramidBuilder(source, min_size=256, scale_factor=2, tile_width=None, tile_height=None, resample_func=None, num_workers=2, use_native_levels=True, progress=None)

Bases: object

Single-pass R-Set generation via incremental accumulation.

Reads R0 tiles in raster order and incrementally builds every reduced-resolution level. Completed overview tiles are stored in BufferedImageAssetProvider instances allocated at construction time and drained by the caller’s DatasetWriter via build_and_write().

Parameters:
  • source (Any) – A duck-typed ImageAssetProvider representing the full-resolution image (R0).

  • min_size (int) – Overview generation stops once either image dimension of the current level falls strictly below this threshold; that level is included as the final overview. Must be greater than zero. Defaults to 256.

  • scale_factor (int) – Per-level reduction factor. v2.0 supports only scale_factor=2; any other value raises ValueError. Defaults to 2.

  • tile_width (Optional[int]) – Tile width for overview levels. When None, inherits from the source’s num_pixels_per_block_horizontal. Defaults to None.

  • tile_height (Optional[int]) – Tile height for overview levels. When None, inherits from the source’s num_pixels_per_block_vertical. Defaults to None.

  • resample_func (Optional[Callable[[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]], int, int], ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]]]) – A ResampleFunc callable used to downsample each 2x2 tile group. Defaults to sips_rrds_resample() when None.

  • num_workers (int) – Number of background threads used for the prefetch + writeback pipeline. 0 runs entirely in the calling thread (no executors). Must be non-negative. Defaults to 2.

  • use_native_levels (bool) – When True and the source exposes num_resolution_levels > 1, populate the first N overview levels from native reduced-resolution reads instead of resampling. Defaults to True.

  • progress (Optional[ProgressCallback]) – Optional callback invoked after each source tile is processed. Receives (completed, total, level) — see ProgressCallback for the full protocol. Defaults to None (no reporting).

Raises:

ValueError – If scale_factor != 2, min_size <= 0, or num_workers < 0.

property source: Any

The full-resolution source provider (R0).

property min_size: int

Threshold below which overview generation stops.

property scale_factor: int

Per-level reduction factor (always 2 in v2.0).

property tile_width: int

Tile width used for every overview level.

property tile_height: int

Tile height used for every overview level.

property resample_func: Callable[[ndarray[tuple[int, ...], dtype[_ScalarType_co]], int, int], ndarray[tuple[int, ...], dtype[_ScalarType_co]]]

The resampling callable applied to each 2x2 tile group.

property num_workers: int

Background thread count for prefetch and writeback.

property use_native_levels: bool

Whether to prefer native reduced-resolution source reads.

property progress: ProgressCallback | None

The progress callback, or None if not set.

build()

Generate every pyramid level in a single R0 pass.

Reads each R0 tile exactly once (raster order), incrementally cascades each tile’s contribution up every overview level, and populates the pre-allocated BufferedImageAssetProvider instances in place.

Returns a list whose first element is the source (R0) itself and whose remaining elements are the populated BufferedImageAssetProvider instances for each overview level, ordered highest to lowest resolution.

When use_native_levels=True and the source exposes num_resolution_levels > 1, the first N overview levels are filled from native reduced-resolution reads; the accumulator cascade starts at the first level beyond native support.

When num_workers == 0, execution is entirely single-threaded — no ThreadPoolExecutor instances are created. Otherwise a prefetch thread decodes R0 tiles ahead of the main thread and a writeback thread drains set_block calls; exceptions in either background thread are propagated on the main thread and both executors are shut down before re-raising.

Return type:

List[Any]

Returns:

[source, level_1_provider, ..., level_N_provider].

build_and_write(writer, base_key='image:0', file_metadata=None, image_metadata_fn=None)

Build overview levels and write them to a DatasetWriter.

Invokes build() to produce the full level list, then writes only the overview levels (level 1+) as assets on writer. The source image (level 0) is never written — callers that need the base in the output (e.g. for COG) should add it to the writer themselves.

Parameters:
  • writer (Any) – A duck-typed DatasetWriter exposing add_asset(key, provider, title, description, roles) and a metadata setter.

  • base_key (str) – Base asset key prefix. Overview levels are keyed as f"{base_key}:overview:{i}". Defaults to "image:0".

  • file_metadata (Optional[Any]) – Optional dataset-level metadata. When provided, it is applied to writer (via the metadata setter) before any asset is added.

  • image_metadata_fn (Optional[Callable[[int], Any]]) – Optional callable taking a level index (1-based for overviews) and returning a MetadataProvider (or compatible) to attach to that level’s output asset. Metadata is attached by wrapping the overview provider with BufferedImageAssetProvider.from_provider().

Return type:

None

Downsampled Image Provider

class aws.osml.image_processing.DownsampledImageProvider(source, scale_factor=2, resample_func=None, tile_width=None, tile_height=None, cache=None)

Bases: object

Lazy reduced-resolution view of an ImageAssetProvider.

Wraps a source provider and presents a virtual tile grid at reduced resolution. Blocks are computed on demand via one of two paths:

  • Native path: when the source exposes multiple resolution levels (e.g. J2K wavelet decomposition), blocks are requested at the appropriate resolution_level and stitched into the output tile. No resampling function is invoked.

  • Resample path: when the source has only one resolution level, full-resolution blocks covering the output tile’s footprint (plus halo if resample_func is sips_rrds_resample) are read, stitched, and passed through resample_func.

Implements the ImageAssetProvider interface (duck-typed) so it can be passed to DatasetWriter, MappedImageProvider, or another DownsampledImageProvider for chaining.

Parameters:
  • source (Any) – A duck-typed ImageAssetProvider instance.

  • scale_factor (int) – Reduction factor. Must be a positive power of 2. Defaults to 2.

  • resample_func (Optional[Callable[[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]], int, int], ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]]]) – A ResampleFunc callable used when the native path is not available. Defaults to sips_rrds_resample() when None.

  • tile_width (Optional[int]) – Tile width for the output grid. When None, defaults to ceil(source_block_width / scale_factor).

  • tile_height (Optional[int]) – Tile height for the output grid. When None, defaults to ceil(source_block_height / scale_factor).

  • cache (Optional[TileCache]) – Optional shared TileCache for caching computed output blocks. When None, no caching is performed.

Raises:

ValueError – If scale_factor is not a power of 2, or if the source block dimensions are too small for the resample path.

property key: str

Unique key identifying this operator in the processing chain.

property num_rows: int

Number of pixel rows in the downsampled image.

property num_columns: int

Number of pixel columns in the downsampled image.

property num_bands: int

Number of image bands (delegated to source).

property pixel_value_type: Any

Pixel value type (delegated to source).

property num_pixels_per_block_horizontal: int

Tile width in pixels for the output grid.

property num_pixels_per_block_vertical: int

Tile height in pixels for the output grid.

property num_resolution_levels: int

Number of resolution levels available.

When the native path is active, the number of remaining resolution levels in the source beyond the one consumed by this operation. Otherwise 1 (only the resampled level).

property block_grid_size: Tuple[int, int]

Grid dimensions (rows, cols) of the output block layout.

has_block(row, col, resolution_level=0)

Check whether a block exists at the given grid position.

Always returns True for in-bounds coordinates (the downsampled view is never sparse — missing source blocks are padded).

Parameters:
  • row (int) – Block row index.

  • col (int) – Block column index.

  • resolution_level (int) – Resolution level (default 0).

Return type:

bool

Returns:

True if the coordinates are within the output grid, False otherwise.

get_block(row, col, resolution_level=0, bands=None)

Read a downsampled block at the given grid position.

Dispatches to the native path or resample path depending on whether the source exposes enough resolution levels. Results are cached when a TileCache is provided.

Parameters:
  • row (int) – Block row index.

  • col (int) – Block column index.

  • resolution_level (int) – Resolution level (default 0).

  • bands (Optional[Tuple[int, ...]]) – Optional tuple of band indices to read.

Return type:

ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]

Returns:

A CHW NDArray of shape (num_bands, tile_height, tile_width) with the source’s dtype.

Raises:
  • IndexError – If (row, col) is out of the output grid bounds.

  • ValueError – If resolution_level exceeds the available levels.

property metadata: Any

Return the metadata object from the source provider.

Tiled Image Pyramid

class aws.osml.image_processing.TiledImagePyramid(levels, scale_factor=2, reader=None)

Bases: object

Read-side container grouping ImageAssetProviders into a pyramid.

Level 0 is the highest resolution. This class does no computation — it wraps providers that already exist (from COG overviews, NITF R-Sets, PyramidBuilder output, or build_pyramid_levels()).

Parameters:
  • levels (List[Any]) – A non-empty list of ImageAssetProvider instances ordered from highest resolution (level 0) to lowest.

  • scale_factor (int) – The nominal per-level reduction factor. Defaults to 2.

  • reader (Optional[Any]) – Optional DatasetReader that provides metadata and DES segment access. Stored by from_dataset().

Raises:

ValueError – If levels is empty.

property num_levels: int

Number of pyramid levels.

property scale_factor: int

Nominal per-level reduction factor.

property reader: Any

The DatasetReader providing metadata and DES access.

Returns None when the pyramid was built via from_providers() or constructed without a reader.

get_level(level)

Return the provider at the given pyramid level.

Parameters:

level (int) – Level index in [0, num_levels).

Return type:

Any

Returns:

The ImageAssetProvider at the requested level.

Raises:

IndexError – If level is out of [0, num_levels).

image_shape_at_level(level)

Return (num_bands, num_rows, num_columns) at the given level.

Parameters:

level (int) – Level index in [0, num_levels).

Return type:

Tuple[int, int, int]

Returns:

A 3-tuple of (num_bands, num_rows, num_columns).

Raises:

IndexError – If level is out of [0, num_levels).

tile_grid_at_level(level)

Return the block grid size (rows, cols) at the given level.

Parameters:

level (int) – Level index in [0, num_levels).

Return type:

Tuple[int, int]

Returns:

A 2-tuple of (grid_rows, grid_cols).

Raises:

IndexError – If level is out of [0, num_levels).

best_level_for(src_size, output_size)

Pick the deepest pyramid level that avoids upsampling.

Given a source window of size src_size (width, height) at R0 and a desired output_size (width, height), returns the deepest level N where src_size / scale_factor^N >= output_size on both axes.

When no level meets the target (i.e. even level 0’s scaled size is smaller than output_size), returns 0.

Parameters:
  • src_size (Tuple[int, int]) – Source window dimensions as (width, height). Both must be > 0.

  • output_size (Tuple[int, int]) – Desired output dimensions as (width, height). Both must be > 0.

Return type:

int

Returns:

The level index in [0, num_levels).

Raises:

ValueError – If any dimension is <= 0.

compute_statistics(level=None, max_pixels=10000000, num_bins=0, bin_edges=None, num_workers=0)

Compute statistics from the most efficient pyramid level.

When level is None, selects the deepest level with at least max_pixels total spatial pixels (~R2-R3 for typical large imagery). Gives sub-percent mean/stddev accuracy with minimal I/O.

Min/max from overview levels are approximate — isolated extrema get averaged away by the downsampling kernel. Callers needing exact min/max should compute at level 0.

Parameters:
  • level (Optional[int]) – Explicit level to compute at. When None, auto-selects via _best_level_for_statistics().

  • max_pixels (int) – Minimum spatial pixel count for auto-selection. Defaults to 10_000_000.

  • num_bins (int) – Number of histogram bins. See compute_image_statistics().

  • bin_edges (Union[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]], List[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]], None]) – Explicit bin edges. See compute_image_statistics().

  • num_workers (int) – Thread count for concurrent block processing. See compute_image_statistics().

Return type:

ImageStatistics

Returns:

An ImageStatistics instance.

static from_providers(providers, scale_factor=2)

Construct a pyramid from an explicit list of providers.

Parameters:
  • providers (List[Any]) – A non-empty list of ImageAssetProvider instances ordered from highest to lowest resolution.

  • scale_factor (int) – Nominal per-level reduction factor. Defaults to 2.

Return type:

TiledImagePyramid

Returns:

A TiledImagePyramid wrapping the providers.

Raises:

ValueError – If providers is empty.

static from_dataset(reader, base_key='image:0')

Discover overview assets in a dataset reader and build a pyramid.

Looks for overview assets using the key convention "{base_key}:overview:{N}" for N = 1, 2, ..., and also checks for assets with role "overview" referencing base_key. Levels are ordered by decreasing resolution (ascending overview index).

When no overviews are found, returns a single-level pyramid containing only the base asset.

Parameters:
  • reader (Any) – A duck-typed DatasetReader that exposes get_asset(key) and optionally get_assets_by_role(role) or list_asset_keys().

  • base_key (str) – The key identifying the base (full-resolution) image asset. Defaults to "image:0".

Return type:

TiledImagePyramid

Returns:

A TiledImagePyramid with levels ordered from highest to lowest resolution.

Raises:

KeyError – If the base asset is not found in the reader.

Pyramid Helpers

aws.osml.image_processing.iter_blocks(provider, order='raster', resolution_level=0)

Yield (block_row, block_col, block) from a provider.

Iterates the provider’s block grid in the specified order, skipping sparse blocks (where provider.has_block(r, c, resolution_level) returns False).

Parameters:
  • provider (Any) – A duck-typed ImageAssetProvider.

  • order (str) – Iteration order. Currently only "raster" (row-major) is supported. Defaults to "raster".

  • resolution_level (int) – Resolution level to read. Defaults to 0.

Yields:

Tuples of (block_row, block_col, NDArray) for each non-sparse block.

Return type:

Iterator[Tuple[int, int, ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]]]

aws.osml.image_processing.build_pyramid_levels(source, min_size=256, scale_factor=2, tile_width=None, tile_height=None, resample_func=None, cache=None)

Build a lazy pyramid as a chain of DownsampledImageProvider providers.

The first element of the returned list is the source itself. Each subsequent element is a DownsampledImageProvider wrapping the previous element, forming a chain of progressively lower-resolution virtual providers. No pixels are decoded until get_block() is called on one of the returned providers.

Generation stops once either dimension of the current level falls strictly below min_size; that level is included as the final entry.

Parameters:
  • source (Any) – A duck-typed ImageAssetProvider for the full-resolution image.

  • min_size (int) – Minimum dimension threshold. Generation stops when either axis falls below this value. Defaults to 256.

  • scale_factor (int) – Per-level reduction factor. Must be a positive power of 2. Defaults to 2.

  • tile_width (Optional[int]) – Tile width for the output grid of each DownsampledImageProvider. When None, defaults to ceil(source_block / scale_factor).

  • tile_height (Optional[int]) – Tile height for the output grid of each DownsampledImageProvider. When None, defaults to ceil(source_block / scale_factor).

  • resample_func (Optional[Callable[[ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]], int, int], ndarray[tuple[int, ...], dtype[TypeVar(_ScalarType_co, bound= generic, covariant=True)]]]]) – A ResampleFunc callable. Defaults to sips_rrds_resample() when None.

  • cache (Optional[TileCache]) – Optional shared TileCache for caching computed output blocks in each DownsampledImageProvider.

Return type:

List[Any]

Returns:

A list [source, level_1, level_2, ...] where each level_i (for i > 0) is a DownsampledImageProvider whose internal source is level_{i-1}.