Array to NIfTI in Python is a wrap: take a NumPy array, give it an affine, nibabel.Nifti1Image, nibabel.save. This page is that how-to. It is not “convert a DICOM series,” and it is not “write extra header tags.”
If the source is a DICOM series → how to convert DICOM to NIfTI. If you need to store tags on the file after you wrap it → store metadata in NIfTI and NRRD.
When this is the right convert
| You have | Do this |
|---|---|
| A NumPy volume or mask | This page: Nifti1Image + affine + save |
| A DICOM series on disk | dcm2niix / dicom2nifti — not a wrap |
| JPG / PNG you were going to turn into DICOM first | Read them into an array, then wrap here. Skip the DICOM hop |
| A CSV stack that is already a volume | Load to NumPy, then wrap |
The usual job is a segmentation mask that has to leave Python as one .nii / .nii.gz.
Environment
python -m venv array_nifti
source array_nifti/bin/activate # Windows: array_niftiScriptsactivate
pip install numpy nibabel
Sanity check: import numpy, nibabel. Docs: nibabel.
Wrap: array, affine, Nifti1Image, save
import numpy as np
import nibabel as nib
converted_array = np.array(normal_array, dtype=np.float32)
affine = np.eye(4)
nifti_file = nib.Nifti1Image(converted_array, affine)
nib.save(nifti_file, "mask.nii.gz")
np.array(..., dtype=np.float32) is the payload. Use float32 for images, an integer dtype for a label mask if you want labels to stay exact. Nifti1Image needs the array and an affine. nib.save writes .nii or .nii.gz from the path you pass.
The affine is not decoration
np.eye(4) means “1 voxel = 1 mm, origin at (0, 0, 0).” That is fine when you invented the array (a mask on a unit grid, a synthetic volume) and you are using identity on purpose.
If the array came from a real scan, put spacing and origin on the affine. Otherwise a viewer will draw a 0.7 mm CT as 1 mm voxels and everything downstream is the wrong size.
spacing = (0.7, 0.7, 1.5) # i, j, k in mm
origin = (0.0, 0.0, 0.0)
affine = np.eye(4)
affine[0, 0] = spacing[0]
affine[1, 1] = spacing[1]
affine[2, 2] = spacing[2]
affine[:3, 3] = origin
nifti_file = nib.Nifti1Image(converted_array, affine)
nib.save(nifti_file, "mask.nii.gz")
Copy the affine from the source NIfTI when the mask is in that volume’s grid: affine = src.affine. Do not rebuild identity and hope the overlay lines up.
Header
Nifti1Image also takes an optional header=. That is for fields you already have, not for stuffing patient tags. Writing extra metadata (a JSON extension, NRRD SetMetaData) is store metadata in NIfTI and NRRD.
Walk-through of the wrap: array to NIfTI on YouTube.
PYCAD builds the imaging side of products that have to write these files for real. Case studies.