Skip to content

confusius.multipose

multipose

Multi-pose data processing utilities.

This module provides functions for processing multi-pose fUSI data, including consolidating multiple poses into a single volume, slice timing correction, and other multi-pose specific operations.

Modules:

  • consolidate

    Multi-pose volume consolidation.

Functions:

  • consolidate_poses

    Merge pose and sweep_dim dimensions into a single axis ordered by position.

consolidate_poses

consolidate_poses(
    da: DataArray,
    affines_key: str = "physical_to_lab",
    sweep_dim: str = "z",
    rtol: float = 0.01,
) -> DataArray

Merge pose and sweep_dim dimensions into a single axis ordered by position.

For each (pose, sweep_dim) voxel, the position is computed using the sweep-dim column and translation of the per-pose affine (other spatial dims are zero at voxel centres along the sweep):

pos[p, i] = affine[p, :3, sweep_col] * sweep_mm[i] + affine[p, :3, 3]

where sweep_col is the column index of sweep_dim in the spatial dim ordering (z, y, x) → columns (0, 1, 2).

The primary sweep direction is found via singular value decomposition of all positions. Each voxel is projected onto that axis, the positions are checked for regularity, then the data is reindexed in ascending order along the consolidated sweep axis.

This function is primarily intended for consolidating multi-pose fUSI volumes acquired with an Iconeus system using a purely translational probe sweep. In that workflow, each pose corresponds to one probe position along the elevation axis (z), and the DataArray is produced by load_scan:

scan_3d = load_scan("recording.scan")       # dims: (pose, z, y, x)
volume  = consolidate_poses(scan_3d)        # dims: (z, y, x)

scan_4d = load_scan("recording_4d.scan")    # dims: (time, pose, z, y, x)
volume  = consolidate_poses(scan_4d)        # dims: (time, z, y, x)

The function also works on any DataArray that carries a (npose, 4, 4) affine stack in da.attrs["affines"][affines_key] with columns ordered as (z, y, x, translation). The sweep_dim parameter selects which spatial dimension is being swept across poses. For example, a stack of NIfTI DataArrays concatenated along a new pose dimension with their physical_to_qform affines stacked accordingly.

Parameters:

  • da

    (DataArray) –

    DataArray with a pose dimension and a (npose, 4, 4) affine stack stored in da.attrs["affines"][affines_key]. Typically produced by load_scan for 3Dscan or 4Dscan files.

  • affines_key

    (str, default: "physical_to_lab" ) –

    Key into da.attrs["affines"] that holds the (npose, 4, 4) affine stack. Column order must be (z, y, x, translation).

  • sweep_dim

    (str, default: "z" ) –

    Name of the spatial dimension being swept across poses. Must be one of the spatial dimensions in da.dims. The column index in the affine is determined by the order of spatial dimensions in the DataArray (e.g., if spatial dims are ["z", "y", "x"], then "z" → column 0, "y" → column 1, "x" → column 2).

  • rtol

    (float, default: 0.01 ) –

    Relative tolerance for the regularity check (fraction of mean spacing).

Returns:

  • DataArray

    DataArray with pose merged into sweep_dim, sorted by physical position. The consolidated sweep_dim coordinate holds the projection of each voxel's lab position (mm) onto the sweep axis. For inputs that carry a pose_time coordinate, a consolidated pose_time with dims ("time", sweep_dim) is included: each slice inherits the timestamp of the pose it came from.

Raises:

  • ValueError

    If da has no pose dimension, if sweep_dim is not one of the spatial dimensions in da.dims, if the rotation block of the affine is not constant across poses (non-translation sweep), or if the consolidated positions are not regularly spaced within rtol.

Warns:

  • UserWarning

    If the sweep is not purely 1D (secondary/primary singular value ratio > 0.01).