brain_deer.surface.projection

Volume -> surface projection and voxel-wise thresholding.

  • project_vol2surf() samples a NIfTI volume at surface vertices (optionally averaging along the vertex normal to approximate ribbon sampling), yielding a per-vertex scalar suitable for build_vertexwise_scene().

  • voxelwise_threshold() turns a volume into thresholded points/values for a voxel-wise 3D plot, accepting absolute numbers or percentile strings like '99%'.

Headless (numpy + nibabel only). Sampling uses the volume affine to map vertex mm (RAS+) into voxel space, then nearest or trilinear interpolation.

Functions

parse_threshold(→ Optional[float])

Resolve a threshold to an absolute number.

project_vol2surf(→ numpy.ndarray)

Sample volume_img at surface vertices (RAS+ mm) -> per-vertex values.

project_vol2streamlines(→ list[numpy.ndarray])

Sample volume_img at each streamline point (RAS+ mm) -> per-point values.

streamline_scalars_to_rgba(→ numpy.ndarray)

Per-point scalars (one 1D array per streamline) → flat (N, 4) uint8 RGBA via a LUT.

voxelwise_threshold(volume_img, *[, threshold, absolute])

Return (points_mm, values) for voxels passing threshold.

voxelwise_threshold_multi(→ tuple[numpy.ndarray, ...)

voxelwise_threshold() over one or several volumes, concatenated.

Module Contents

brain_deer.surface.projection.parse_threshold(threshold: float | int | str | None, values: numpy.ndarray) → float | None

Resolve a threshold to an absolute number.

  • None -> None (no threshold).

  • number -> that number.

  • '99%' / '99.5%' -> that percentile of the finite absolute values.

brain_deer.surface.projection.project_vol2surf(volume_img, vertices: numpy.ndarray, *, faces: numpy.ndarray | None = None, method: str = 'trilinear', ribbon_mm: float = 0.0, ribbon_steps: int = 3, agg: str = 'mean', dilate_vox: int = 0, ball_mm: float = 0.0) → numpy.ndarray

Sample volume_img at surface vertices (RAS+ mm) -> per-vertex values.

  • method: ‘trilinear’ (default) or ‘nearest’.

  • ribbon_mm > 0 samples along the vertex normal at +/- ribbon and aggregates (agg = ‘mean’ | ‘max’ | ‘min’); requires faces for normals.

  • dilate_vox > 1 maximum-filters positive peaks before sampling (matches sparse activation maps that look bright in 2D but miss the surface shell).

  • ball_mm > 0 takes a further max over a voxel ball around each sample (robust when hotspots sit beside the shell, not only along the normal).

brain_deer.surface.projection.project_vol2streamlines(volume_img, streamlines: Sequence[numpy.ndarray], *, method: str = 'trilinear') → list[numpy.ndarray]

Sample volume_img at each streamline point (RAS+ mm) -> per-point values.

Returns one 1D array per streamline, matching the SBA-style tractometry colouring path used by build_tracts_scene().

brain_deer.surface.projection.streamline_scalars_to_rgba(scalars: Sequence[numpy.ndarray], lut_rgba: numpy.ndarray, lo: float, hi: float, *, alpha_byte: int = 255, threshold: float | None = None) → numpy.ndarray

Per-point scalars (one 1D array per streamline) → flat (N, 4) uint8 RGBA via a LUT.

Row order matches the concatenated streamline point order — the same order used when building display polydata — so the result can be written straight onto a VTK point scalar array. Non-finite or sub-threshold samples become fully transparent; the LUT’s own alpha column is ignored in favour of alpha_byte (tract opacity lives in alpha).

brain_deer.surface.projection.voxelwise_threshold(volume_img, *, threshold: float | str | None = None, absolute: bool = True)

Return (points_mm, values) for voxels passing threshold.

Points are voxel-centre RAS+ mm coordinates (via the affine); values are the voxel intensities. threshold accepts a number or percentile string (‘99%’).

brain_deer.surface.projection.voxelwise_threshold_multi(volumes, *, threshold: float | str | None = None, absolute: bool = True) → tuple[numpy.ndarray, numpy.ndarray]

voxelwise_threshold() over one or several volumes, concatenated.

volumes is a single path/image or a list of them (e.g. the two per-hemisphere maps of a group result, which live in separate files). Each is thresholded independently and the surviving (points_mm, values) are stacked into one pair, so both sides plot in a single scene on a shared colour scale.