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.
resampleandresample_bounding_boxstream 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-5displacementsorcoordinatestransform is converted before the graph is built, andngff_displacement_field_to_itk_transformreads its field in full throughfield.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 thecompute()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.Resamplesolves exactly this, and its own words are the specification:Three parts, and the second is the good idea:
stream_region_sourceannounces the window when it can be priced ahead of the data,measured_region_sourcemeasures it from the field when one is declared, andmeasures_at_runsays 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_boxis already the counterpart ofstream_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 ITKDisplacementFieldTransformper 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.