Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

How to convert a NumPy array into a NIfTI file in Python

Convert numpy array to NIfTI file using Python: simple method with nibabel for medical imaging data.

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 serieshow 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.

We build custom medical imaging platforms — advanced DICOM viewers, AI segmentation, and the clinical systems around them.

Get in Touch

Copyright © 2026 PYCAD. All Rights Reserved.