Skip to content

Commit 084dd1c

Browse files
Merge pull request #576 from pauldmccarthy/unambiguify_nifti_docs
MRG: Clarification to docs regarding initial sform/qform code values
2 parents 2139ce0 + 188b194 commit 084dd1c

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

doc/source/nifti_images.rst

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,63 @@ The algorithm is defined in the ``get_best_affine()`` method. It is:
314314
#. If ``qform_code`` != 0 ('unknown') use the qform affine; else
315315
#. Use the fall-back affine.
316316

317+
.. _default-sform-qform-codes:
318+
319+
Default sform and qform codes
320+
=============================
321+
322+
If you create a new image, e.g.:
323+
324+
>>> data = np.random.random((20, 20, 20))
325+
>>> xform = np.eye(4) * 2
326+
>>> img = nib.nifti1.Nifti1Image(data, xform)
327+
328+
The sform and qform codes will be initialised to 2 (aligned) and 0 (unknown)
329+
respectively:
330+
331+
>>> img.get_sform(coded=True) # doctest: +NORMALIZE_WHITESPACE
332+
(array([[ 2., 0., 0., 0.],
333+
[ 0., 2., 0., 0.],
334+
[ 0., 0., 2., 0.],
335+
[ 0., 0., 0., 1.]]), array(2, dtype=int16))
336+
>>> img.get_qform(coded=True)
337+
(None, 0)
338+
339+
This is based on the assumption that the affine you specify for a newly
340+
created image will align the image to some known coordinate system. According
341+
to the `NIfTI specification <nifti1>`_, the qform is intended to encode a
342+
transformation into scanner coordinates - for a programmatically created
343+
image, we have no way of knowing what the scanner coordinate system is;
344+
furthermore, the qform cannot be used to store an arbitrary affine transform,
345+
as it is unable to encode shears. So the provided affine will be stored in the
346+
sform, and the qform will be left uninitialised.
347+
348+
If you create a new image and specify an existing header, e.g.:
349+
350+
>>> example_ni1 = os.path.join(data_path, 'example4d.nii.gz')
351+
>>> n1_img = nib.load(example_ni1)
352+
>>> new_header = header=n1_img.header.copy()
353+
>>> new_data = np.random.random(n1_img.shape[:3])
354+
>>> new_img = nib.nifti1.Nifti1Image(data, None, header=new_header)
355+
356+
then the newly created image will inherit the same sform and qform codes that
357+
are in the provided header. However, if you create a new image with both an
358+
affine and a header specified, e.g.:
359+
360+
>>> xform = np.eye(4)
361+
>>> new_img = nib.nifti1.Nifti1Image(data, xform, header=new_header)
362+
363+
then the sform and qform codes will *only* be preserved if the provided affine
364+
is the same as the affine in the provided header. If the affines do not match,
365+
the sform and qform codes will be set to their default values of 2 and 0
366+
respectively. This is done on the basis that, if you are changing the affine,
367+
you are likely to be changing the space to which the affine is pointing. So
368+
the original sform and qform codes can no longer be assumed to be valid.
369+
370+
If you wish to set the sform and qform affines and/or codes to some other
371+
value, you can always set them after creation using the ``set_sform`` and
372+
``set_qform`` methods, as described above.
373+
317374
************
318375
Data scaling
319376
************

nibabel/nifti1.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,7 +1764,20 @@ def __init__(self, dataobj, affine, header=None,
17641764
if header is None and affine is not None:
17651765
self._affine2header()
17661766
# Copy docstring
1767-
__init__.doc = analyze.AnalyzeImage.__init__.__doc__
1767+
__init__.__doc__ = analyze.AnalyzeImage.__init__.__doc__ + '''
1768+
Notes
1769+
-----
1770+
1771+
If both a `header` and an `affine` are specified, and the `affine` does
1772+
not match the affine that is in the `header`, the `affine` will be used,
1773+
but the ``sform_code`` and ``qform_code`` fields in the header will be
1774+
re-initialised to their default values. This is performed on the basis
1775+
that, if you are changing the affine, you are likely to be changing the
1776+
space to which the affine is pointing. The :meth:`set_sform` and
1777+
:meth:`set_qform` methods can be used to update the codes after an image
1778+
has been created - see those methods, and the :ref:`manual
1779+
<default-sform-qform-codes>` for more details. '''
1780+
17681781

17691782
def update_header(self):
17701783
''' Harmonize header with image data and affine

0 commit comments

Comments
 (0)