brain_deer.warp.field¶
Dense displacement fields and operations on them.
A DeformationField is a regular grid of RAS-millimetre displacements
plus the affine that places that grid in world space. It defines the point map
phi(x) = x + sample(x). It carries no “forward”/”inverse” label – that is
the caller’s bookkeeping about which file went where.
The big ANTs fields are hundreds of MB compressed and over a gigabyte in RAM, so
compose_streaming() composes a small correction into a large on-disk field
without ever holding the large field whole. (Measured: slab-by-slab access on a
.nii.gz is O(n**2) because gzip is not seekable, so we decompress once to a
temporary uncompressed file and memory-map that instead.)
Classes¶
A dense displacement field over a regular grid. |
Functions¶
|
Resample |
|
Compose |
|
Numeric fixed-point inverse of |
|
Compose the small |
|
Compose the large field at |
Module Contents¶
- class brain_deer.warp.field.DeformationField¶
A dense displacement field over a regular grid.
- displacement¶
- Type:
(I, J, K, 3) float32 array of RAS-mm displacements.
- affine¶
- Type:
(4, 4) float64, mapping voxel index -> RAS world mm.
- property spacing: FloatArray¶
Per-axis voxel size in mm (column norms of the affine).
- brain_deer.warp.field.resample_field(field: DeformationField, *, affine: FloatArray, shape: tuple[int, int, int], order: int = 3) DeformationField¶
Resample
fieldonto a new grid, preserving the displacement values.
- brain_deer.warp.field.compose(outer: DeformationField, inner: DeformationField, order: int = 3) DeformationField¶
Compose
phi_outer o phi_inneroninner’s grid.d(x) = d_inner(x) + outer.sample(x + d_inner(x))– the displacement that first appliesinnerthenouter.
- brain_deer.warp.field.invert(field: DeformationField, *, max_iter: int = 20, tol_mm: float = 0.01, order: int = 3) DeformationField¶
Numeric fixed-point inverse of
phi, on the same grid.Solves
psi(y) = -field.sample(y + psi(y))by fixed-point iteration. This converges only for near-identity fields (||J(d)|| < 1); it is intended for the small, smooth correction fields authored here, never for the large ANTs warps – those already ship as separate forward/inverse files.
- brain_deer.warp.field.compose_streaming(outer: DeformationField, inner_path: str | pathlib.Path, out_path: str | pathlib.Path, *, slab: int = 16, order: int = 3) None¶
Compose the small
outerfield onto the large field atinner_path.Writes
phi_outer o phi_inner(d(x) = d_inner(x) + outer.sample(x + d_inner(x))) toout_pathoninner’s grid, holding only one K-slab of the large field in RAM at a time. This is the direction where the correction is applied last; Lead-DBS uses it for the inverse composite (with the inverted correction asouter). Seecompose_streaming_outer().
- brain_deer.warp.field.compose_streaming_outer(outer_path: str | pathlib.Path, inner: DeformationField, out_path: str | pathlib.Path, *, slab: int = 16, order: int = 3, big_field_order: int = 1) None¶
Compose the large field at
outer_pathonto the smallinnerfield.Writes
phi_outer o phi_inner(d(x) = d_inner(x) + outer.sample(x + d_inner(x))) toout_pathon the outer (large) field’s grid. This is the direction where the correction (inner) is applied first and the big warp wraps it – Lead-DBS’s forward composite (compose(outer=forwardWarp, inner=corrections)).The large field must be sampled at
x + d_inner(x), which is only a few mm fromxsince the correction is small; the memmapped grid gives that random access without holding the field in RAM.big_field_orderdefaults to 1 (linear): the large ANTs field is smooth at its native resolution, so linear differs from cubic by ~0.005mm here, and it avoidsmap_coordinates’ cubic prefilter – which would otherwise re-filter the whole 500MB+ field once per slab per component and dominate the runtime.orderstill controls the (cheap) correction sampling.