Skip to content

Commit 368c407

Browse files
committed
Merge pull request #322 from matthew-brett/read-par-exts
MRG: reading PAR headers from NIfTI extensions A small function to fetch PARHeader object from PAR headers recorded in NIfTI comment extensions.
2 parents ad95b4e + 543200a commit 368c407

File tree

2 files changed

+69
-5
lines changed

2 files changed

+69
-5
lines changed

nibabel/parrec.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
import numpy as np
9696
from copy import deepcopy
9797
import re
98+
from io import StringIO
99+
from locale import getpreferredencoding
98100

99101
from .keywordonly import kw_only_meth
100102
from .spatialimages import SpatialImage, Header
@@ -280,8 +282,6 @@ def _split_header(fobj):
280282
return version, gen_dict, image_lines
281283

282284

283-
284-
285285
def _process_gen_dict(gen_dict):
286286
""" Process `gen_dict` key, values into `general_info`
287287
"""
@@ -504,6 +504,36 @@ def _data_from_rec(rec_fileobj, in_shape, dtype, slice_indices, out_shape,
504504
return rec_data
505505

506506

507+
def exts2pars(exts_source):
508+
"""Parse, return any PAR headers from NIfTI extensions in `exts_source`
509+
510+
Parameters
511+
----------
512+
exts_source : sequence or `Nifti1Image`, `Nifti1Header` instance
513+
A sequence of extensions, or header containing NIfTI extensions, or an
514+
image containing a header with NIfTI extensions.
515+
516+
Returns
517+
-------
518+
par_headers : list
519+
A list of PARRECHeader objects, usually empty or with one element, each
520+
element contains a PARRECHeader read from the contained extensions.
521+
"""
522+
headers = []
523+
exts_source = (exts_source.header if hasattr(exts_source, 'header')
524+
else exts_source)
525+
exts_source = (exts_source.extensions if hasattr(exts_source, 'extensions')
526+
else exts_source)
527+
for extension in exts_source:
528+
content = extension.get_content()
529+
content = content.decode(getpreferredencoding(False))
530+
if not content.startswith('# === DATA DESCRIPTION FILE ==='):
531+
continue
532+
gen_info, image_info = parse_PAR_header(StringIO(content))
533+
headers.append(PARRECHeader(gen_info, image_info))
534+
return headers
535+
536+
507537
class PARRECArrayProxy(object):
508538
@kw_only_meth(2)
509539
def __init__(self, file_like, header, mmap=True, scaling='dv'):

nibabel/tests/test_parrec.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
from os.path import join as pjoin, dirname, basename
55
from glob import glob
66
from warnings import simplefilter
7-
import shutil
87

98
import numpy as np
109
from numpy import array as npa
1110

1211
from .. import load as top_load
12+
from ..nifti1 import Nifti1Image, Nifti1Extension
1313
from .. import parrec
1414
from ..parrec import (parse_PAR_header, PARRECHeader, PARRECError, vol_numbers,
15-
vol_is_full, PARRECImage, PARRECArrayProxy)
15+
vol_is_full, PARRECImage, PARRECArrayProxy, exts2pars)
1616
from ..openers import Opener
1717
from ..fileholders import FileHolder
1818
from ..volumeutils import array_from_file
@@ -21,7 +21,7 @@
2121
assert_array_equal)
2222

2323
from nose.tools import (assert_true, assert_false, assert_raises,
24-
assert_equal, assert_not_equal)
24+
assert_equal)
2525

2626
from ..testing import catch_warn_reset, suppress_warnings
2727

@@ -600,3 +600,37 @@ def test_anonymized():
600600
assert_almost_equal(img_defs['window center'][-1], 236.385836385836, 6)
601601
assert_almost_equal(img_defs['window width'][0], 767.277167277167, 6)
602602
assert_almost_equal(img_defs['window width'][-1], 236.385836385836, 6)
603+
604+
605+
def test_exts2par():
606+
# Test we can load PAR headers from NIfTI extensions
607+
par_img = PARRECImage.from_filename(EG_PAR)
608+
nii_img = Nifti1Image.from_image(par_img)
609+
assert_equal(exts2pars(nii_img), [])
610+
assert_equal(exts2pars(nii_img.header), [])
611+
assert_equal(exts2pars(nii_img.header.extensions), [])
612+
assert_equal(exts2pars([]), [])
613+
# Add a header extension
614+
with open(EG_PAR, 'rb') as fobj:
615+
hdr_dump = fobj.read()
616+
dump_ext = Nifti1Extension('comment', hdr_dump)
617+
nii_img.header.extensions.append(dump_ext)
618+
hdrs = exts2pars(nii_img)
619+
assert_equal(len(hdrs), 1)
620+
# Test attribute from PARRECHeader
621+
assert_equal(hdrs[0].get_slice_orientation(), 'transverse')
622+
# Add another PAR extension
623+
nii_img.header.extensions.append(Nifti1Extension('comment', hdr_dump))
624+
hdrs = exts2pars(nii_img)
625+
assert_equal(len(hdrs), 2)
626+
# Test attribute from PARRECHeader
627+
assert_equal(hdrs[1].get_slice_orientation(), 'transverse')
628+
# Add null extension, ignored
629+
nii_img.header.extensions.append(Nifti1Extension('comment', b''))
630+
# Check all valid inputs
631+
for source in (nii_img,
632+
nii_img.header,
633+
nii_img.header.extensions,
634+
list(nii_img.header.extensions)):
635+
hdrs = exts2pars(source)
636+
assert_equal(len(hdrs), 2)

0 commit comments

Comments
 (0)