brain_deer.plugins.warpdrive.overlay2d

Plugin-owned 2D overlays for WarpDrive: correction glyphs and a live warped preview.

Everything here is drawn on the axial/coronal/sagittal pyqtgraph views through the generic BrainDeerAPI.add_view_overlay_item seam — the viewer never learns the word “landmark”.

Two visual layers:

  • Glyphs (cheap): source/target scatter + connector lines per correction. No warp math; redrawn on every slice change.

  • Warped preview (throttled by the caller): the normalized anat re-sampled through the current correction field, per visible slice (Lead-DBS behaviour).

Coordinate frames (easy to get wrong):

  • Correction points are RAS world millimetres.

  • The reference layer’s affine maps voxel index to RAS world mm.

  • pyqtgraph items use the same display-axis voxel frame as the base slice (world mm → reference voxel → viewer.world_to_display → (x, y)).

  • The warped-preview image is built in the raw voxel-slice frame, then run through coords.display_orient_rgb like the base slice.

Classes

WarpOverlay2D

Owns and redraws WarpDrive's 2D overlay items across the three slice views.

Module Contents

class brain_deer.plugins.warpdrive.overlay2d.WarpOverlay2D(api: Any, get_viewer: Callable[[], Any])

Owns and redraws WarpDrive’s 2D overlay items across the three slice views.

rebuild_glyphs(points: Sequence[Any], pending_source: tuple[float, float, float] | None = None, pending_target: tuple[float, float, float] | None = None) → None

Redraw source/target scatter + connector lines for all active points.

update_preview(field: Any, anat_img: Any, order: int = 1, alpha: int = 255) → None

Draw the anat warped by field on each visible slice (pull sampling).

alpha (0-255) fades the warped overlay so the atlas/template beneath it can show through for comparison; only non-background pixels are made translucent so the anat doesn’t wash the whole view.

clear_preview() → None

Remove only the warped-image overlay, keeping the glyphs.

static warp_slice(view: str, ref_affine: numpy.ndarray, ref_shape: tuple[int, int, int], anat_data: numpy.ndarray, inv_anat: numpy.ndarray, k: int, field: Any, order: int = 1) → numpy.ndarray

Warp one slice of anat_data into the reference frame (raw voxel frame).

Returns an (n0, n1) array over the view’s display_axes (a0, a1), before any display-orientation flip. Pull sampling: an output pixel at a reference position takes its intensity from field.transform_points of that position (field maps target->source), so the dragged structure renders at the target.