This is a question for users of those two formats: if you had to set up a workflow where you need to store your medical images imported from DICOM in a single file, which would you choose between NRRD and NIFTI (or another?) and why?
Are there clear advantages known for each of those formats versus the other? Has anyone done any benchmarks to compare size, IO speed?
The only knowledge I have is that NIFTI is an upgrade from ANALYZE, and NIFTI itself has two versions where the image orientation can be stored in multiple ways, which aren’t always straightforward: The NIFTI file format | Brainder.
While DICOM is very complicated, both NRRD and NIfTI are very simple. From my perspective, they fill a very similar niche and are of similar complexity. I would choose the one that is used most in your domain.
NIfTI is very explicit, with a fixed 348-byte binary header. This makes it very simple to read. However, it is a bit harder to write, because it demands the order of image data dimensions (e.g. a Red, Green, Blue image MUST be saved RGBRGBRGB…), the first three dimensions must be spatial the fourth temporal and dimensions 5,6,7 are up to the user.
NRRD is text based, so it is human readable. It is easy to write, as you can easily describe whatever order you want to your dimensions. The trade off is that it is harder to create a reader, as you need to juggle the image dimensions. What is elegant about NRRD is that the flexibility of the header allows you to create a tiny header that describes a complicated image in a different format, for example you could write a NRRD-format nhdr file that describes most uncompressed DICOM images allowing easy support for DICOM.
With respect to speed, both are very fast to parse, and the small cost of the header is swamped for larger images. Without a doubt, NIfTI being all binary is faster, but in real world cases the amount is negligible. Further, since the NIfTI format is so constrained, many users add a BIDS JSON text sidecar to store extra information, and reading this incurs the same penalty as the text header in NRRD.
In my experience, Slicer supports both thoroughly, so you might want to look at other tools in your toolchain to decide.
Nifti format contains a lot of neuroimaging-specific details and it is quite rigid (fixed, binary header; inflexible dimensions). This makes nifti a good file format for neuroimaging but not well suited as a general image file format.
I’d add another nice thing about nrrd is the unu command, which can be very convenient for manipulating datasets. I don’t know if there’s anything similar for nifti. I’d generally use python to do most of what unu does, but for certain circumstances it’s a good tool.
I am a radiologist working on deep learning research and I’m curious on any perspectives on storing raw dicom data as a 3D NumPy volume? This would allow for the fast load times for downstream applications.
I have worked with NifTI and converting files into NumPy ended up slowing things down a lot.
Loading speed: Loading a 3D array from nrrd or nifti is just as fast as loading from npy/npz file. You may have compared uncompressed npy loading time to compressed nrrd/nifti loading times. All these formats can optionally use compression, which typically cuts required disk space by half and increases loading time by 5-10x. Loading from DICOM files (single-frame-per-file) takes about 100x more time than loading the same volume from nrrd/nifty/npy (regardless of compression).
Fast loading of course is not the only factor consider, so normally you will use all three kind of data representations: DICOM, research file formats (nrrd, nifti), and tensor files (numpy npy/npz arrays or other specialized hypercube storage). Each file format has its own very important role:
DICOM: long-term archival format, preserves all metadata and UIDs; usable across projects and institutions; very slow and complicated.
Research file formats (nrrd, nifti): preserves essential metadata (i.e., image geometry); suitable for representing a single cohort, usable across experiments within a single project, by a small group of collaborators; fast and simple, suitable for images only.
Numpy array (npy, npz): does not preserve metadata, therefore it is only usable for a single experiment, by one or few closely collaborating researchers; fast and very simple, supports arbitrary dimensions and can represent non-image vector data.
Thank you so much for the quick response @lassoan.
Yes, compression could have definitely been a factor.
I was considering the idea of storing a hybrid format with NumPy array for pixel data, than JSON for key metadata of interest. The original dicom data could also be preserved in an archive.
This seems like an optimal combination for a ML pipeline, but would love to hear any possible downsides to this.
This is definitely a good approach for low-level ML pipeline, for a single user, for a specific experiment.
Downsides:
numpy file format is only supported in numpy: you cannot directly read it into any medical image computing software; there are no official, high-quality libraries for reading/writing them in any other languages (C++, Java, C#, etc.)
clumsy metadata storage: cannot easily store metadata in the same file, if you store data in separate files then there is a high risk of data corruption (when you copy/move/rename data)
no standard conventions for storing even the most essential metadata (image origin, spacing, axis directions, axis roles, dimensions): you can define your custom metadata format/conventions, but of course it would not be sustainable (imagine what would happen if every researcher would implement his own format)
For a specific application domain, larger group of users can agree in their own custom conventions. A good example for this is BIDS. They do something similar to what you describe (simple image file format + json sidecar for metadata). However, these solutions are only simple and efficient because all users work on sufficiently similar projects, so their assumptions and needs are similar.
For Nifti: What aspects are inflexible about the dimensions? I have used Nifti to store masks for abdominal imaging projects with standard MR dimensions of 512 x 512 x [slices].
Thanks again! I’m learning a lot from this conversation
Also, I think HDf5 will answer a lot of the considerations and works as a really nice medium for merging data formats such as numpy and attribute data.
See in the nifti standard. There is pretty much no flexibility in how you define 5 out of 7 dimensions.
In the nifti format, the first three dimensions are reserved to define the three spatial dimensions — x , y and z —, while the fourth dimension is reserved to define the time points — t . The remaining dimensions, from fifth to seventh, are for other uses. The fifth dimension, however, can still have some predefined uses, such as to store voxel-specific distributional parameters or to hold vector-based data.
HDF5 is a very powerful container format. Unfortunately, it is so complex that in practice it often creates more problems than it solves (see for example here).
Compression always trades off file size for speed. Both NRRD and NIfTI use the gz format. This is an old, simple format. However, due to its popularity a lot of development has focused on optimizing this tool. Using an optimized gz-compatible library (CloudFlare, ng or lib deflate) can dramatically accelerate this format for single and parallel threaded environments.
A limitation of most compression schemes (gz, zstd, etc) is that they are tuned for text and 8-bit data. Raw MRI and CT scans are typically 16-bit integer, and 32-bit float is common for computation. With these data types, bit-shuffling can dramatically improve performance.
If you want to share data with other tools, leveraging the large ecosystem, I would encourage NIfTI or NRRD (uncompressed when speed matters, compressed for file size).
If you want a nice container format that is strictly for Python, you may want to look at zarr with its support of bit-shuffling optimized zstd. You could again choose uncompressed for speed, but would have access to a modern, high performance compression method that is optimized for your data.