brain_deer.warp.session¶
Headless orchestration of a refinement session.
A WarpSession holds the correction set and the grid the correction
field is computed on, and turns the set into a dense field on demand. It is the
seam the Qt plugin and the command layer both drive; it imports no Qt and no VTK.
The correction field is always rebuilt from scratch from the full active point
set – there is no incremental accumulation. That is what makes editing and
undo trivial (drop a point, re-solve), and it is why undo_to_source_frame()
exists: see its docstring.
Classes¶
A live refinement session over one reference grid. |
Module Contents¶
- class brain_deer.warp.session.WarpSession¶
A live refinement session over one reference grid.
- static coarse_grid(affine: FloatArray, shape: tuple[int, int, int], spacing_mm: float) tuple[FloatArray, tuple[int, int, int]]¶
A coarser isotropic grid over the same world extent.
The correction never needs the full ANTs resolution – a 2mm grid is ~8x fewer voxels and is upsampled implicitly wherever it is sampled. The world origin and axis directions are preserved; only the sample spacing changes.
- solve() brain_deer.warp.field.DeformationField¶
Rebuild the correction field from every active control point.
- undo_to_source_frame(point_display: FloatArray, order: int = 3) tuple[float, float, float]¶
Map a point from the corrected (display) frame back to the source frame.
The user clicks on an image that already has the current correction applied, so their click is a display-frame coordinate. But the field is rebuilt from scratch each time, so a stored source landmark must live in the un-corrected frame. This pushes the click back through the inverse of the current correction before it is stored.
Targets are never passed through here: a target is where the user wants the content to end up in the display frame, which is exactly the frame they clicked in. Getting this backwards makes every correction drift as points are added – and it looks like a solver bug, not a bookkeeping one.