Skip to content

Stream the field of an RFC-5 displacements or coordinates transform #692

Description

@vboussot

resample and resample_bounding_box stream the moving image: each output block reads only the moving chunks its region touches, and the full image is never loaded. One input escapes that. An RFC-5 displacements or coordinates transform is converted before the graph is built, and ngff_displacement_field_to_itk_transform reads its field in full through field.data.compute().

The eager read is load-bearing, not an oversight: the graph calls resample_bounding_box(transform_list, grid, moving) per block while it is being built, and that bounding box decides which moving chunks the block reads. Without the transform there is no box, and without the box there is no graph. Deferring the compute() alone does not help.

So a field the size of the volume has to fit in memory while the moving image does not, which is the opposite of what the rest of the call promises. #674 documents the limit; this issue is about removing it.

The design exists in KonfAI

konfai.data.transform.Resample solves exactly this, and its own words are the specification:

A field on disk is read region by region, and the window a region samples is its own box: the sup of the values just read bounds that region's read.

Three parts, and the second is the good idea:

  • The field is never read whole. A region reads its own box, which it needs for sampling anyway, so the read that computes is the read that bounds. Nothing is read twice or in excess.
  • The bound is the sup of the values just read, and it is exact rather than conservative: an interpolated displacement is a convex combination of the lattice values around it, so it cannot exceed their sup. A quiet slab pays a quiet halo. A global reduction over the whole field would instead charge every region the worst displacement in the volume.
  • Two paths are declared separately: stream_region_source announces the window when it can be priced ahead of the data, measured_region_source measures it from the field when one is declared, and measures_at_run says which applies. The planner knows before touching a source voxel whether it can price the read or has to measure it.

Why it belongs here

resample_bounding_box is already the counterpart of stream_region_source. What is missing is the measured variant: for a field transform, read the block's own field box, take its sup, derive the moving region from it, and build the ITK DisplacementFieldTransform per block from the field sliced to that region.

Moving it here rather than reimplementing it means KonfAI can drop its copy, which is the direction of #650 and #667: fewer bespoke implementations downstream, one streamed resampler upstream that both use.

Not in #674, which converts every RFC-5 transformation type to ITK and is large enough on its own.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions