kaltu
kaltu

Reputation: 310

How do I edit and save voxel size and the corresponding affine of a 3D volume in Nifti format in python?

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?

Upvotes: 1

Views: 2545

Answers (1)

jkr
jkr

Reputation: 19310

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)

Upvotes: 1

Related Questions