# SimpleITK writing NIfTI with invalid header

**URL:** <https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498>\
**Category:** Uncategorized\
**Tags:** simpleitk\
**Created:** [December 9, 2019, 6:59pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498 "2019-12-09T18:59:33Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [December 9, 2019, 6:59pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/1 "2019-12-09T18:59:34Z")

</div>

Hello,

I’m using SimpleITK 1.2.4 to read and write NIfTI images. [NIfTI docs](https://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/qsform.html) say that it “should not occur” that `qfac` is `0`. `qfac` is the first value of the `pixdim` array in the header and is expected to be `-1` or `1`.

When I create an image using `GetImageFromArray`, the written header is fine. If I read and write and image with SimpleITK, the header is incorrect. Here’s some code to show what I mean, and the output:

```python
import gzip
import struct
from pathlib import Path
from tempfile import NamedTemporaryFile
import numpy as np
import nibabel as nib
import SimpleITK as sitk

def get_qfac(image_path):
    image_path = Path(image_path)
    with NamedTemporaryFile(suffix='.nii') as f:
        if image_path.suffix == '.gz':
            with gzip.open(image_path, 'rb') as f_in:
                with open(f.name, 'wb') as f_out:
                    shutil.copyfileobj(f_in, f_out)
            image_path = f.name
        with open(image_path, 'rb') as f:
            fmt = 8 * 'f'
            size = struct.calcsize(fmt)
            f.seek(76)
            chunk = f.read(size)
            pixdim = struct.unpack(fmt, chunk)
    qfac = pixdim[0]
    return qfac

def check_qfac(image_path):
    qfac = get_qfac(image_path)
    if qfac in (-1, 1):
        print('qfac is ok:', qfac)
    else:
        print(f'qfac is {qfac} in {image_path}')

def main():
    filepath_nib = '/tmp/test_nib.nii'
    filepath_itk = '/tmp/test_itk.nii'
    array = np.random.rand(10,10,10)
    affine = np.eye(4)

    print('Written with NiBabel')
    nib.Nifti1Image(array, affine).to_filename(filepath_nib)
    check_qfac(filepath_nib)

    print('\nGetImageFromArray, written with ITK')
    im = sitk.GetImageFromArray(array)
    sitk.WriteImage(im, filepath_itk)
    check_qfac(filepath_itk)

    print('\nRead and write with ITK')
    im = sitk.ReadImage(filepath_nib)
    sitk.WriteImage(im, filepath_itk)
    check_qfac(filepath_itk)

if __name__ == " __main__":
    main()

```

Output:

```auto
Written with NiBabel
qfac is ok: 1.0

GetImageFromArray, written with ITK
qfac is ok: 1.0

Read and write with ITK
qfac is 0.0 in /tmp/test_itk.nii

```

Do you know what could be happening?

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [December 9, 2019, 7:11pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/2 "2019-12-09T19:11:46Z")

</div>

When you first read an image in ITK, the Image may contain additional meta data tags from the reader. I did a test with NifTi and there were quite a lot of NifTi tags:

```auto
In [1]: import SimpleITK as sitk                                                                                                                                                                                           

In [2]: img = sitk.Image([10,9], sitk.sitkUInt8)                                                                                                                                                                           

In [3]: sitk.WriteImage(img, "foo.nii")                                                                                                                                                                                    

In [4]: rimg = sitk.ReadImage("foo.nii")                                                                                                                                                                                   
...
In [6]: for k in rimg.GetMetaDataKeys(): 
   ...: v = rimg.GetMetaData(k) 
   ...: print("({0}) = = \"{1}\"".format(k,v)) 
   ...:                                                                                                                                                                                                                    
(ITK_FileNotes) = = ""
(aux_file) = = ""
(bitpix) = = "8"
(cal_max) = = "0"
(cal_min) = = "0"
(datatype) = = "2"
(descrip) = = ""
(dim[0]) = = "2"
(dim[1]) = = "10"
(dim[2]) = = "9"
(dim[3]) = = "1"
(dim[4]) = = "1"
(dim[5]) = = "1"
(dim[6]) = = "1"
(dim[7]) = = "1"
(dim_info) = = ""
(intent_code) = = "0"
(intent_name) = = ""
(intent_p1) = = "0"
(intent_p2) = = "0"
(intent_p3) = = "0"
(pixdim[0]) = = "1"
(pixdim[1]) = = "1"
(pixdim[2]) = = "1"
(pixdim[3]) = = "1"
(pixdim[4]) = = "0"
(pixdim[5]) = = "0"
(pixdim[6]) = = "0"
(pixdim[7]) = = "0"
(qform_code) = = "1"
(qform_code_name) = = "NIFTI_XFORM_SCANNER_ANAT"
(qoffset_x) = = "-0"
(qoffset_y) = = "-0"
(qoffset_z) = = "0"
(quatern_b) = = "0"
(quatern_c) = = "0"
(quatern_d) = = "1"
(scl_inter) = = "0"
(scl_slope) = = "1"
(sform_code) = = "0"
(sform_code_name) = = "NIFTI_XFORM_UNKNOWN"
(slice_code) = = ""
(slice_duration) = = "0"
(slice_end) = = "0"
(slice_start) = = "0"
(srow_x) = = "0 0 0 0"
(srow_y) = = "0 0 0 0"
(srow_z) = = "0 0 0 0"
(toffset) = = "0"
(vox_offset) = = "352"
(xyzt_units) = = ""

```

I’m guessing that the `itk::NifTiImageIO` reader is trying to do something “smart” with the NifTi tags to preserve them. Clearly there is a bug here.

With ITK, when an image if filtered the meta-data tags are not propagated, the this issue is not frequently encountered.

You can call [`EraseMetaData`](https://itk.org/SimpleITKDoxygen/html/classitk_1_1simple_1_1Image.html#af5c224f1f5173836258dbb983341a2f9) to remove the extraneous/redundant tags.

---

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [December 9, 2019, 7:44pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/3 "2019-12-09T19:44:36Z")

</div>

Thanks for your reply, @blowekamp.

Adding `im.EraseMetaData('pixdim[0]')` before my calls to `sitk.WriteImage` in my previous example didn’t help.

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [December 9, 2019, 7:55pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/4 "2019-12-09T19:55:27Z")

</div>

Try deleting all MetaData elements. The default behavior of an ITK filter is not to propagate the tags so “I’m += 0” would be the easiest was to accomplish this.

---

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [December 10, 2019, 12:53am UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/5 "2019-12-10T00:53:46Z")

</div>

Thanks, I’ll do that. Should I create an issue on ITK/SimpleITK on GitHub?

---

<div class="post-metadata">

**Author:** ![lassoan](https://discourse.itk.org/user_avatar/discourse.itk.org/lassoan/32/27_2.png) [@lassoan](https://discourse.itk.org/u/lassoan)\
**Post date:** [December 10, 2019, 6:28am UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/6 "2019-12-10T06:28:21Z")

</div>

Instead of nifti, can you use a general-purpose 3D image file format, such as nrrd or metaimage?

Nifti makes sense for neuroimaging, but for all other fields, it is so inconvenient - there are many complications due to that directions can be defined using several different approaches, header is not human-readable and not easy to extend, there are lots of irrelevant (neuroimaging specific) fields but nothing for any other specialty, etc.

---

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [December 10, 2019, 8:20am UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/7 "2019-12-10T08:20:33Z")

</div>

Hi Andras,

Definitely going to switch to NRRD soon, I’ve had enough issues with NIfTI over the last years.

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [December 10, 2019, 9:19pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/8 "2019-12-10T21:19:50Z")

</div>

> [@fepegar](#):
>
> Thanks, I’ll do that. Should I create an issue on ITK/SimpleITK on GitHub?

If there is a bug it would be in the itk:NifTiImageIO class, so that is an ITK bug.

I was able to reproduce the same behavior. However, if all NifTi metadata tags are removed before rewriting the file then the error does not occur. As @lassoan says, the NifTi spec is a bit complicated and it’s not clear what the valid states are for the redundant data.

---

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [December 11, 2019, 7:20am UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/9 "2019-12-11T07:20:42Z")

</div>

> [@blowekamp](#):
>
> I was able to reproduce the same behavior. However, if all NifTi metadata tags are removed before rewriting the file then the error does not occur.

Yes, but this is a hack.  
I’ll report the bug on the ITK tracker. Thanks for your help, @blowekamp.

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [December 11, 2019, 2:00pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/10 "2019-12-11T14:00:57Z")

</div>

> [@fepegar](#):
>
> Yes, but this is a hack.

There is something funny going on here that hopefully can be addressed. However, this is not as much of a “hack” as one might think. It is best practice to inspect the meta-data dictionary before writing an itk::Image. Since the meta-data dictionary is not propagate between filter generally this step is omitted. For this case the reader provides every detail of the NifTi header in the meta-data dictionary. These meta-data fields should not be written out as meta-data, but the fields are represented by then itk::Image’s geometric information which gets written in the NifTi header.

If you would like code that directly does the operations consider:

```auto
def strip_metadata(img):
  for k in img.GetMetaDataKeys():
    img.EraseMetaData(k)

```

---

<div class="post-metadata">

**Author:** ![pip010](https://discourse.itk.org/user_avatar/discourse.itk.org/pip010/32/1363_2.png) [@pip010](https://discourse.itk.org/u/pip010)\
**Post date:** [December 7, 2020, 12:12pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/11 "2020-12-07T12:12:21Z")

</div>

> [@blowekamp](#):
>
> It is best practice to inspect the meta-data dictionary before writing an itk::Image. Since the meta-data dictionary is not propagate between filter generally this step is omitted.

This sounds a bit like oxymoron to me.

I’ve looked into way to customize how spacing is defined q-form versus s-form. Anyway, I can instruct the NiftiIO to prefer the one or the other upon saving? For instance on load the trick of overwriting s-form/q-form meta data works. That is I can force ITK to prefer s-form instead of the default q-form but now way to achieve the same upon saving ☹

---

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [December 7, 2020, 12:19pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/12 "2020-12-07T12:19:29Z")

</div>

I forgot to reference my issue (which has been marked as “stale” by a bot) on ITK: [https://github.com/InsightSoftwareConsortium/ITK/issues/1484](https://github.com/InsightSoftwareConsortium/ITK/issues/1484)

---

<div class="post-metadata">

**Author:** ![gdevenyi](https://discourse.itk.org/user_avatar/discourse.itk.org/gdevenyi/32/355_2.png) [@gdevenyi](https://discourse.itk.org/u/gdevenyi)\
**Post date:** [August 26, 2022, 6:07pm UTC](https://discourse.itk.org/t/simpleitk-writing-nifti-with-invalid-header/2498/13 "2022-08-26T18:07:17Z")

</div>

ITK’s NIFTIO always writes out “Method 3” (sform \> 0) NIFTI files, from what I can tell. This I believe was chosen because sform can store coordinates with more precision.

qfac is only a valid code for “Method 2”, it is not used for “Method 3” reading, which means that while invalid, it shouldn’t be used by other software reading the file.

The spec is “should not” vs. must not. But we know how well in general the NIFTI spec has been followed…
