Skip to content

ENH: reading PAR headers from NIfTI extensions #322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 9, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions nibabel/parrec.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@
import numpy as np
from copy import deepcopy
import re
from io import StringIO
from locale import getpreferredencoding

from .keywordonly import kw_only_meth
from .spatialimages import SpatialImage, Header
Expand Down Expand Up @@ -280,8 +282,6 @@ def _split_header(fobj):
return version, gen_dict, image_lines




def _process_gen_dict(gen_dict):
""" Process `gen_dict` key, values into `general_info`
"""
Expand Down Expand Up @@ -504,6 +504,36 @@ def _data_from_rec(rec_fileobj, in_shape, dtype, slice_indices, out_shape,
return rec_data


def exts2pars(exts_source):
"""Parse, return any PAR headers from NIfTI extensions in `exts_source`

Parameters
----------
exts_source : sequence or `Nifti1Image`, `Nifti1Header` instance
A sequence of extensions, or header containing NIfTI extensions, or an
image containing a header with NIfTI extensions.

Returns
-------
par_headers : list
A list of PARRECHeader objects, usually empty or with one element, each
element contains a PARRECHeader read from the contained extensions.
"""
headers = []
exts_source = (exts_source.header if hasattr(exts_source, 'header')
else exts_source)
exts_source = (exts_source.extensions if hasattr(exts_source, 'extensions')
else exts_source)
for extension in exts_source:
content = extension.get_content()
content = content.decode(getpreferredencoding(False))
if not content.startswith('# === DATA DESCRIPTION FILE ==='):
continue
gen_info, image_info = parse_PAR_header(StringIO(content))
headers.append(PARRECHeader(gen_info, image_info))
return headers


class PARRECArrayProxy(object):
@kw_only_meth(2)
def __init__(self, file_like, header, mmap=True, scaling='dv'):
Expand Down
40 changes: 37 additions & 3 deletions nibabel/tests/test_parrec.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
from os.path import join as pjoin, dirname, basename
from glob import glob
from warnings import simplefilter
import shutil

import numpy as np
from numpy import array as npa

from .. import load as top_load
from ..nifti1 import Nifti1Image, Nifti1Extension
from .. import parrec
from ..parrec import (parse_PAR_header, PARRECHeader, PARRECError, vol_numbers,
vol_is_full, PARRECImage, PARRECArrayProxy)
vol_is_full, PARRECImage, PARRECArrayProxy, exts2pars)
from ..openers import Opener
from ..fileholders import FileHolder
from ..volumeutils import array_from_file
Expand All @@ -21,7 +21,7 @@
assert_array_equal)

from nose.tools import (assert_true, assert_false, assert_raises,
assert_equal, assert_not_equal)
assert_equal)

from ..testing import catch_warn_reset, suppress_warnings

Expand Down Expand Up @@ -600,3 +600,37 @@ def test_anonymized():
assert_almost_equal(img_defs['window center'][-1], 236.385836385836, 6)
assert_almost_equal(img_defs['window width'][0], 767.277167277167, 6)
assert_almost_equal(img_defs['window width'][-1], 236.385836385836, 6)


def test_exts2par():
# Test we can load PAR headers from NIfTI extensions
par_img = PARRECImage.from_filename(EG_PAR)
nii_img = Nifti1Image.from_image(par_img)
assert_equal(exts2pars(nii_img), [])
assert_equal(exts2pars(nii_img.header), [])
assert_equal(exts2pars(nii_img.header.extensions), [])
assert_equal(exts2pars([]), [])
# Add a header extension
with open(EG_PAR, 'rb') as fobj:
hdr_dump = fobj.read()
dump_ext = Nifti1Extension('comment', hdr_dump)
nii_img.header.extensions.append(dump_ext)
hdrs = exts2pars(nii_img)
assert_equal(len(hdrs), 1)
# Test attribute from PARRECHeader
assert_equal(hdrs[0].get_slice_orientation(), 'transverse')
# Add another PAR extension
nii_img.header.extensions.append(Nifti1Extension('comment', hdr_dump))
hdrs = exts2pars(nii_img)
assert_equal(len(hdrs), 2)
# Test attribute from PARRECHeader
assert_equal(hdrs[1].get_slice_orientation(), 'transverse')
# Add null extension, ignored
nii_img.header.extensions.append(Nifti1Extension('comment', b''))
# Check all valid inputs
for source in (nii_img,
nii_img.header,
nii_img.header.extensions,
list(nii_img.header.extensions)):
hdrs = exts2pars(source)
assert_equal(len(hdrs), 2)