| Title: | Geometric Transforms for Neuroimaging Data |
|---|---|
| Description: | A self-contained, dependency-light library for geometric transforms in neuroimaging. Provides affine and nonlinear (warp) mappings between coordinate systems, plus volume-to-surface mapping primitives. Emphasizes correctness, elegance, and composability with a category-theoretic flavor. |
| Authors: | Brad Buchsbaum [aut, cre] |
| Maintainer: | Brad Buchsbaum <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0 |
| Built: | 2026-10-03 18:32:33 UTC |
| Source: | https://github.com/bbuchsbaum/neurotransform |
Returns an adjoint morphism when defined.
adjoint(object, ...) ## S4 method for signature 'Morphism' adjoint(object, ...) ## S4 method for signature 'IdentityMorphism' adjoint(object, ...) ## S4 method for signature 'Affine3DMorphism' adjoint(object, ...) ## S4 method for signature 'Warp3DMorphism' adjoint(object, ...) ## S4 method for signature 'VolToSurfMorphism' adjoint(object, ...) ## S4 method for signature 'SurfToSurfMorphism' adjoint(object, ...)adjoint(object, ...) ## S4 method for signature 'Morphism' adjoint(object, ...) ## S4 method for signature 'IdentityMorphism' adjoint(object, ...) ## S4 method for signature 'Affine3DMorphism' adjoint(object, ...) ## S4 method for signature 'Warp3DMorphism' adjoint(object, ...) ## S4 method for signature 'VolToSurfMorphism' adjoint(object, ...) ## S4 method for signature 'SurfToSurfMorphism' adjoint(object, ...)
object |
A Morphism object |
... |
Additional arguments |
For invertible morphisms, adjoint() is defined and equals invert().
For other morphisms, adjoint() may not be implemented and will error.
Adjoint morphism or error if not available
Wrap an affine matrix built from components into an Affine3DMorphism
affine_from_components(source, target, ...)affine_from_components(source, target, ...)
source |
Source domain identifier |
target |
Target domain identifier |
... |
Arguments passed to |
Affine3DMorphism object
Lightweight helpers for building, decomposing, and testing affine transforms without introducing external dependencies or tool-specific semantics.
Represents an affine transformation between volume spaces. The matrix maps target coords -> source coords (pullback semantics).
Affine3DMorphism(source, target, matrix, cost = 1, method_tag = "anatomical")Affine3DMorphism(source, target, matrix, cost = 1, method_tag = "anatomical")
source |
Source domain hash |
target |
Target domain hash |
matrix |
4x4 affine matrix (target -> source) |
cost |
Path cost (default 1.0) |
method_tag |
Method tag (default "anatomical") |
Affine3DMorphism object
# Translation by (10, 20, 30) mat <- diag(4) mat[1:3, 4] <- c(10, 20, 30) aff <- Affine3DMorphism("native", "mni", mat)# Translation by (10, 20, 30) mat <- diag(4) mat[1:3, 4] <- c(10, 20, 30) aff <- Affine3DMorphism("native", "mni", mat)
Represents an affine transformation (rotation, translation, scaling, shear) between volume spaces.
matrix4x4 affine transformation matrix (maps target -> source)
Converts an AFNI RAI/DICOM affine matrix to our internal RAS convention by
flipping the X and Y axes. Optionally applies AFNI-style deobliquing
compensation when source/target image affines are provided. Standard
3dAllineate -1Dmatrix_save matrices map base/target coordinates to
source/input coordinates, which is already the package's pullback direction.
afni_aff12_to_ras( mat_rai, source_affine = NULL, target_affine = NULL, oblique_correction = TRUE )afni_aff12_to_ras( mat_rai, source_affine = NULL, target_affine = NULL, oblique_correction = TRUE )
mat_rai |
4x4 affine in RAI coordinates |
source_affine |
Optional 4x4 source (moving) voxel-to-world affine |
target_affine |
Optional 4x4 target (reference) voxel-to-world affine |
oblique_correction |
Logical; apply AFNI cardinal rotation correction |
4x4 affine in RAS coordinates
mat_rai <- diag(4) mat_ras <- afni_aff12_to_ras(mat_rai)mat_rai <- diag(4) mat_ras <- afni_aff12_to_ras(mat_rai)
Detect whether an affine is oblique (not cardinal axis-aligned)
afni_is_oblique(affine, threshold_deg = 0.01)afni_is_oblique(affine, threshold_deg = 0.01)
affine |
4x4 voxel-to-world affine |
threshold_deg |
Angular threshold in degrees |
Logical
Reads a single affine from a .aff12.1D file and returns it as a 4x4
matrix in AFNI RAI/DICOM coordinates. AFNI axis labels describe the negative
end of each axis, so numeric RAI coordinates increase toward Left, Posterior,
and Superior (LPS).
afni_read_aff12(path, row = NULL)afni_read_aff12(path, row = NULL)
path |
Path to |
row |
Optional 1-based row to select from a multi-row file. Required when the file holds more than one matrix. |
4x4 affine matrix (in RAI)
afni_read_aff12_array for per-volume matrix series
## Not run: mat_rai <- afni_read_aff12("transform.aff12.1D") ## End(Not run)## Not run: mat_rai <- afni_read_aff12("transform.aff12.1D") ## End(Not run)
Reads all matrix rows, returning one 4x4 matrix per row in AFNI RAI/DICOM
coordinates. Comment lines are returned in the "comments" attribute.
afni_read_aff12_array(path)afni_read_aff12_array(path)
path |
Path to a |
A list of 4x4 matrices in RAI, with a "comments" attribute
holding the file's comment lines
afni_read_aff12 for a single-matrix file
path <- tempfile(fileext = ".aff12.1D") afni_write_aff12(list(diag(4), diag(4)), path) length(afni_read_aff12_array(path))path <- tempfile(fileext = ".aff12.1D") afni_write_aff12(list(diag(4), diag(4)), path) length(afni_read_aff12_array(path))
AFNI-specific coordinate convention handling. AFNI 3dQwarp stores displacement fields in DICOM/LPS convention. These functions handle the LPS <-> RAS conversion for warps and RAI <-> RAS for affines.
RAI/DICOM (used by AFNI affines and warp displacements): +X=Left, +Y=Posterior, +Z=Superior (numerically LPS)
RAS (NIfTI/neuroim2): +X=Right, +Y=Anterior, +Z=Superior
LPS to RAS: negate X and Y (Z is the same).
Writes matrices in AFNI's canonical layout: one row of twelve row-major
numbers per matrix, optionally preceded by a banner comment. This is the
layout 3dAllineate -1Dmatrix_apply expects.
afni_write_aff12(x, path, comment = TRUE)afni_write_aff12(x, path, comment = TRUE)
x |
A 4x4 (or 3x4) matrix in RAI, or a list of them |
path |
Output path |
comment |
Logical, or a character vector of comment lines to write as a
header. |
Invisibly, path
path <- tempfile(fileext = ".aff12.1D") afni_write_aff12(diag(4), path)path <- tempfile(fileext = ".aff12.1D") afni_write_aff12(diag(4), path)
S4 class definitions for the neurotransform package. This file defines the morphism class hierarchy. neurotransform is a pure transform kernel; domain and geometry abstractions live in higher-level packages.
Morphism (virtual) |-- IdentityMorphism |-- Affine3DMorphism |-- Warp3DMorphism |-- VolToSurfMorphism |-- SurfToSurfMorphism MorphismPath (lightweight list wrapper for composed paths)
A morphism A -> B maps coordinates in B to coordinates in A (pullback semantics). This is the natural convention for resampling: to get a value at target location, you need to know where to sample from in the source.
Generic function definitions for the neurotransform package. These define the core API for coordinate transforms.
Creates a morphism (or MorphismPath) from an ANTs composite H5 transform file. These files typically contain both a displacement field and an affine transform.
ants_h5_morphism( path, source = "source", target = "target", apply_affine = TRUE )ants_h5_morphism( path, source = "source", target = "target", apply_affine = TRUE )
path |
Path to ANTs H5 file |
source |
Source coordinate space identifier |
target |
Target coordinate space identifier |
apply_affine |
If TRUE and an embedded affine is present, return a MorphismPath combining warp and affine. If FALSE, return only the warp. |
Warp3DMorphism (if no affine or apply_affine=FALSE), MorphismPath,
or Affine3DMorphism for an affine-only H5 file. For an affine-only file,
apply_affine=FALSE is an error because there is no displacement field.
When apply_affine=TRUE, the H5 component order is preserved in the returned
MorphismPath. Both ITK composite transforms and MorphismPath evaluate the
stored components from last to first, so preserving the order reproduces ITK
point-transform semantics.
Generic function to apply a 4x4 affine matrix to 3D coordinates.
apply_affine(coords, affine)apply_affine(coords, affine)
coords |
Numeric matrix (N x 3) or vector of length 3 |
affine |
4x4 affine transformation matrix |
Transformed coordinates
coords <- matrix(c(10, 20, 30), ncol = 3) affine <- diag(4) affine[1:3, 4] <- c(5, 10, 15) # translation apply_affine(coords, affine)coords <- matrix(c(10, 20, 30), ncol = 3) affine <- diag(4) affine[1:3, 4] <- c(5, 10, 15) # translation apply_affine(coords, affine)
Apply a resampling plan to a volume
apply_resampling_plan( plan, source_data, outside = NA_real_, modulate = c("none", "jacobian", "sqrt_jacobian") )apply_resampling_plan( plan, source_data, outside = NA_real_, modulate = c("none", "jacobian", "sqrt_jacobian") )
plan |
ResamplingPlan |
source_data |
3D or 4D array in source_grid geometry |
outside |
Value for out-of-bounds sampling |
modulate |
Jacobian modulation: "none", "jacobian", "sqrt_jacobian" |
Array with target_grid dimensions (and trailing data dim if 4D input)
Applies the transpose of the exact forward operator, including fixed masks
and the selected normalization, without renormalizing its transpose. This is
an algebraic adjoint, not reverse geometric interpolation or reconstruction.
Unsupported source columns receive algebraic zero; details=TRUE identifies
them. Missing-data omission is not a fixed linear operator and is unsupported.
apply_surface_adjoint( plan, x, normalize = c("element", "sum", "none"), details = FALSE )apply_surface_adjoint( plan, x, normalize = c("element", "sum", "none"), details = FALSE )
plan |
A |
x |
Numeric vector or matrix with one row per reference vertex. |
normalize |
Forward-operator normalization: |
details |
Return values and supported-source-column diagnostics. |
Vector/matrix or a list with values and available.
Geometry, source ROI mass and finite-data mass are distinct. Unsupported or
masked outputs are unavailable (NA), while supported numerical zero remains
zero. Zero-weight missing inputs never contaminate an output. Omission returns
the retained raw weight mass as an attribute, or in the detailed result.
apply_surface_resampling( plan, x, inverse = FALSE, normalize = c("element", "sum", "none"), na_policy = c("propagate", "omit", "error"), data_type = c("continuous", "label"), label_method = c("aggregate", "largest"), label_table = NULL, unassigned = NA_integer_, details = FALSE )apply_surface_resampling( plan, x, inverse = FALSE, normalize = c("element", "sum", "none"), na_policy = c("propagate", "omit", "error"), data_type = c("continuous", "label"), label_method = c("aggregate", "largest"), label_table = NULL, unassigned = NA_integer_, details = FALSE )
plan |
A |
x |
Numeric vertex vector or matrix with |
inverse |
Legacy transpose followed by normalization. Deprecated; use
|
normalize |
|
na_policy |
|
data_type |
|
label_method |
|
label_table |
Optional data frame with a unique integer |
unassigned |
Integer output key for unavailable labels, or |
details |
Return values and per-column coverage diagnostics. |
Label keys are never averaged. Aggregate voting sums weights for each key; largest voting selects one source vertex. Ties select the smallest label key for aggregate voting and the smallest source vertex index for largest voting.
Vector/matrix, or a list when details=TRUE. Diagnostics include raw
source and finite-data weight mass before normalization and target masking.
Adaptive plans also report source_roi_target_area before target masking.
effective_target_area is available only for row normalization, and is
column specific under omission. With finite continuous data and no target
exclusion it gives the area identity described in the surface vignette.
File paths are read with read_transform() and no further arguments.
FSL warps need image geometry that a path alone does not carry, so read
them with read_transform(..., source_affine, source_dim) and pass the
resulting morphisms instead.
as_morphism_path(...)as_morphism_path(...)
... |
Morphism objects or file paths to transforms |
MorphismPath object
Implements a simple backprojection operator that distributes each surface value into the source volume grid using the same interpolation weights that forward sampling would use.
backproject_surface_to_volume( surface_values, morphism, grid, surface_coords = NULL, method = c("linear", "nearest", "ribbon"), outside = 0 )backproject_surface_to_volume( surface_values, morphism, grid, surface_coords = NULL, method = c("linear", "nearest", "ribbon"), outside = 0 )
surface_values |
Numeric vector (length N) or matrix (N x k) of values at surface points |
morphism |
VolToSurfMorphism |
grid |
Source Grid (volume geometry) |
surface_coords |
Optional N x 3 world coordinates; defaults to morphism@params$mid_coords |
method |
"linear", "nearest", or "ribbon" |
outside |
Value used for out-of-bounds (default 0) |
This is the transpose/adjoint of the linear sampling operator for
sample_volume_on_surface(..., method="linear") when the same
surface_coords are used.
3D array (or 4D if multivariate surface_values) in grid geometry
Build a 4x4 affine matrix from components
build_affine_matrix( translation = c(0, 0, 0), scales = c(1, 1, 1), skews = c(0, 0, 0), angles = c(0, 0, 0), anchor = c("none", "origin", "centre", "center") )build_affine_matrix( translation = c(0, 0, 0), scales = c(1, 1, 1), skews = c(0, 0, 0), angles = c(0, 0, 0), anchor = c("none", "origin", "centre", "center") )
translation |
length-3 translation vector (applied last) |
scales |
length-3 scaling |
skews |
length-3 shear terms (xy, xz, yz) |
angles |
length-3 rotation angles (radians) about x, y, z (applied in Z-Y-X order) |
anchor |
Either |
4x4 numeric matrix
Returns the composition g . f (f applied first, then g). The result is a MorphismPath that can be passed to transform().
compose(f, g) ## S4 method for signature 'Morphism,Morphism' compose(f, g) ## S4 method for signature 'MorphismPath,Morphism' compose(f, g) ## S4 method for signature 'Morphism,MorphismPath' compose(f, g) ## S4 method for signature 'MorphismPath,MorphismPath' compose(f, g)compose(f, g) ## S4 method for signature 'Morphism,Morphism' compose(f, g) ## S4 method for signature 'MorphismPath,Morphism' compose(f, g) ## S4 method for signature 'Morphism,MorphismPath' compose(f, g) ## S4 method for signature 'MorphismPath,MorphismPath' compose(f, g)
f |
First morphism (applied first) |
g |
Second morphism (applied second) |
MorphismPath representing the composition
aff1 <- Affine3DMorphism("a", "b", diag(4)) aff2 <- Affine3DMorphism("b", "c", diag(4)) path <- compose(aff1, aff2) # a -> b -> caff1 <- Affine3DMorphism("a", "b", diag(4)) aff2 <- Affine3DMorphism("b", "c", diag(4)) path <- compose(aff1, aff2) # a -> b -> c
Returns the composition B(A(x)) = BA * x.
compose_affines(A, B)compose_affines(A, B)
A |
First affine (applied first) |
B |
Second affine (applied second) |
Composed 4x4 affine matrix
A <- diag(4); A[1:3, 4] <- c(1, 2, 3) B <- diag(4); B[1:3, 4] <- c(4, 5, 6) compose_affines(A, B)A <- diag(4); A[1:3, 4] <- c(1, 2, 3) B <- diag(4); B[1:3, 4] <- c(4, 5, 6) compose_affines(A, B)
Creates a reproducible hash using digest with serialize=TRUE.
compute_hash(..., algo = "xxhash64")compute_hash(..., algo = "xxhash64")
... |
Objects to hash |
algo |
Hash algorithm (default "xxhash64" for speed) |
Character string hash
compute_hash("hello", "world") compute_hash(list(a = 1, b = 2))compute_hash("hello", "world") compute_hash(list(a = 1, b = 2))
Convert affine conventions between "generic" (target→source world) and "fsl" (source→target vox)
convert_affine_convention( matrix, source_affine, target_affine, source_dim = NULL, target_dim = NULL, from = c("generic", "fsl"), to = c("generic", "fsl") )convert_affine_convention( matrix, source_affine, target_affine, source_dim = NULL, target_dim = NULL, from = c("generic", "fsl"), to = c("generic", "fsl") )
matrix |
4x4 matrix in the |
source_affine |
4x4 voxel-to-world for source image |
target_affine |
4x4 voxel-to-world for target image |
source_dim |
Optional source image dimensions (for FSL handedness swap) |
target_dim |
Optional target image dimensions (for FSL handedness swap) |
from |
Input convention ("generic", "fsl") |
to |
Output convention ("generic", "fsl") |
Functions for converting between coordinate conventions used in neuroimaging.
Internal convention: RAS (Right-Anterior-Superior) in millimeters.
RAS: Right-Anterior-Superior (internal standard)
LPS: Left-Posterior-Superior (ANTs/ITK convention)
tkRAS: FreeSurfer tkregister RAS
FSL: FSL world coordinates (mm, may need scaling)
Apply affines -> warp -> affines to coordinates (target -> source)
cpp_path_apply_affine_warp_affine( coords, affines_pre, field, dim, world_to_vox, cubic, affines_post )cpp_path_apply_affine_warp_affine( coords, affines_pre, field, dim, world_to_vox, cubic, affines_post )
coords |
n x 3 target world coords |
affines_pre |
list of 4x4 matrices applied before warp |
field |
displacement field |
dim |
field dims |
world_to_vox |
warp world_to_vox |
cubic |
use cubic sampling |
affines_post |
list of 4x4 matrices applied after warp |
n x 3 source world coords
Apply arbitrary steps (affine/warp) to coordinates (target -> source)
cpp_path_apply_steps(coords, steps)cpp_path_apply_steps(coords, steps)
coords |
n x 3 target world coords |
steps |
list of steps with kind \"affine\" or \"warp\" and associated data |
n x 3 transformed coords
Decompose a 4x4 affine matrix into components
decompose_affine_matrix(matrix)decompose_affine_matrix(matrix)
matrix |
4x4 numeric matrix |
list with translation, rotation_matrix, scales, skews, angles
Helpers to materialize morphisms on voxel grids for visualization or export, keeping the core morphism API untouched.
deformation_field(morphism, grid, with_jacobian = TRUE, log = FALSE)deformation_field(morphism, grid, with_jacobian = TRUE, log = FALSE)
morphism |
A Morphism (affine or warp) |
grid |
A Grid object (see grid_spec/grid_from_data) |
with_jacobian |
Logical; attach Jacobian determinant volume |
log |
If TRUE, store log-Jacobian |
An array with dim = c(grid@dims, 3) and class "DeformationField"
Determines whether a dense FSL warp stores relative displacements or absolute source coordinates, using two kinds of evidence on a regular subsample of non-zero lattice vectors:
Field of view (when source_affine and source_dim are
given): the reading whose implied source FSL coordinates fall inside the
source image (within one voxel) for a clearly larger fraction of samples
(by at least 0.25) wins.
Jacobian: field values are fitted as in
reference FSL coordinates, so the implied reference-to-source Jacobian is
(absolute) or (relative). A reading wins when the
other implies a volume change at least twice as extreme
( larger by ).
The field-of-view test decides first. If neither is decisive the function
stops rather than guess; pass def_type explicitly in that case.
Scaled or axis-permuted mappings (e.g. a small or sagittally stored source)
can make the Jacobian test ambiguous, which the field-of-view test resolves.
detect_fnirt_def_type( warp_path, sample_n = 1000, threshold_mm = NULL, source_affine = NULL, source_dim = NULL )detect_fnirt_def_type( warp_path, sample_n = 1000, threshold_mm = NULL, source_affine = NULL, source_dim = NULL )
warp_path |
Path to FNIRT warp file |
sample_n |
Approximate number of lattice points sampled |
threshold_mm |
Deprecated and ignored; retained for compatibility. |
source_affine, source_dim
|
Optional source image voxel-to-RAS affine and dimensions, enabling the field-of-view test. |
"relative" or "absolute"
## Not run: def_type <- detect_fnirt_def_type("warp.nii.gz", source_affine = src_affine, source_dim = src_dim) ## End(Not run)## Not run: def_type <- detect_fnirt_def_type("warp.nii.gz", source_affine = src_affine, source_dim = src_dim) ## End(Not run)
NIfTI vector fields are classified from the header before the filename:
FSL intent codes 2006 (dense field) and 2007–2009 (coefficients) and the
ITK vector layout (5D with intent 1007) are definitive. Otherwise filename
hints apply, then the layout: a 4D (X, Y, Z, 3) field is FSL's
layout (ITK/ANTs cannot read it), and remaining fields default to ANTs.
Dense FSL fields need source image geometry, so an FSL result is only
usable with source_affine and source_dim.
detect_transform_type(path, source_affine = NULL, target_affine = NULL)detect_transform_type(path, source_affine = NULL, target_affine = NULL)
path |
Transform file path |
source_affine |
Optional source affine used to disambiguate linear files |
target_affine |
Optional target affine used to disambiguate linear files |
Character scalar naming the detected transform family
Convenience wrapper returning the Dice coefficient from overlap_metrics().
dice_coefficient( x, y, threshold = 0, label = NULL, na.rm = TRUE, empty = c("one", "zero", "na"), check_geometry = TRUE, tolerance = sqrt(.Machine$double.eps) )dice_coefficient( x, y, threshold = 0, label = NULL, na.rm = TRUE, empty = c("one", "zero", "na"), check_geometry = TRUE, tolerance = sqrt(.Machine$double.eps) )
x, y
|
Arrays or image objects with matching dimensions. |
threshold |
Numeric scalar used to form foreground masks when |
label |
Optional single label value. If supplied, Dice is computed for that label instead of by thresholding. |
na.rm |
Logical; if |
empty |
How to score Dice, Jaccard, overlap coefficient, and volume
similarity when both masks are empty. |
check_geometry |
Logical; if |
tolerance |
Numeric tolerance used for affine comparisons. |
Numeric scalar Dice coefficient.
x <- array(c(TRUE, TRUE, FALSE, FALSE), dim = c(2, 2, 1)) y <- array(c(TRUE, FALSE, TRUE, FALSE), dim = c(2, 2, 1)) dice_coefficient(x, y)x <- array(c(TRUE, TRUE, FALSE, FALSE), dim = c(2, 2, 1)) y <- array(c(TRUE, FALSE, TRUE, FALSE), dim = c(2, 2, 1)) dice_coefficient(x, y)
Extract affine matrix from data
extract_affine(x) ## S4 method for signature 'array' extract_affine(x) ## S4 method for signature 'matrix' extract_affine(x) ## S4 method for signature 'ANY' extract_affine(x) ## S4 method for signature 'DenseNeuroVol' extract_affine(x) ## S4 method for signature 'DenseNeuroVec' extract_affine(x)extract_affine(x) ## S4 method for signature 'array' extract_affine(x) ## S4 method for signature 'matrix' extract_affine(x) ## S4 method for signature 'ANY' extract_affine(x) ## S4 method for signature 'DenseNeuroVol' extract_affine(x) ## S4 method for signature 'DenseNeuroVec' extract_affine(x)
x |
Data object |
4x4 affine matrix
Given a FLIRT matrix (source_FSL -> ref_FSL), returns the internal ref_world -> src_world affine for pullback semantics.
fsl_flirt_to_internal_affine( flirt_mat, source_affine, ref_affine, source_dim = NULL, ref_dim = NULL )fsl_flirt_to_internal_affine( flirt_mat, source_affine, ref_affine, source_dim = NULL, ref_dim = NULL )
flirt_mat |
4x4 FLIRT matrix |
source_affine |
4x4 voxel-to-world for source image |
ref_affine |
4x4 voxel-to-world for reference image |
source_dim |
Optional source image dimensions (needed for handedness swap) |
ref_dim |
Optional reference image dimensions (needed for handedness swap) |
4x4 internal affine (ref_world -> src_world)
## Not run: flirt_mat <- as.matrix(read.table("xform.mat")) src_aff <- diag(4) # from source image header ref_aff <- diag(4) # from reference image header internal <- fsl_flirt_to_internal_affine(flirt_mat, src_aff, ref_aff) ## End(Not run)## Not run: flirt_mat <- as.matrix(read.table("xform.mat")) src_aff <- diag(4) # from source image header ref_aff <- diag(4) # from reference image header internal <- fsl_flirt_to_internal_affine(flirt_mat, src_aff, ref_aff) ## End(Not run)
FSL-specific coordinate convention handling. FSL uses scaled voxel coordinates for FLIRT matrices and has specific conventions for FNIRT warp fields (relative vs absolute).
Returns a small factory descriptor for linear transform IO, including canonical format and reader/writer function handles.
get_linear_factory(fmt, is_array = TRUE)get_linear_factory(fmt, is_array = TRUE)
fmt |
Format name (e.g. |
is_array |
Logical; if |
List with format, reader, and writer
Gets a loader function from the registry.
get_loader(name = NULL) get_warp_loader(name = NULL)get_loader(name = NULL) get_warp_loader(name = NULL)
name |
Loader name (default "neuroim2") |
Loader function
loader <- get_loader("neuroim2")loader <- get_loader("neuroim2")
Get world coordinates for a grid
grid_coords(grid)grid_coords(grid)
grid |
Grid object |
Numeric matrix (prod(dims) x 3)
Get grid specification from volume data
grid_from_data(data)grid_from_data(data)
data |
Volume with geometry |
Grid object
Extract Grid from volume or grid-like input
grid_of(x)grid_of(x)
x |
neuroim2 volume, array, or Grid |
Grid
Create a grid specification
grid_spec(dims, affine)grid_spec(dims, affine)
dims |
Integer vector of dimensions |
affine |
4x4 voxel-to-world matrix |
Grid object
Grid: regular coordinate grid specification
## S4 method for signature 'Grid' show(object)## S4 method for signature 'Grid' show(object)
object |
A Grid object (for show method) |
dimsInteger: grid dimensions
affine4x4 voxel-to-world matrix
Returns TRUE if adjoint() is available for this morphism.
For linear/invertible morphisms, the adjoint is the inverse.
has_adjoint(object)has_adjoint(object)
object |
A Morphism object |
Logical
The identity morphism maps a domain to itself. Cost is 0.
IdentityMorphism(domain)IdentityMorphism(domain)
domain |
Domain hash string |
IdentityMorphism object
id <- IdentityMorphism("my_domain_hash")id <- IdentityMorphism("my_domain_hash")
The identity morphism maps a domain to itself. Required for categorical structure and useful for composition.
Returns the inverse morphism if available (inverse_type == "exact" or "approximate"). For morphisms with approximate or adjoint inverses, use adjoint() instead.
invert(object) ## S4 method for signature 'Morphism' invert(object) ## S4 method for signature 'IdentityMorphism' invert(object) ## S4 method for signature 'Affine3DMorphism' invert(object) ## S4 method for signature 'Warp3DMorphism' invert(object)invert(object) ## S4 method for signature 'Morphism' invert(object) ## S4 method for signature 'IdentityMorphism' invert(object) ## S4 method for signature 'Affine3DMorphism' invert(object) ## S4 method for signature 'Warp3DMorphism' invert(object)
object |
A Morphism object |
Inverted morphism
aff <- Affine3DMorphism("a", "b", diag(4)) inv <- invert(aff) # b -> aaff <- Affine3DMorphism("a", "b", diag(4)) inv <- invert(aff) # b -> a
Invert an affine transformation
invert_affine(affine)invert_affine(affine)
affine |
4x4 affine matrix |
Inverted 4x4 affine matrix
affine <- diag(4) affine[1:3, 4] <- c(5, 10, 15) inv <- invert_affine(affine)affine <- diag(4) affine[1:3, 4] <- c(5, 10, 15) inv <- invert_affine(affine)
Check if an object is a numeric 4x4 affine matrix
is_affine_matrix(x)is_affine_matrix(x)
x |
Object to test |
Logical
Check if an object is an Affine3DMorphism
is_affine_morphism(x)is_affine_morphism(x)
x |
Object to test |
Logical
Returns TRUE only if a geometric inverse is available via invert().
is_invertible(object)is_invertible(object)
object |
A Morphism object |
Logical
aff <- Affine3DMorphism("a", "b", diag(4)) is_invertible(aff) # TRUEaff <- Affine3DMorphism("a", "b", diag(4)) is_invertible(aff) # TRUE
Check if morphism is linear (affine or identity)
is_linear_morphism(object)is_linear_morphism(object)
object |
A Morphism object |
Logical
Returns TRUE if the path is composable, FALSE otherwise.
is_valid_path(path)is_valid_path(path)
path |
List of Morphism objects |
Logical
aff1 <- Affine3DMorphism("a", "b", diag(4)) aff2 <- Affine3DMorphism("b", "c", diag(4)) is_valid_path(list(aff1, aff2)) # TRUEaff1 <- Affine3DMorphism("a", "b", diag(4)) aff2 <- Affine3DMorphism("b", "c", diag(4)) is_valid_path(list(aff1, aff2)) # TRUE
Check if morphism is a warp field
is_warp_morphism(object)is_warp_morphism(object)
object |
A Morphism object |
Logical
Convenience wrapper returning the Jaccard index from overlap_metrics().
jaccard_index( x, y, threshold = 0, label = NULL, na.rm = TRUE, empty = c("one", "zero", "na"), check_geometry = TRUE, tolerance = sqrt(.Machine$double.eps) )jaccard_index( x, y, threshold = 0, label = NULL, na.rm = TRUE, empty = c("one", "zero", "na"), check_geometry = TRUE, tolerance = sqrt(.Machine$double.eps) )
x, y
|
Arrays or image objects with matching dimensions. |
threshold |
Numeric scalar used to form foreground masks when |
label |
Optional single label value. If supplied, Dice is computed for that label instead of by thresholding. |
na.rm |
Logical; if |
empty |
How to score Dice, Jaccard, overlap coefficient, and volume
similarity when both masks are empty. |
check_geometry |
Logical; if |
tolerance |
Numeric tolerance used for affine comparisons. |
Numeric scalar Jaccard index.
x <- array(c(1, 1, 0, 0), dim = c(2, 2, 1)) y <- array(c(1, 0, 1, 0), dim = c(2, 2, 1)) jaccard_index(x, y)x <- array(c(1, 1, 0, 0), dim = c(2, 2, 1)) y <- array(c(1, 0, 1, 0), dim = c(2, 2, 1)) jaccard_index(x, y)
Compute Jacobian matrices and determinants for morphisms. The Jacobian is the derivative of the coordinate transformation.
jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'IdentityMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'Affine3DMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'Warp3DMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'MorphismPath,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'VolToSurfMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'SurfToSurfMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'DeformationField,missing' jacobian(morphism, coords, mode = c("pullback", "pushforward"))jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'IdentityMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'Affine3DMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'Warp3DMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'MorphismPath,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'VolToSurfMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'SurfToSurfMorphism,ANY' jacobian(morphism, coords, mode = c("pullback", "pushforward")) ## S4 method for signature 'DeformationField,missing' jacobian(morphism, coords, mode = c("pullback", "pushforward"))
morphism |
A Morphism or MorphismPath |
coords |
Numeric matrix (n x 3) of coordinates |
mode |
"pullback" (default) or "pushforward" |
JacobianField object
For a morphism with pullback semantics (transform maps target -> source), the pullback Jacobian is d(source)/d(target), evaluated at target coordinates.
"pullback": d(source)/d(target) - natural for resampling
"pushforward": d(target)/d(source) - requires invertible morphism
aff <- Affine3DMorphism("a", "b", diag(4)) coords <- matrix(c(0, 0, 0, 10, 20, 30), ncol = 3, byrow = TRUE) J <- jacobian(aff, coords)aff <- Affine3DMorphism("a", "b", diag(4)) coords <- matrix(c(0, 0, 0, 10, 20, 30), ncol = 3, byrow = TRUE) J <- jacobian(aff, coords)
Compute Jacobian determinants
jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'IdentityMorphism' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'Affine3DMorphism' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'Warp3DMorphism' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'MorphismPath' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") )jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'IdentityMorphism' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'Affine3DMorphism' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'Warp3DMorphism' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") ) ## S4 method for signature 'MorphismPath' jacobian_det( morphism, coords, log = FALSE, mode = c("pullback", "pushforward") )
morphism |
A Morphism or MorphismPath |
coords |
Numeric matrix (n x 3) of coordinates |
log |
Return log(|det(J)|)? |
mode |
"pullback" or "pushforward" |
Numeric vector of determinants
aff <- Affine3DMorphism("a", "b", diag(4) * 2) coords <- matrix(c(0, 0, 0), ncol = 3) jacobian_det(aff, coords) # 8 (2^3) jacobian_det(aff, coords, log = TRUE) # log(8)aff <- Affine3DMorphism("a", "b", diag(4) * 2) coords <- matrix(c(0, 0, 0), ncol = 3) jacobian_det(aff, coords) # 8 (2^3) jacobian_det(aff, coords, log = TRUE) # log(8)
Extract Jacobian determinant volume from a morphism on a grid
jacobian_det_field(morphism, grid, log = FALSE)jacobian_det_field(morphism, grid, log = FALSE)
morphism |
A Morphism (affine or warp) |
grid |
A Grid object |
log |
Logical; if TRUE, return log-Jacobian determinants |
Array with grid dimensions containing Jacobian determinants
Jacobian field: collection of 3x3 Jacobian matrices
Extract single Jacobian matrix or subset
Number of Jacobians
Compute determinants
Invert Jacobians (for mode switching)
## S4 method for signature 'JacobianField' show(object) ## S4 method for signature 'JacobianField,numeric,ANY,ANY' x[i, j, ..., drop = TRUE] ## S4 method for signature 'JacobianField' length(x) ## S4 method for signature 'JacobianField' det(x, ...) ## S4 method for signature 'JacobianField,missing' solve(a, b, ...)## S4 method for signature 'JacobianField' show(object) ## S4 method for signature 'JacobianField,numeric,ANY,ANY' x[i, j, ..., drop = TRUE] ## S4 method for signature 'JacobianField' length(x) ## S4 method for signature 'JacobianField' det(x, ...) ## S4 method for signature 'JacobianField,missing' solve(a, b, ...)
object |
A JacobianField object (for show method) |
x |
A JacobianField object (for other methods) |
i |
Numeric index for subsetting |
j |
Second index (optional) |
... |
Additional arguments |
drop |
Logical; if TRUE drop dimensions |
a |
A JacobianField object (for solve method) |
b |
Missing (solve method signature) |
valuesNumeric array (n x 3 x 3) of Jacobian matrices
coordsNumeric matrix (n x 3) of coordinate locations
modeCharacter: "pullback" or "pushforward"
morphism_hashHash of source morphism
List all registered loaders
list_loaders()list_loaders()
Character vector of registered loader names
list_loaders()list_loaders()
ANTs and ITK use LPS (Left-Posterior-Superior) convention. This function converts to our internal RAS convention by flipping the first two axes.
lps_to_ras(coords)lps_to_ras(coords)
coords |
Numeric matrix (N x 3) or vector of length 3 in LPS |
Coordinates in RAS convention
lps <- c(-10, -20, 30) ras <- lps_to_ras(lps)lps <- c(-10, -20, 30) ras <- lps_to_ras(lps)
Read/write FreeSurfer LTA linear transform files (single or array forms).
Build a resampling plan
make_resampling_plan( morphism, source_grid, target_grid, interpolation = c("linear", "cubic", "nearest"), reuse_count = 1L, cache = TRUE )make_resampling_plan( morphism, source_grid, target_grid, interpolation = c("linear", "cubic", "nearest"), reuse_count = 1L, cache = TRUE )
morphism |
Morphism or MorphismPath |
source_grid |
Grid describing the source volume geometry |
target_grid |
Grid describing the target geometry |
interpolation |
"linear", "cubic", or "nearest" |
reuse_count |
Hint for expected reuse; >1 enables caching |
cache |
Logical; cache the plan by hash |
A ResamplingPlan object
Check whether a surface mesh is approximately spherical
mesh_is_sphere(mesh, tolerance = 1.001)mesh_is_sphere(mesh, tolerance = 1.001)
mesh |
SurfaceMesh object |
tolerance |
Ratio tolerance for min/max radius comparison |
Logical
Set mesh radius for spherical meshes
mesh_set_radius(mesh, radius = 100)mesh_set_radius(mesh, radius = 100)
mesh |
SurfaceMesh object |
radius |
Target radius |
SurfaceMesh object with rescaled coordinates
Constructors and methods for morphism classes. Morphisms represent coordinate transformations with pullback semantics.
Creates a stable hash from morphism properties for identity and caching.
morphism_hash(object)morphism_hash(object)
object |
A Morphism object |
Character hash string
Returns the morphism kind (identity, affine3d, warp3d, vol2surf, surf2surf).
morphism_kind(object)morphism_kind(object)
object |
A Morphism object |
Character string indicating kind
aff <- Affine3DMorphism("a", "b", diag(4)) morphism_kind(aff) # "affine3d"aff <- Affine3DMorphism("a", "b", diag(4)) morphism_kind(aff) # "affine3d"
A Morphism represents a coordinate transformation between domains. Direction convention: a morphism A -> B maps coordinates in B to coordinates in A (pullback semantics). Data flows opposite: from A to B.
## S4 method for signature 'Morphism' show(object)## S4 method for signature 'Morphism' show(object)
object |
A Morphism object (for show method) |
idCharacter identifier
sourceCharacter: source domain hash (opaque string)
targetCharacter: target domain hash (opaque string)
kindCharacter morphism kind (identity, affine3d, warp3d, vol2surf, surf2surf)
paramsList: forward params/metadata
inverse_paramsList: inverse params/metadata
method_tagCharacter: path selection tag (anatomical/functional/etc.)
coverageOptional mask/metadata for valid region
costNumeric: cost/weight for graph traversal
hashStable hash of morphism
inverse_typeOne of "exact", "approximate", "adjoint", "none"
inverse_qualityNumeric in range 0 to 1, optional confidence for inverse
inverse_methodDescription/label for inverse strategy
provenanceList: metadata about the transform origin
cacheEnvironment for cached data
A lightweight wrapper around a list of morphisms representing a composed path. When passed to transform(), applies the full sequence efficiently. Order convention: path = list(f, g) means f first, then g (like g . f).
morphismsList of Morphism objects
sourceSource domain hash (from first morphism)
targetTarget domain hash (from last morphism)
Compute voxelwise overlap summaries for two images or masks. Inputs may be
plain arrays or image objects that can be coerced with as.array(), including
neuroim2 volumes.
overlap_metrics( x, y, threshold = 0, labels = NULL, na.rm = TRUE, empty = c("one", "zero", "na"), check_geometry = TRUE, tolerance = sqrt(.Machine$double.eps) )overlap_metrics( x, y, threshold = 0, labels = NULL, na.rm = TRUE, empty = c("one", "zero", "na"), check_geometry = TRUE, tolerance = sqrt(.Machine$double.eps) )
x, y
|
Arrays or image objects with matching dimensions. |
threshold |
Numeric scalar used to form foreground masks when |
labels |
Optional vector of label values to compare. When supplied,
|
na.rm |
Logical; if |
empty |
How to score Dice, Jaccard, overlap coefficient, and volume
similarity when both masks are empty. |
check_geometry |
Logical; if |
tolerance |
Numeric tolerance used for affine comparisons. |
By default, numeric images are converted to foreground masks with
value > threshold, and logical images use TRUE as foreground. Supply
labels to compute label-wise overlap instead.
A data frame with voxel counts and overlap metrics. sensitivity
is intersection / n_x; precision is intersection / n_y.
x <- array(c(1, 1, 0, 0), dim = c(2, 2, 1)) y <- array(c(1, 0, 1, 0), dim = c(2, 2, 1)) overlap_metrics(x, y)x <- array(c(1, 1, 0, 0), dim = c(2, 2, 1)) y <- array(c(1, 0, 1, 0), dim = c(2, 2, 1)) overlap_metrics(x, y)
Converts from our internal RAS convention to ANTs/ITK LPS convention.
ras_to_lps(coords)ras_to_lps(coords)
coords |
Numeric matrix (N x 3) or vector of length 3 in RAS |
Coordinates in LPS convention
ras <- c(10, 20, 30) lps <- ras_to_lps(ras)ras <- c(10, 20, 30) lps <- ras_to_lps(ras)
Converts from scanner RAS to FreeSurfer's tkRAS coordinate system.
ras_to_tkras(ras, c_ras)ras_to_tkras(ras, c_ras)
ras |
Numeric matrix (N x 3) or vector of length 3 in scanner RAS |
c_ras |
Numeric vector of length 3: the c_ras offset from FreeSurfer |
Coordinates in tkRAS
scanner_ras <- c(0.5, -2.3, 1.1) c_ras <- c(0.5, -2.3, 1.1) tkras <- ras_to_tkras(scanner_ras, c_ras)scanner_ras <- c(0.5, -2.3, 1.1) c_ras <- c(0.5, -2.3, 1.1) tkras <- ras_to_tkras(scanner_ras, c_ras)
Comment lines (starting with "#") are ignored. If a line contains "affineType:" the value is returned as the detected type.
read_affine_matrix_txt(file, type = NULL)read_affine_matrix_txt(file, type = NULL)
file |
Path to text file containing affine matrix |
type |
Optional type hint (overrides auto-detection) |
list(matrix = 4x4, type = character|NULL)
Simple image I/O using neuroim2
read_image(path)read_image(path)
path |
File path |
neuroim2 volume (DenseNeuroVol or DenseNeuroVec) or array fallback
Read an affine transform file into an Affine3DMorphism
read_linear_transform( path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), source = "source", target = "target", source_affine = NULL, target_affine = NULL, source_dim = NULL, target_dim = NULL, oblique_correction = TRUE, invert = FALSE )read_linear_transform( path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), source = "source", target = "target", source_affine = NULL, target_affine = NULL, source_dim = NULL, target_dim = NULL, oblique_correction = TRUE, invert = FALSE )
path |
Path to transform file |
format |
One of "generic", "fsl", "afni", or "itk" |
source |
Source domain id |
target |
Target domain id |
source_affine |
Source voxel-to-world affine (required for fsl) |
target_affine |
Target voxel-to-world affine (required for fsl) |
source_dim |
Optional source image dimensions for FSL handedness-aware conversion |
target_dim |
Optional target image dimensions for FSL handedness-aware conversion |
oblique_correction |
Logical; for AFNI format, apply cardinal/deoblique correction |
invert |
Logical; if TRUE, invert the read matrix before wrapping |
Affine3DMorphism
Supports single-file transforms and FSL/MCFLIRT-style indexed files
(path.000, path.001, ...).
read_linear_transform_array( path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), source = "source", target = "target", ... )read_linear_transform_array( path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), source = "source", target = "target", ... )
path |
Base file path |
format |
One of |
source |
Source domain id |
target |
Target domain id |
... |
Passed to |
A LinearTransformArray object
Read transform from file into a Morphism
read_transform( path, type = NULL, source = NULL, target = NULL, apply_affine = TRUE, ... )read_transform( path, type = NULL, source = NULL, target = NULL, apply_affine = TRUE, ... )
path |
Path or Morphism |
type |
Optional type hint: ants_h5, ants, fsl, fsl_coef, afni, x5, linear, fsl_affine, afni_affine, itk_affine, lta_affine |
source |
Optional source id |
target |
Optional target id |
apply_affine |
Logical; for ANTs H5 files, whether to include embedded affine |
... |
Additional constructor arguments. FSL warps require
|
A Morphism or MorphismPath object
Read X5 transform file
read_x5(path)read_x5(path)
path |
Input file path |
List of X5Transform objects
Adds a loader function to the registry. Loaders are used to read warp displacement fields from various file formats.
register_loader(name, loader) register_warp_loader(name, loader)register_loader(name, loader) register_warp_loader(name, loader)
name |
Character identifier for the loader |
loader |
Function(path) -> list(array, dim, world_to_vox) |
Invisibly returns the name
# Register a custom loader my_loader <- function(path) { # Load and return list(array, dim, world_to_vox) } register_loader("my_format", my_loader)# Register a custom loader my_loader <- function(path) { # Load and return list(array, dim, world_to_vox) } register_loader("my_format", my_loader)
The fundamental resampling operation: transform coordinates via morphism, then evaluate sampler at transformed coordinates.
resample( sampler, morphism, coords, modulate = c("none", "jacobian", "sqrt_jacobian") )resample( sampler, morphism, coords, modulate = c("none", "jacobian", "sqrt_jacobian") )
sampler |
Sampler object |
morphism |
Morphism or MorphismPath |
coords |
Target coords (n x 3 matrix) or Grid |
modulate |
Jacobian modulation: "none", "jacobian", "sqrt_jacobian" |
Sampled values
# Create volume and sampler vol <- array(1:27, dim = c(3, 3, 3)) sampler <- volume_sampler(vol, affine = diag(4)) # Create identity morphism morph <- IdentityMorphism("test") # Resample at specific coordinates coords <- matrix(c(0, 0, 0, 1, 1, 1), ncol = 3, byrow = TRUE) resample(sampler, morph, coords)# Create volume and sampler vol <- array(1:27, dim = c(3, 3, 3)) sampler <- volume_sampler(vol, affine = diag(4)) # Create identity morphism morph <- IdentityMorphism("test") # Resample at specific coordinates coords <- matrix(c(0, 0, 0, 1, 1, 1), ncol = 3, byrow = TRUE) resample(sampler, morph, coords)
High-level resampling helper
resample_to(moving, target, transform, method = "linear", modulate = "none")resample_to(moving, target, transform, method = "linear", modulate = "none")
moving |
Source volume (neuroim2 or array) |
target |
Target volume or Grid |
transform |
Morphism, MorphismPath, or file path. When a path is a
dense FSL field, the moving image (a neuroim2 volume) supplies the source
geometry the field needs. FNIRT coefficient files also need the reference
geometry, which the target grid does not reliably provide, so read them
with |
method |
Interpolation method |
modulate |
Jacobian modulation |
neuroim2 volume (matching target geometry)
Convenience wrapper for common volume-to-volume resampling.
resample_volume(data, morphism, target, method = "linear", modulate = "none")resample_volume(data, morphism, target, method = "linear", modulate = "none")
data |
Source volume |
morphism |
Transform |
target |
Target geometry (Grid or volume) |
method |
Interpolation method |
modulate |
Jacobian modulation |
Array with target dimensions
Plan once, apply many times: precompute target voxel centres and flatten the morphism path so repeated resampling of multiple volumes is cheap while keeping the public API small.
Rebuilds correspondence from the original reference to the original moving mesh, checking both ordered geometry identities. The new source must contain faces for barycentric interpolation. This generally differs from a transpose and does not recover information discarded by downsampling. Masks swap sides.
reverse_surface_resampling_plan(plan, reference, moving)reverse_surface_resampling_plan(plan, reference, moving)
plan |
Original |
reference |
Original reference mesh. |
moving |
Original moving mesh. |
A new SurfaceResamplingPlan with geometries swapped.
Project volumetric data onto surface vertices.
sample_volume_on_surface( data, morphism, surface_coords = NULL, method = "linear" )sample_volume_on_surface( data, morphism, surface_coords = NULL, method = "linear" )
data |
Source volume |
morphism |
VolToSurfMorphism |
surface_coords |
Surface vertex coordinates (optional) |
method |
Interpolation method |
Values at surface vertices
Construct sampled points
sampled_points(coords)sampled_points(coords)
coords |
Numeric matrix with 3 columns (N x 3) |
SampledPoints object
Lightweight container for point samples in world coordinates.
## S4 method for signature 'SampledPoints' show(object)## S4 method for signature 'SampledPoints' show(object)
object |
A |
coordsNumeric matrix (N x 3)
Samplers encapsulate data + interpolation strategy, enabling elegant composition with morphisms for resampling operations.
A Sampler wraps volumetric or surface data with an interpolation method. The core operation is: given coordinates, return interpolated values.
Resampling through a morphism is then simply:
source_coords <- transform(morphism, target_coords) values <- sampler(source_coords)
Sampler: data + interpolation encapsulation
## S4 method for signature 'Sampler' show(object)## S4 method for signature 'Sampler' show(object)
object |
A Sampler object (for show method) |
evaluateFunction: (coords) -> values
dimsInteger: data dimensions
vdimInteger: output dimensionality per point
boundsList: min/max coordinate bounds
methodCharacter: interpolation method
outsideValue for out-of-bounds queries
Mirrors the common neuroimaging convention where voxel sizes define the linear part and the image center maps to world origin.
shape_zoom_affine(shape, zooms, x_flip = TRUE, y_flip = FALSE)shape_zoom_affine(shape, zooms, x_flip = TRUE, y_flip = FALSE)
shape |
Length-N image shape |
zooms |
Length-N voxel sizes |
x_flip |
Logical; if TRUE, flip X axis (radiological-on-disk style) |
y_flip |
Logical; if TRUE, also flip Y axis (with x_flip gives DICOM style) |
4x4 affine matrix
Get source domain of a morphism
source_of(object) source_domain(object) ## S4 method for signature 'Morphism' source_of(object) ## S4 method for signature 'Morphism' source_domain(object) ## S4 method for signature 'MorphismPath' source_of(object)source_of(object) source_domain(object) ## S4 method for signature 'Morphism' source_of(object) ## S4 method for signature 'Morphism' source_domain(object) ## S4 method for signature 'MorphismPath' source_of(object)
object |
A Morphism object |
Source domain hash (character)
Construct a surface mesh
surface_mesh(vertices, faces = NULL)surface_mesh(vertices, faces = NULL)
vertices |
Numeric matrix with 3 columns (V x 3) |
faces |
Optional matrix with 3 columns (F x 3), 0- or 1-based indices |
SurfaceMesh object
Lightweight surface-to-surface resampling using precomputed sparse triplets. This keeps the core API small while enabling reusable vertex-data transport.
Computes reusable interpolation weights mapping vertex data from a moving mesh onto a reference mesh.
surface_resampling_plan( reference, moving, method = c("barycentric", "nearest", "adaptive_bary_area"), spherical = TRUE, radius = 100, source_mask = NULL, target_mask = NULL, outside = NULL, source_areas = NULL, target_areas = NULL, experimental = FALSE )surface_resampling_plan( reference, moving, method = c("barycentric", "nearest", "adaptive_bary_area"), spherical = TRUE, radius = 100, source_mask = NULL, target_mask = NULL, outside = NULL, source_areas = NULL, target_areas = NULL, experimental = FALSE )
reference |
Reference/output surface ( |
moving |
Moving/input surface ( |
method |
Interpolation method: |
spherical |
Logical; if |
radius |
Radius used when |
source_mask |
Optional logical or finite numeric input ROI; positive values include vertices. Exclusion is applied before row normalization. |
target_mask |
Optional output ROI, applied after normalization. |
outside |
Uncovered-query policy: |
source_areas, target_areas
|
Geometry-bound |
experimental |
Explicitly opt into the adaptive area implementation. Its full-template Workbench parity gate has not passed. |
Spherical barycentric resampling uses the closest point on the rescaled triangular mesh, including edges and vertices (ordinary barycentric, without adaptive area correction). It does not use radial ray intersections. For nonspherical meshes, only interior orthogonal projections are considered, with an explicit policy for uncovered queries. The default is nearest-vertex fallback for nonspherical meshes and an error for spherical meshes.
A SurfaceResamplingPlan object
Create a surface sampler
surface_sampler( vertices, data, faces = NULL, method = c("nearest", "barycentric"), projection = c("interior", "closest") )surface_sampler( vertices, data, faces = NULL, method = c("nearest", "barycentric"), projection = c("interior", "closest") )
vertices |
Vertex coordinates (V x 3), SampledPoints, or SurfaceMesh |
data |
Vertex data (length V or V x k) |
faces |
Face indices (F x 3, optional) |
method |
"nearest" or "barycentric" |
projection |
Barycentric projection policy: interior orthogonal projections (default), or the closest point including edges and vertices. |
Sampler object
Supply either positive area values with explicit provenance, or an anatomical mesh with the same ordered faces and vertex identities as the registration geometry. Mesh areas allocate one third of each Euclidean triangle's area to each corner. Registration spheres are never used implicitly as anatomy.
surface_vertex_areas( geometry, anatomical = NULL, values = NULL, units = "mm^2", provenance = NULL )surface_vertex_areas( geometry, anatomical = NULL, values = NULL, units = "mm^2", provenance = NULL )
geometry |
Registration |
anatomical |
Optional anatomical |
values |
Optional finite positive numeric area vector. |
units |
Area units, for example |
provenance |
Nonempty source description, required for supplied values. |
A SurfaceVertexAreas object with values, geometry identity, units and provenance.
Lightweight mesh reference for surface operations.
## S4 method for signature 'SurfaceMesh' show(object)## S4 method for signature 'SurfaceMesh' show(object)
object |
A |
coordsNumeric matrix (V x 3) of vertices
facesInteger matrix (F x 3) of 0-based triangle indices
Maps between surface meshes via spherical registration.
SurfToSurfMorphism( source, target, method = c("sphere", "area", "sulc"), source_sphere = "", target_sphere = "", mapping = c("nearest", "barycentric"), source_vertices = NULL, target_vertices = NULL, faces = NULL, cost = 1, method_tag = "anatomical" )SurfToSurfMorphism( source, target, method = c("sphere", "area", "sulc"), source_sphere = "", target_sphere = "", mapping = c("nearest", "barycentric"), source_vertices = NULL, target_vertices = NULL, faces = NULL, cost = 1, method_tag = "anatomical" )
source |
Source surface domain hash |
target |
Target surface domain hash |
method |
Registration method: "sphere", "area", "sulc" |
source_sphere |
Path to source sphere surface |
target_sphere |
Path to target sphere surface |
mapping |
How to map target points onto the source mesh.
|
source_vertices |
Optional V x 3 numeric matrix of source mesh vertices.
Required for |
target_vertices |
Optional V x 3 numeric matrix of target mesh vertices.
Required for |
faces |
Optional F x 3 integer matrix of triangle vertex indices (0- or 1-based).
Required for |
cost |
Path cost (default 1.0) |
method_tag |
Method tag (default "anatomical") |
SurfToSurfMorphism object
Maps between surface meshes (e.g., native to fsaverage via spherical registration).
methodRegistration method ("sphere", "area", "sulc")
source_spherePath to source sphere surface
target_spherePath to target sphere surface
Get target domain of a morphism
target_of(object) target_domain(object) ## S4 method for signature 'Morphism' target_of(object) ## S4 method for signature 'Morphism' target_domain(object) ## S4 method for signature 'MorphismPath' target_of(object)target_of(object) target_domain(object) ## S4 method for signature 'Morphism' target_of(object) ## S4 method for signature 'Morphism' target_domain(object) ## S4 method for signature 'MorphismPath' target_of(object)
object |
A Morphism object |
Target domain hash (character)
FreeSurfer's tkregister uses a shifted coordinate system (tkRAS) that differs from scanner RAS by the c_ras offset stored in the surface header.
tkras_to_ras(tkras, c_ras)tkras_to_ras(tkras, c_ras)
tkras |
Numeric matrix (N x 3) or vector of length 3 in tkRAS |
c_ras |
Numeric vector of length 3: the c_ras offset from FreeSurfer |
Coordinates in scanner RAS
tkras <- c(0, 0, 0) c_ras <- c(0.5, -2.3, 1.1) scanner_ras <- tkras_to_ras(tkras, c_ras)tkras <- c(0, 0, 0) c_ras <- c(0.5, -2.3, 1.1) scanner_ras <- tkras_to_ras(tkras, c_ras)
Applies the coordinate pullback: given coordinates in the target domain, returns corresponding coordinates in the source domain.
transform(morphism, coords) ## S4 method for signature 'IdentityMorphism' transform(morphism, coords) ## S4 method for signature 'Affine3DMorphism' transform(morphism, coords) ## S4 method for signature 'Warp3DMorphism' transform(morphism, coords) ## S4 method for signature 'VolToSurfMorphism' transform(morphism, coords) ## S4 method for signature 'SurfToSurfMorphism' transform(morphism, coords) ## S4 method for signature 'MorphismPath' transform(morphism, coords)transform(morphism, coords) ## S4 method for signature 'IdentityMorphism' transform(morphism, coords) ## S4 method for signature 'Affine3DMorphism' transform(morphism, coords) ## S4 method for signature 'Warp3DMorphism' transform(morphism, coords) ## S4 method for signature 'VolToSurfMorphism' transform(morphism, coords) ## S4 method for signature 'SurfToSurfMorphism' transform(morphism, coords) ## S4 method for signature 'MorphismPath' transform(morphism, coords)
morphism |
A Morphism object or MorphismPath |
coords |
Matrix of coordinates (N x 3) in target domain |
Matrix of coordinates (N x 3) in source domain
# Create an affine morphism aff <- Affine3DMorphism("source_hash", "target_hash", diag(4)) coords <- matrix(c(10, 20, 30), ncol = 3) transform(aff, coords)# Create an affine morphism aff <- Affine3DMorphism("source_hash", "target_hash", diag(4)) coords <- matrix(c(10, 20, 30), ncol = 3) transform(aff, coords)
Alias for transform() to maintain neurofunctor compatibility.
transform_coords(object, coords) ## S4 method for signature 'Morphism' transform_coords(object, coords) ## S4 method for signature 'MorphismPath' transform_coords(object, coords)transform_coords(object, coords) ## S4 method for signature 'Morphism' transform_coords(object, coords) ## S4 method for signature 'MorphismPath' transform_coords(object, coords)
object |
A Morphism object |
coords |
Matrix of coordinates (N x 3) |
Transformed coordinates
Lightweight IO helpers for linear transform backends, including format factories, typed IO conditions, and array-style linear transform IO.
Apply a morphism path to coordinates using optimized warp chain.
Given a path of morphisms from source to target and coordinates in the target domain, returns the corresponding coordinates in the source domain.
transform_path(path, target_coords)transform_path(path, target_coords)
path |
List of Morphism objects ordered source -> target |
target_coords |
Numeric matrix (N x 3) of target world coords |
Numeric matrix (N x 3) of source world coords
Given a path [f: A->B, g: B->C], transform_path applies the pullback:
coords_in_C --(g pullback)--> coords_in_B --(f pullback)--> coords_in_A
The path is applied from last to first (g then f).
# Create affine morphisms aff1 <- Affine3DMorphism("native", "mni", diag(4)) aff2 <- Affine3DMorphism("mni", "template", diag(4)) path <- list(aff1, aff2) # Transform template coords to native space template_coords <- matrix(c(0, 0, 0, 10, 20, 30), ncol = 3, byrow = TRUE) native_coords <- transform_path(path, template_coords)# Create affine morphisms aff1 <- Affine3DMorphism("native", "mni", diag(4)) aff2 <- Affine3DMorphism("mni", "template", diag(4)) path <- list(aff1, aff2) # Transform template coords to native space template_coords <- matrix(c(0, 0, 0, 10, 20, 30), ncol = 3, byrow = TRUE) native_coords <- transform_path(path, template_coords)
Construct a transform file-format error condition
TransformFileError(message)TransformFileError(message)
message |
Error message |
Condition object of class TransformFileError
Construct a transform IO error condition
TransformIOError(message)TransformIOError(message)
message |
Error message |
Condition object of class TransformIOError
Checks that a path is composable (each morphism's target matches the next's source). Raises an error if the path is invalid.
validate_path(path)validate_path(path)
path |
List of Morphism objects |
Invisibly returns the path if valid
aff1 <- Affine3DMorphism("a", "b", diag(4)) aff2 <- Affine3DMorphism("b", "c", diag(4)) validate_path(list(aff1, aff2)) # OKaff1 <- Affine3DMorphism("a", "b", diag(4)) aff2 <- Affine3DMorphism("b", "c", diag(4)) validate_path(list(aff1, aff2)) # OK
Reports invalid faces and topology without repairing them. Spherical admission additionally requires origin-based radius spread within tolerance, a closed connected orientable manifold of sphere topology, unambiguous radial face orientations and radial mapping degree one. Input face winding is free. Generic open meshes do not require closed topology or spherical geometry.
validate_surface_mesh( mesh, spherical = TRUE, error = FALSE, radius_tolerance = 1.001 )validate_surface_mesh( mesh, spherical = TRUE, error = FALSE, radius_tolerance = 1.001 )
mesh |
SurfaceMesh or surface-like object with faces. |
spherical |
Require an embedded spherical triangulation. |
error |
Stop when validation fails instead of returning diagnostics. |
radius_tolerance |
Maximum ratio of vertex radii about the origin. |
Diagnostic list with valid, issues (one-based offending indices), topology counts, radius range, radial degree and numerical margins.
Maps from volume domain to surface domain using various sampling strategies.
VolToSurfMorphism( source, target, method = c("trilinear", "ribbon", "mid_thickness", "nearest"), ribbon_inner = "", ribbon_outer = "", ribbon_inner_coords = NULL, ribbon_outer_coords = NULL, n_ribbon_samples = 6L, mid_coords = NULL, cost = 2, method_tag = "anatomical" )VolToSurfMorphism( source, target, method = c("trilinear", "ribbon", "mid_thickness", "nearest"), ribbon_inner = "", ribbon_outer = "", ribbon_inner_coords = NULL, ribbon_outer_coords = NULL, n_ribbon_samples = 6L, mid_coords = NULL, cost = 2, method_tag = "anatomical" )
source |
Volume domain hash |
target |
Surface domain hash |
method |
Sampling method: "trilinear", "ribbon", "mid_thickness", "nearest" |
ribbon_inner |
Path to inner (white) surface for ribbon sampling |
ribbon_outer |
Path to outer (pial) surface for ribbon sampling |
ribbon_inner_coords |
Pre-loaded inner surface coordinates (optional) |
ribbon_outer_coords |
Pre-loaded outer surface coordinates (optional) |
n_ribbon_samples |
Number of samples along ribbon normal |
mid_coords |
Pre-computed midpoint coordinates (optional) |
cost |
Path cost (default 2.0) |
method_tag |
Method tag (default "anatomical") |
VolToSurfMorphism object
Maps volume coordinates to surface vertices. Supports different sampling strategies (ribbon, trilinear point sampling).
methodSampling method ("ribbon", "trilinear", "nearest", "mid_thickness")
ribbon_innerPath to inner (white) surface for ribbon sampling
ribbon_outerPath to outer (pial) surface for ribbon sampling
n_ribbon_samplesNumber of samples along ribbon normal
Create a volume sampler
volume_sampler( data, affine = NULL, method = c("linear", "nearest", "cubic"), outside = NA_real_ )volume_sampler( data, affine = NULL, method = c("linear", "nearest", "cubic"), outside = NA_real_ )
data |
Numeric array (3D/4D) or volume object |
affine |
4x4 voxel-to-world (extracted if NULL) |
method |
Interpolation: "linear", "nearest", "cubic" |
outside |
Value for out-of-bounds |
Sampler object
vol <- array(rnorm(27), dim = c(3, 3, 3)) sampler <- volume_sampler(vol, affine = diag(4)) coords <- matrix(c(1, 1, 1), ncol = 3) sampler@evaluate(coords)vol <- array(rnorm(27), dim = c(3, 3, 3)) sampler <- volume_sampler(vol, affine = diag(4)) coords <- matrix(c(1, 1, 1), ncol = 3) sampler@evaluate(coords)
Builds a Warp3DMorphism directly from a 4D field array and a grid,
without requiring an on-disk warp file.
warp_from_field( source, target, field, grid = NULL, representation = c("displacements", "deformations"), warp_method = c("linear", "cubic"), cost = 1.5, method_tag = "anatomical", id = NULL )warp_from_field( source, target, field, grid = NULL, representation = c("displacements", "deformations"), warp_method = c("linear", "cubic"), cost = 1.5, method_tag = "anatomical", id = NULL )
source |
Source domain id |
target |
Target domain id |
field |
Numeric array with dims |
grid |
Grid describing voxel geometry. If |
representation |
Either |
warp_method |
Interpolation method for warp lookup |
cost |
Path cost |
method_tag |
Method tag |
id |
Optional stable id for the in-memory warp payload |
Warp3DMorphism
Pluggable loader system for warp displacement fields. Provides a registry for different file formats (NIfTI via neuroim2, AFNI, FSL, ANTs H5) with morphism-level caching.
A loader function must accept a file path and return a list with:
array: Numeric vector of displacement values (flattened 3 x X x Y x Z)
dim: Integer vector c(X, Y, Z)
world_to_vox: 4x4 matrix mapping world coords to voxel indices
Represents a nonlinear warp field transformation.
Warp3DMorphism( source, target, warp_path, warp_type = c("ants", "ants_h5", "fsl", "fsl_coef", "afni", "freesurfer", "dense"), inverse_path = "", def_type = NULL, warp_method = c("linear", "cubic"), cost = 1.5, method_tag = "anatomical", source_affine = NULL, source_dim = NULL, target_affine = NULL, target_dim = NULL )Warp3DMorphism( source, target, warp_path, warp_type = c("ants", "ants_h5", "fsl", "fsl_coef", "afni", "freesurfer", "dense"), inverse_path = "", def_type = NULL, warp_method = c("linear", "cubic"), cost = 1.5, method_tag = "anatomical", source_affine = NULL, source_dim = NULL, target_affine = NULL, target_dim = NULL )
source |
Source domain hash |
target |
Target domain hash |
warp_path |
Path to displacement field file |
warp_type |
One of "ants", "ants_h5", "fsl", "fsl_coef", "afni", "freesurfer", "dense" |
inverse_path |
Path to inverse warp (optional) |
def_type |
Deformation type: "relative" (displacement) or "absolute" (coordinates) |
warp_method |
Interpolation method for warp field lookup: "linear" or "cubic" |
cost |
Path cost (default 1.5) |
method_tag |
Method tag (default "anatomical") |
source_affine, source_dim
|
Source image voxel-to-RAS affine and three
dimensions. Required for FSL warps ( |
target_affine, target_dim
|
Reference image voxel-to-RAS affine and three
dimensions. For dense FSL fields they default to the warp lattice; supply
both when the field lattice differs from the reference image grid. Required
for FNIRT coefficient files ( |
Warp3DMorphism object
warp <- Warp3DMorphism("native", "mni", "path/to/warp.nii.gz")warp <- Warp3DMorphism("native", "mni", "path/to/warp.nii.gz")
Represents a nonlinear warp field transformation (e.g., ANTs SyN, FSL FNIRT). Stores metadata; the actual warp field is loaded on demand.
warp_pathPath to the warp field file
warp_typeType of warp ("ants", "ants_h5", "fsl", "fsl_coef", "afni", "freesurfer", "dense")
inverse_pathPath to inverse warp (if available)
Write a 4x4 affine matrix to a text file
write_affine_matrix_txt(matrix, file, type = NULL, comment = TRUE)write_affine_matrix_txt(matrix, file, type = NULL, comment = TRUE)
matrix |
4x4 numeric affine matrix |
file |
Output file path |
type |
Optional type label to write as comment |
comment |
Logical; if TRUE, write type as comment header |
Invisibly returns the file path
Write image using neuroim2
write_image(x, path)write_image(x, path)
x |
neuroim2 volume or array |
path |
Output path |
Write an affine transform to disk
write_linear_transform( x, path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), source_affine = NULL, target_affine = NULL, source_dim = NULL, target_dim = NULL, oblique_correction = TRUE, invert = FALSE )write_linear_transform( x, path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), source_affine = NULL, target_affine = NULL, source_dim = NULL, target_dim = NULL, oblique_correction = TRUE, invert = FALSE )
x |
Affine3DMorphism or 4x4 matrix (internal pullback convention) |
path |
Output file path |
format |
One of "generic", "fsl", "afni", or "itk" |
source_affine |
Source voxel-to-world affine (required for fsl) |
target_affine |
Target voxel-to-world affine (required for fsl) |
source_dim |
Optional source image dimensions for FSL handedness-aware conversion |
target_dim |
Optional target image dimensions for FSL handedness-aware conversion |
oblique_correction |
Logical; for AFNI format, apply cardinal/deoblique correction |
invert |
Logical; if TRUE, invert before writing |
Invisibly returns path
Write a series of linear transforms
write_linear_transform_array( x, path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), ... )write_linear_transform_array( x, path, format = c("generic", "fsl", "afni", "itk", "lta", "x5"), ... )
x |
A |
path |
Base output path |
format |
One of |
... |
Passed to |
Invisibly returns written path(s)
Convenience wrapper around write_linear_transform() for affine morphisms
and raw 4x4 matrices. For Warp3DMorphism, writes an LPS NIfTI vector
field (ANTs-compatible when the output contains displacements).
write_transform(x, path, type = NULL, ...)write_transform(x, path, type = NULL, ...)
x |
Affine3DMorphism, Warp3DMorphism, or 4x4 numeric matrix |
path |
Output file path |
type |
Optional output type:
|
... |
Passed to |
Invisibly returns path
Writes a 5D vector image (X, Y, Z, 1, 3), with intent code 1007 and LPS components. Displacement output is compatible with ANTs. Absolute deformation output contains source coordinates and must be explicitly read as such; ANTs expects displacements. Requires RNifti.
write_warp_field( x, path, representation = c("auto", "displacements", "deformations") )write_warp_field( x, path, representation = c("auto", "displacements", "deformations") )
x |
Warp3DMorphism |
path |
Output NIfTI path |
representation |
Output representation: |
Invisibly returns path
Write X5 transform file
write_x5(path, x5_list)write_x5(path, x5_list)
path |
Output file path |
x5_list |
List of |
Invisibly returns path
Create an X5 domain descriptor
x5_domain(grid, size, mapping = NULL, coordinates = NULL)x5_domain(grid, size, mapping = NULL, coordinates = NULL)
grid |
Logical |
size |
Integer vector |
mapping |
Optional matrix |
coordinates |
Optional coordinate kind string |
An X5Domain object
Create an X5 transform descriptor
x5_transform( type, transform, subtype = NULL, representation = NULL, metadata = NULL, dimension_kinds = NULL, domain = NULL, inverse = NULL, jacobian = NULL, additional_parameters = NULL, array_length = 1L )x5_transform( type, transform, subtype = NULL, representation = NULL, metadata = NULL, dimension_kinds = NULL, domain = NULL, inverse = NULL, jacobian = NULL, additional_parameters = NULL, array_length = 1L )
type |
|
transform |
Numeric array of transform parameters |
subtype |
Optional subtype |
representation |
Optional representation label |
metadata |
Optional named list or JSON string |
dimension_kinds |
Optional character vector |
domain |
Optional |
inverse |
Optional inverse array |
jacobian |
Optional Jacobian array |
additional_parameters |
Optional array |
array_length |
Integer array length |
An X5Transform object