1

I'm changing the voxel size of some 3D volumes. How do I edit the pixdim field and calculate the new affine?

I have some MR volumes which are anisotropic, the voxel sizes are, say, 0.5 x 0.5 x 3 mm. And I've some code to interpolate them into isotropic (like 0.5 x 0.5 x 0.5 mm voxel size) volumes. The problem is when I need to save the file, I have to calculate the affine to map the now denser voxels in ijk space to reference xyz space. How do I do that?

First, my thought is to use the old affine and calculate the new affine.

For example, if volume V has a shape of 256 x 256 x 20 voxels with 0.5 x 0.5 x 3 voxel size and interpolated into volume U 256 x 256 x 120 voxels with 0.5 x 0.5 x 0.5 voxelsize.

The old affine will do [255 255 19]OA = [X Y Z] and the new affine should do [255 255 119]NA = [X Y Z] and we know AX=B X=inverse(A)B.

So the new affine should be inverse([255 255 119])[X Y Z]. However, the inverse matrix only exists for a square matrix. There will be no such thing of inverse([255 255 119]).

And it seems there is no set_voxel_size function in python-nibabel matlab-nifti-toolbox and so. How does that a case?

How do I change the voxel size explicitly?

kaltu
  • 330
  • 5
  • 17

1 Answers1

1

I am facing a similar problem at the moment. To solve it, I create a nifti header from scratch with 0.5 mm isotropic voxels and the desired shape. You can use header.set_zooms() to set the voxel size in mm.

import nibabel as nib
import numpy as np

hdr = nib.Nifti1Header()
hdr.set_data_shape((256, 256, 120))
hdr.set_zooms((0.5, 0.5, 0.5))  # set voxel size
hdr.set_xyzt_units(2)  # millimeters
dst_aff = hdr.get_best_affine()

src_aff = np.eye(4)
src_aff_inv = np.linalg.inv(src_aff)

transform = np.matmul(src_aff_inv, dst_aff)
jkr
  • 17,119
  • 2
  • 42
  • 68
  • Thank you for your answer on how to change the size. But this way still discarded the affine that maps voxel coordinate back to scanner coordinate. – kaltu May 12 '21 at 08:51