Getting Started¶
Installation¶
pip install osml-imagery-io
That’s it. The wheels are self-contained — Rust core and C codecs are bundled. No system libraries, no C toolchain, no conda required at runtime.
Read an Image¶
from aws.osml.io import imread
pixels = imread("image.ntf")
print(pixels.shape) # (3, 1024, 1024) — CHW layout (bands, height, width)
print(pixels.dtype) # uint8
All images are returned as NumPy arrays in CHW layout (bands, height, width),
which integrates directly with PyTorch and other ML frameworks.
Read a Windowed Region¶
Extract a rectangular sub-region without loading the full image. The window is
(x, y, width, height) where x and y are column and row offsets:
chip = imread("image.ntf", window=(100, 200, 256, 256))
print(chip.shape) # (3, 256, 256)
Select Specific Bands¶
Read only the bands you need by passing zero-based indices:
red_green = imread("image.ntf", bands=[0, 1])
print(red_green.shape) # (2, 1024, 1024)
Save an Image¶
Write a NumPy array to a file. The format is inferred from the extension:
from aws.osml.io import imsave
import numpy as np
data = np.random.randint(0, 255, (3, 512, 512), dtype=np.uint8)
imsave("output.tif", data) # GeoTIFF with Deflate compression
imsave("output.ntf", data) # NITF with JPEG 2000 lossless
imsave("output.png", data) # PNG
2-D arrays (height, width) are treated as single-band images automatically:
grayscale = np.zeros((256, 256), dtype=np.uint8)
imsave("gray.png", grayscale)
Inspect Metadata¶
Get image properties and the full format-specific metadata without reading any pixels:
from aws.osml.io import iminfo
info = iminfo("image.ntf")
print(f"{info.width}x{info.height}, {info.bands} bands, {info.dtype}")
The metadata attribute gives you the full format-specific metadata dictionary
for the image segment — NITF subheader fields and parsed TREs, or TIFF IFD tags:
# Rational polynomial coefficients for geopositioning
rpc = info.metadata["RPC00B"]
print(rpc["LAT_OFF"], rpc["LINE_SCALE"])
# Acquisition context — mission, date
stdidc = info.metadata["STDIDC"]
print(stdidc["MISSION"], stdidc["ACQ_DATE"])
# Exploitation usability — GSD, sun angles
use00a = info.metadata["USE00A"]
print(use00a["MEAN_GSD"], use00a["SUN_EL"])
Iterate Over Tiles¶
Process a large image in fixed-size tiles without loading it all into memory:
from aws.osml.io import tiles
for tile in tiles("large_image.tif", tile_size=(256, 256)):
print(f"Tile ({tile.tile_col}, {tile.tile_row}) at pixel ({tile.x}, {tile.y})")
process(tile.data)
Edge tiles are smaller when the image dimensions are not evenly divisible by the tile size. Add overlap between adjacent tiles for seamless stitching:
for tile in tiles("large_image.tif", tile_size=(256, 256), overlap=(32, 32)):
# stride = (224, 224), tiles share 32 pixels on each edge
process(tile.data)
What’s Underneath¶
The convenience functions are a thin layer over a full-featured, block-level API. Here is the same read expressed both ways, so you can see what the convenience layer handles for you:
Convenience — one line:
from aws.osml.io import imread
pixels = imread("image.ntf")
Low-level equivalent:
from aws.osml.io import IO, AssetType
import numpy as np
with IO.open("image.ntf", "r") as dataset:
keys = dataset.get_asset_keys(asset_type=AssetType.Image, roles=["data"])
image = dataset.get_asset(keys[0])
bw = image.num_pixels_per_block_horizontal or image.num_columns
bh = image.num_pixels_per_block_vertical or image.num_rows
grid_rows, grid_cols = image.block_grid_size
dtype = np.dtype(image.pixel_value_type.to_numpy_dtype())
pixels = np.zeros((image.num_bands, image.num_rows, image.num_columns), dtype=dtype)
for r in range(grid_rows):
for c in range(grid_cols):
block = image.get_block(r, c, resolution_level=0)
y0, x0 = r * bh, c * bw
pixels[:, y0:y0 + block.shape[1], x0:x0 + block.shape[2]] = block
When you need fine-grained control — custom metadata, block-level access, compression tuning, multi-asset datasets — the full API is always available. Start with the Introduction to understand the library’s design, then explore:
Datasets and the IO Interface — how files are organized into typed, keyed assets
Image Assets — block-level pixel access, block grids, sparse images
Metadata — TREs, GeoKeys, file-level and image-level metadata
Writing Imagery Assets — compression, georeferencing, encoding hints, multi-file pyramids
Development Setup¶
If you are building the library from source or contributing, you will need the Rust toolchain and a conda environment:
conda env create -f environment.yml
conda activate osml-imagery-io-dev
source scripts/setup-dev-env.sh
maturin develop
pytest
cargo test
See CONTRIBUTING.md for details.