Resampling, downsampling, and reorientation

This vignette shows how to:

We’ll use the example NIfTI that ships with the package:

demo_path <- system.file("extdata", "global_mask_v4.nii", package = "neuroim2")
vol  <- read_vol(demo_path)  # 3D NeuroVol
vec4 <- read_vec(demo_path)  # 4D NeuroVec

sp   <- space(vol)
dim(vol)
#> [1] 64 64 25
spacing(vol)
#> [1] 3.5 3.5 3.7

1. Resampling to a new space

resample_to() is a convenience wrapper around the S4 resample() methods that accepts human‑readable interpolation names.

You specify a target grid (NeuroSpace or NeuroVol) and choose "nearest", "linear", or "cubic" interpolation:

# Create a target space with 2× smaller voxels in each dimension
sp_fine <- NeuroSpace(
  dim    = sp@dim * 2L,
  spacing = sp@spacing / 2,
  origin  = sp@origin,
  trans   = trans(vol)
)

vol_fine_lin <- resample_to(vol, sp_fine, method = "linear")
dim(vol_fine_lin)
#> [1] 128 128  50
spacing(vol_fine_lin)
#> [1] 1.75 1.75 1.85

Typical patterns:

You can also call resample(source, target, interpolation = 0/1/3) directly if you prefer numeric codes.

2. Downsampling to coarser resolution

When you want fewer voxels (e.g. to speed up analysis or plotting) but don’t need arbitrarily defined target grids, use downsample() on a NeuroVec or NeuroVol.

2.1 Downsample a 4D NeuroVec

# Downsample by a factor of 0.5 in each spatial dimension
vec_down_factor <- downsample(vec4, factor = 0.5)

dim(vec4)
#> [1] 64 64 25  4
dim(vec_down_factor)
#> [1] 32 32 12  4
spacing(vec4)
#> [1] 3.5 3.5 3.7
spacing(vec_down_factor)
#> [1] 7.00000 7.00000 7.70833

You can also specify a target spacing or output dimensions:

# Target spacing (mm)
vec_down_spacing <- downsample(vec4, spacing = c(4, 4, 4))

# Target spatial dimensions
vec_down_outdim  <- downsample(vec4, outdim = c(32, 32, 16))
#> Warning in calculate_downsample_dims(current_dims, current_spacing, spacing, :
#> Output dimensions do not preserve aspect ratios. Using uniform scaling based on
#> smallest dimension.

Exactly one of factor, spacing, or outdim must be supplied. The current implementation uses a simple box‑averaging scheme in space.

2.2 Downsample a 3D NeuroVol

The same interface applies to volumes:

vol_down_factor <- downsample(vol, factor = 0.5)

dim(vol)
#> [1] 64 64 25
dim(vol_down_factor)
#> [1] 32 32 12

This is useful for coarse previews or multi‑scale workflows.

3. Reorienting images

reorient() updates the mapping between voxel indices and physical coordinates without changing the raw data array. This is helpful when you want a canonical orientation (e.g. RAS) or need to match another dataset’s axis directions.

For NeuroSpace, you supply three axis codes:

sp_lpi <- sp                      # assume input is LPI‑like
sp_ras <- reorient(sp_lpi, c("R", "A", "S"))

sp_lpi
#> 
#>  NeuroSpace Object 
#> 
#>  >> Dimensions 
#>   Grid Size: 64 x 64 x 25
#>   Memory:   5.9 KB
#> 
#>  >> Spatial Properties 
#>   Spacing:   3.50 x 3.50 x 3.70 mm
#>   Origin:    112.00 x -108.00 x -46.20 mm
#> 
#>  >> Anatomical Orientation 
#>   X: Right-to-Left  |  Y: Posterior-to-Anterior  |  Z: Inferior-to-Superior 
#> 
#>  >> World Transformation 
#>   Forward (Voxel to World): 
#>     -3.500  0.000  -0.000   112.000
#>  0.000  3.500  -0.000  -108.000
#>  0.000  0.000   3.700   -46.200
#>  0.000  0.000   0.000     1.000 
#>   Inverse (World to Voxel): 
#>     -0.286  0.000  0.000  32.000
#>  0.000  0.286  0.000  30.857
#>  0.000  0.000  0.270  12.486
#>  0.000  0.000  0.000   1.000 
#> 
#>  >> Bounding Box 
#>   Min Corner: -108.5, -108.0, -46.2 mm
#>   Max Corner: 112.0, 112.5, 42.6 mm
#> 
#> ==================================================
sp_ras
#> 
#>  NeuroSpace Object 
#> 
#>  >> Dimensions 
#>   Grid Size: 64 x 64 x 25
#>   Memory:   5.9 KB
#> 
#>  >> Spatial Properties 
#>   Spacing:   3.50 x 3.50 x 3.70 mm
#>   Origin:    -112.00 x 108.00 x 46.20 mm
#> 
#>  >> Anatomical Orientation 
#>   X: Right-to-Left  |  Y: Posterior-to-Anterior  |  Z: Inferior-to-Superior 
#> 
#>  >> World Transformation 
#>   Forward (Voxel to World): 
#>     3.500   0.000   0.000  -112.000
#> 0.000  -3.500   0.000   108.000
#> 0.000   0.000  -3.700    46.200
#> 0.000   0.000   0.000     1.000 
#>   Inverse (World to Voxel): 
#>     0.286   0.000   0.000  32.000
#> 0.000  -0.286   0.000  30.857
#> 0.000   0.000  -0.270  12.486
#> 0.000   0.000   0.000   1.000 
#> 
#>  >> Bounding Box 
#>   Min Corner: -112.0, -112.5, -42.6 mm
#>   Max Corner: 108.5, 108.0, 46.2 mm
#> 
#> ==================================================

For NeuroVol / NeuroVec, you typically reorient via their space:

vol_ras <- NeuroVol(as.array(vol), sp_ras)
dim(vol_ras)
#> [1] 64 64 25
spacing(vol_ras)
#> [1] 3.5 3.5 3.7

Note that reorient() preserves physical positions; it only changes how grid indices are interpreted in space. Coordinate transforms (coord_to_grid, grid_to_coord) automatically respect the new orientation.

4. Putting it together

Common combinations: