Learn R Programming

ravetools (version 0.3.2)

register_volume3d: Native 3D volume registration ('rigid', 'affine', or 'SyN')

Description

Self-contained image registration for 3D volumes, implemented purely in RcppEigen (no other external registration library). It mirrors the core behavior of 'ANTs' antsRegistration: a multi-resolution, physical-shift scaled gradient-descent optimizer driving a similarity metric, working entirely in the anatomical RAS (right-anterior-superior) space. Each volume carries its own vox2ras (0-indexed voxel index to anatomical RAS) \(4\times 4\) transform, so volumes with different sampling, orientation, or field of view are aligned correctly.

Usage

register_volume3d(
  source,
  target,
  source_vox2ras = NULL,
  target_vox2ras = NULL,
  source_mask = NULL,
  target_mask = NULL,
  source_points = NULL,
  target_points = NULL,
  points_weight = 0.5,
  weights = NULL,
  type = c("rigid", "affine", "syn", "syn_only"),
  metric = "mattes",
  shrink_factors = c(4, 2, 1),
  smoothing_sigmas = c(2, 1, 0),
  iterations = c(1000, 500, 250),
  sampling_rate = 0.2,
  interpolation = "trilinear",
  number_of_bins = 32L,
  seed = 1L,
  init_transform = NULL,
  syn_iterations = c(40, 20, 0),
  syn_sigma = 3,
  verbose = TRUE
)

Value

A list with:

transform

the estimated 4x4 RAS-to-RAS linear transform mapping target (fixed) coordinates to source (moving) coordinates

image

the (primary) source resampled onto the target grid

images

a list with every source channel resampled onto the target grid using its own interpolation; image is the first element. For single-image input this is a length-1 list

forward_field,inverse_field

(only for "syn") the deformation fields

metric_trace

the metric value across optimizer iterations

type,metric

echoes of the inputs

Arguments

source

the moving volume to be aligned, a 3D array (for example a 'CT'); the result transform maps target into this image's space. May also be a list of already co-registered 3D arrays (multiple modalities such as 'T1', 'T2', an atlas constraint); all source channels must share the same dimensions and vox2ras

target

the fixed/reference volume to align to, a 3D array (for example a 'MRI'), or a list of co-registered arrays matching source channel-for-channel

source_vox2ras, target_vox2ras

4x4 (or 3x4) matrices mapping the 0-indexed voxel coordinate (column-row-slice, 'C'-style starting from 0, complying with 'NIfTI') to the RAS coordinate system; if NULL, the function looks for a "vox2ras" attribute on the array

source_mask, target_mask

optional 3D mask arrays restricting where the metric is evaluated; default NULL (no mask, evaluate everywhere). A target_mask (on the target/fixed grid, same dimensions as target) limits which target voxels drive the registration; a source_mask (on the source/moving grid) drops samples that map outside it. Non-zero voxels are included. Besides focusing the alignment on a region of interest, masks speed things up by skipping background: the linear stage samples only inside the mask, and the deformable stage skips warping voxels outside the (dilated) mask. One mask per grid, shared across channels

source_points, target_points

optional N x 3 matrices of corresponding landmark coordinates that add a surface/landmark term to the deformable ("syn"/"syn_only") stage; default NULL (no term). Row i of target_points (in the target/fixed RAS) and row i of source_points (in the source/moving RAS) must be the same anatomical location, for example corresponding cortical-surface vertices from a 'FreeSurfer' spherical registration. The term pulls the warp of each target point onto its source correspondent, recovering cortical folding (gyrification) that the intensity metric blurs over, while the image metric still drives deep-brain subcortical structures. Must be supplied together with equal row counts. Points must be in the same RAS frame as source_vox2ras/target_vox2ras (note 'FreeSurfer' surfaces use surface/tkr RAS, which differs from scanner RAS by c_ras)

points_weight

relative weight of the landmark term against the image metric in the deformable stage; default 0.5. Larger values follow the landmarks more closely. The sparse landmark force is attenuated by syn_sigma smoothing, so this typically needs tuning for a given point count and spacing

weights

optional numeric weights, one per source/target pair, controlling each channel's contribution to the deformable cost; default is equal weighting. Weights are normalized internally to sum to 1. Only the deformable ("syn"/"syn_only") stage is multivariate; the linear stage always uses the first (primary) pair

type

type of transform to estimate; one of 'rigid' (6 degrees of freedom), 'affine' (12), "syn" (affine followed by a SDR - symmetric diffeomorphic deformation), or 'syn_only' (deformable stage only — no affine is estimated; init_transform is used directly as the starting affine, useful when you already have a good linear alignment)

metric

similarity metric: "mattes" (Mattes mutual information, the default, best for cross-modal such as 'CT'-'MRI'), "cc" (normalized cross-correlation, for same-modality), or "meansquares" (mean squared intensity difference). With multiple channels, supply either a single metric (used for every pair) or a vector with one metric per source/target pair

shrink_factors

integer down-sampling factors, one per resolution level (coarsest first); default c(4, 2, 1)

smoothing_sigmas

Gaussian smoothing applied at each level, in voxels, same length as shrink_factors; default c(2, 1, 0)

iterations

maximum optimizer iterations per level; default c(1000, 500, 250)

sampling_rate

fraction of fixed voxels sampled to evaluate the metric (speeds up large volumes); default 0.2

interpolation

output interpolation used when warping each modality onto the target grid: 'trilinear' (default), 'nearest' (keeps label or segmentation values intact), or "bspline" (cubic Catmull-Rom, higher quality, slower). Like metric, supply a single value (applied to every channel) or one per source/target pair. This affects only the returned warped images, never the optimization's internal sampling (always 'trilinear', so every channel still produces smooth gradients)

number_of_bins

number of histogram bins for the "mattes" metric; default 32

seed

random seed for the voxel sampler, for reproducibility

init_transform

optional 4x4 initial RAS-to-RAS transform (fixed to moving) to start from

syn_iterations, syn_sigma

deformable stage controls (only used when type = "syn" or "syn_only"): per-level iteration counts and the Gaussian regularization sigma (in voxels) applied to the update field. Both are recycled to the number of levels, so syn_sigma may be a vector to vary the regularization per stage (e.g. c(3, 3, 1) to relax it at the finest level for sharper detail)

verbose

logical; if TRUE (default) print per-level and per-iteration progress to the console, including the current stage, shrink factor, smoothing sigma, cost metric, and step size (linear) or maximum displacement (deformable); useful to monitor convergence on large volumes

See Also

apply_transform3d, resample_3d_volume

Examples

Run this code
# \donttest{

# --- synthetic same-modality example -------------------------------------
nd <- c(50, 50, 50)
vox2ras <- diag(4); vox2ras[1:3, 4] <- -25
blob <- function(cx, cy, cz, s = 6) {
  g <- expand.grid(x = 0:(nd[1]-1), y = 0:(nd[2]-1), z = 0:(nd[3]-1))
  array(exp(-((g$x-cx)^2 + (g$y-cy)^2 + (g$z-cz)^2) / (2*s^2)), nd)
}
target <- blob(25, 25, 25)
source <- blob(28, 23, 26)            # shifted by a known (3, -2, 1) mm

res <- register_volume3d(
  source, target,
  source_vox2ras = vox2ras, target_vox2ras = vox2ras,
  type = "rigid", metric = "cc"
)
res$transform[1:3, 4]                 # ~ c(3, -2, 1)


# --- multimodal registration (several co-registered channels) ------------
# Two aligned modalities (e.g. a T1 and a T2) jointly drive the deformable
# stage. Each pair may use its own metric, and `weights` set their relative
# influence (normalized internally to sum to 1). All source channels must
# share a grid; likewise all target channels.
t1_target <- blob(25, 25, 25, s = 6)
t2_target <- blob(25, 25, 25, s = 9)  # same anatomy, different contrast
t1_source <- blob(27, 24, 26, s = 6)  # both channels share the same warp
t2_source <- blob(27, 24, 26, s = 9)

res_mm <- register_volume3d(
  source = list(t1_source, t2_source),
  target = list(t1_target, t2_target),
  source_vox2ras = vox2ras, target_vox2ras = vox2ras,
  weights = c(2, 1),                  # T1 counts twice as much as T2
  metric = c("mattes", "cc"),         # one metric per channel
  type = "syn"
)
res_mm$transform[1:3, 4]

# }

Run the code above in your browser using DataLab