ngff_zarr.resample

Resample a moving image onto a fixed image grid, one block at a time.

Module Contents

Functions

_default_padding

_component_type

_shape_only

An array carrying a shape without owning memory for it.

_block_grid

A geometry-only stand-in for one output block of the fixed grid.

_chunk_offsets

The index of each chunk’s first element, per axis.

_nested_key

The dask key at index in a nested key list.

_chunk_span

Which chunks a region touches: the first, how many, and where it starts.

_field_block_transform

The ITK transform one output block needs, from that block’s field window.

_assemble_region

Reassemble whole chunks into the sub-array bounds selects.

_resample_block

Resample one output block from the moving chunks its region touches.

_add_field_transform

Add the task that builds one block’s transform, and return its key.

resample

Resample moving onto the grid of fixed through transform.

Data

API

ngff_zarr.resample._INTERPOLATORS

(‘linear’, ‘nearest_neighbor’, ‘label_image’, ‘b_spline’, ‘windowed_sinc’, ‘gaussian’)

ngff_zarr.resample._INTERPOLATOR_PADDING

None

ngff_zarr.resample._FLOAT64_INTERPOLATOR_PADDING

None

ngff_zarr.resample._default_padding(interpolator: str, dtype) → int
ngff_zarr.resample._component_type(out_dtype) → str
ngff_zarr.resample._shape_only(shape: tuple) → numpy.ndarray

An array carrying a shape without owning memory for it.

Only shape and dtype are ever read off these stand-ins. Allocating for real costs one byte per output voxel, which looks free while the pages stay untouched and is then paid in full the moment something serializes the object holding it.

ngff_zarr.resample._block_grid(
fixed: ngff_zarr.ngff_image.NgffImage,
starts: dict,
shape: tuple,
) → ngff_zarr.ngff_image.NgffImage

A geometry-only stand-in for one output block of the fixed grid.

ngff_zarr.resample._chunk_offsets(chunks)

The index of each chunk’s first element, per axis.

ngff_zarr.resample._nested_key(keys, index)

The dask key at index in a nested key list.

ngff_zarr.resample._chunk_span(offsets, bounds)

Which chunks a region touches: the first, how many, and where it starts.

offsets holds the index of each chunk’s first element per axis, as

Func:

_chunk_offsets gives them, and bounds the region as (start, stop) per axis.

ngff_zarr.resample._field_block_transform(
chunks,
*,
transform,
nchunks,
offset,
bounds,
field_dims,
field_scale,
field_translation,
field_axes_types,
)

The ITK transform one output block needs, from that block’s field window.

Built inside the task, from the field chunks the window touches, so the field reaches ITK a window at a time instead of whole.

ngff_zarr.resample._assemble_region(chunks, nchunks, offset, bounds)

Reassemble whole chunks into the sub-array bounds selects.

chunks are whole chunks in C order over the nchunks grid that covers the region, offset the index of the first of them in the array they came from, and bounds the region itself, as (start, stop) per axis.

ngff_zarr.resample._resample_block(
chunks,
transform_list,
*,
nchunks,
offset,
bounds,
moving_dims,
moving_scale,
moving_translation,
moving_orientations,
grid_dims,
grid_scale,
grid_translation,
grid_shape,
grid_orientations,
interpolator: str,
default_value: float,
out_dtype,
)

Resample one output block from the moving chunks its region touches.

chunks are whole moving-image chunks, in C order over the nchunks grid of chunks that covers the block’s region; offset is the index of the first of them in the moving image and bounds the region itself. transform_list arrives as a task argument rather than bound into the callable, so the graph carries it once for every block instead of once per block: see where the tasks are built.

ngff_zarr.resample._add_field_transform(
graph,
name,
index,
transform,
field: ngff_zarr.ngff_image.NgffImage,
field_keys,
field_offsets,
field_geometry,
window,
)

Add the task that builds one block’s transform, and return its key.

ngff_zarr.resample.resample(
transform,
fixed: ngff_zarr.ngff_image.NgffImage,
moving: ngff_zarr.ngff_image.NgffImage,
padding: int | None = None,
interpolator: str = 'linear',
default_value: float = 0.0,
*,
fields: collections.abc.Mapping[str, object] | None = None,
) → ngff_zarr.ngff_image.NgffImage

Resample moving onto the grid of fixed through transform.

The result is a lazy :class:NgffImage: nothing is read or computed until the returned Dask array is. Each output block is resampled on its own from the moving chunks inside the region its resample reads, as reported by

Func:

ngff_zarr.resample_bounding_box. The regions are computed once, when the graph is built, and the blocks are tasks of a single Dask graph that reference the moving chunks directly, so a chunk that several blocks need is read and decoded once per computation. The full moving image is never loaded, which is what makes this usable when it is larger than memory, remote, or chunked.

An RFC-5 displacements or coordinates field is streamed the same way. A block reads the window of the field its own points fall in, and that window becomes the block’s ITK transform; what sizes the block’s moving read is the range of displacement that window holds. The field is passed over once when the graph is built, a chunk at a time, to learn that range per chunk. Neither the moving image nor the field has to fit in memory.

A window declares its own origin, and on a float64 moving image that changes the last bits of the continuous index ITK computes from it, so the result is bit-identical to an undecomposed call on float32 and equal to about 1e-13 on float64.

Resampling runs through itkwasm-downsample, so no native ITK build is required and the result is identical to one across platforms.

Parameters:
  • transform –

    An RFC-5 coordinate transformation, an itk.Transform (including the CompositeTransform an Elastix registration returns), or an ITK-Wasm Transform / TransformList. It maps fixed points into moving space.

    The two are interpreted in different coordinate spaces, exactly as

    func:

    ngff_zarr.resample_bounding_box interprets them. An RFC-5 transformation acts on the intrinsic coordinate systems, where a point is translation + scale * index and no direction matrix applies, so the anatomical orientation of either image does not enter; its input and output identifiers are not resolved either. An ITK transform acts on ITK physical space, direction matrix included.

  • fixed (NgffImage) – The image whose grid defines the output. Geometry only, its pixels are never read.

  • moving (NgffImage) – The image to sample.

  • padding (int | None) – Pixels of padding added per side when computing each block’s source region. Defaults to what interpolator reads beyond the continuous index bound, so the two stay in step; b_spline defaults to 16, or 32 on float64 images.

  • interpolator (str) – One of "linear" (default), "nearest_neighbor", "label_image", "b_spline", "windowed_sinc" or "gaussian".

  • default_value (float) – Value written where a block samples outside moving.

  • fields (Mapping[str, NgffImage | NgffMultiscales], optional) –

    The field images an RFC-5 displacements or coordinates transformation points at, keyed by its path, as

    func:

    ngff_zarr.ngff_transform_to_itk_transform takes them. Required for those two, ignored otherwise.

Returns:

The resampled image, carrying the geometry of fixed and the dtype of moving.

Return type:

NgffImage