Skip to content

Commit 419da77

Browse files
author
Ben Cipollini
committed
Localize Cifti to /cifti; use nib.load/save
1 parent 9eb7ae8 commit 419da77

File tree

8 files changed

+208
-153
lines changed

8 files changed

+208
-153
lines changed

nibabel/cifti/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
cifti
1818
"""
1919

20-
from .parse_cifti_fast import create_cifti_image
21-
from .cifti import (CiftiMetaData, CiftiHeader, CiftiImage, CiftiLabel,
22-
CiftiLabelTable, CiftiVertexIndices,
20+
from .parse_cifti_fast import CiftiExtension
21+
from .cifti import (CiftiMetaData, CiftiHeader, CiftiImage,
22+
CiftiDenseDataSeriesHeader, CiftiDenseDataSeries,
23+
CiftiLabel, CiftiLabelTable, CiftiVertexIndices,
2324
CiftiVoxelIndicesIJK, CiftiBrainModel, CiftiMatrix,
2425
CiftiMatrixIndicesMap, CiftiNamedMap, CiftiParcel,
2526
CiftiSurface, CiftiTransformationMatrixVoxelIndicesIJKtoXYZ,
2627
CiftiVertices, CiftiVolume, CIFTI_BrainStructures,
2728
CIFTI_MODEL_TYPES, load, save)
28-

nibabel/cifti/cifti.py

Lines changed: 74 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
1919
'''
2020
from __future__ import division, print_function, absolute_import
21-
from ..externals.six import string_types
2221

2322
import numpy as np
2423

25-
DEBUG_PRINT = False
24+
from ..externals.six import string_types
25+
from ..filebasedimages import FileBasedImage, FileBasedHeader
26+
from ..nifti1 import Nifti1Extension
27+
from ..nifti2 import Nifti2Image
28+
2629

2730
CIFTI_MAP_TYPES = ('CIFTI_INDEX_TYPE_BRAIN_MODELS',
2831
'CIFTI_INDEX_TYPE_PARCELS',
@@ -726,7 +729,7 @@ def to_xml(self, prefix='', indent=' '):
726729
return res
727730

728731

729-
class CiftiHeader(object):
732+
class CiftiHeader(FileBasedHeader):
730733
''' Class for Cifti2 header extension '''
731734

732735
version = str
@@ -752,65 +755,88 @@ def from_header(klass, header=None):
752755
return header.copy()
753756
raise ValueError('header is not a CiftiHeader')
754757

755-
class CiftiImage(object):
758+
@classmethod
759+
def may_contain_header(klass, binaryblock):
760+
from .parse_cifti_fast import _CiftiAsNiftiHeader
761+
return _CiftiAsNiftiHeader.may_contain_header(binaryblock)
762+
763+
764+
class CiftiImage(FileBasedImage):
765+
# It is a Nifti2Image, but because Nifti2Image object
766+
# contains both the *format* and the assumption that it's
767+
# a spatial image, we can't inherit directly.
756768
header_class = CiftiHeader
769+
valid_exts = Nifti2Image.valid_exts
770+
files_types = Nifti2Image.files_types
771+
makeable = False
772+
rw = True
757773

758774
def __init__(self, data=None, header=None, nifti_header=None):
759-
self.header = CiftiHeader()
760-
if header is not None:
761-
self.header = header
775+
self._header = header or CiftiHeader()
762776
self.data = data
763777
self.extra = nifti_header
764778

765-
@classmethod
766-
def instance_to_filename(klass, img, filename):
767-
''' Save `img` in our own format, to name implied by `filename`
779+
def get_data(self):
780+
return self.data
768781

769-
This is a class method
782+
@classmethod
783+
def from_file_map(klass, file_map):
784+
""" Load a Gifti image from a file_map
770785
771786
Parameters
772-
----------
773-
img : ``spatialimage`` instance
774-
In fact, an object with the API of ``spatialimage`` -
775-
specifically ``get_data``, ``get_affine``, ``get_header`` and
776-
``extra``.
777-
filename : str
778-
Filename, implying name to which to save image.
779-
'''
780-
img = klass.from_image(img)
781-
img.to_filename(filename)
787+
file_map : string
782788
783-
@classmethod
784-
def from_image(klass, img):
785-
''' Class method to create new instance of own class from `img`
789+
Returns
790+
-------
791+
img : GiftiImage
792+
Returns a GiftiImage
793+
"""
794+
from .parse_cifti_fast import _CiftiAsNiftiImage, CiftiExtension
795+
nifti_img = _CiftiAsNiftiImage.from_file_map(file_map)
796+
797+
# Get cifti header
798+
cifti_header = reduce(lambda accum, item: item.get_content()
799+
if isinstance(item, CiftiExtension)
800+
else accum,
801+
nifti_img.get_header().extensions or [],
802+
None)
803+
if cifti_header is None:
804+
raise ValueError(('Nifti2 header does not contain a CIFTI '
805+
'extension'))
806+
807+
# Construct cifti image
808+
cifti_img = CiftiImage(data=np.squeeze(nifti_img.get_data()),
809+
header=cifti_header,
810+
nifti_header=nifti_img.get_header())
811+
cifti_img.file_map = nifti_img.file_map
812+
return cifti_img
813+
814+
def to_file_map(self, file_map=None):
815+
""" Save the current image to the specified file_map
786816
787817
Parameters
788818
----------
789-
img : ``spatialimage`` instance
790-
In fact, an object with the API of ``spatialimage`` -
791-
specifically ``get_data``, ``get_affine``, ``get_header`` and
792-
``extra``.
819+
file_map : string
793820
794821
Returns
795822
-------
796-
cimg : ``spatialimage`` instance
797-
Image, of our own class
798-
'''
799-
return klass(img._dataobj,
800-
klass.header_class.from_header(img.header),
801-
extra=img.extra.copy())
802-
803-
def to_filename(self, filename):
804-
if not filename.endswith('nii'):
805-
ValueError('CIFTI files have to be stored as uncompressed NIFTI2')
806-
from ..nifti2 import Nifti2Image
807-
from ..nifti1 import Nifti1Extension
808-
data = np.reshape(self.data, [1, 1, 1, 1] + list(self.data.shape))
823+
None
824+
"""
825+
from .parse_cifti_fast import CiftiExtension
809826
header = self.extra
810-
extension = Nifti1Extension(32, self.header.to_xml().encode())
827+
extension = CiftiExtension(content=self.header.to_xml().encode())
811828
header.extensions.append(extension)
829+
data = np.reshape(self.data, [1, 1, 1, 1] + list(self.data.shape))
812830
img = Nifti2Image(data, None, header)
813-
img.to_filename(filename)
831+
img.to_file_map(file_map or self.file_map)
832+
833+
834+
class CiftiDenseDataSeriesHeader(CiftiHeader):
835+
836+
@classmethod
837+
def may_contain_header(klass, binaryblock):
838+
from .parse_cifti_fast import _CiftiDenseDataSeriesNiftiHeader
839+
return _CiftiDenseDataSeriesNiftiHeader.may_contain_header(binaryblock)
814840

815841

816842
class CiftiDenseDataSeries(CiftiImage):
@@ -831,7 +857,9 @@ class CiftiDenseDataSeries(CiftiImage):
831857
series of sampling depths along the surface normal from the white to pial
832858
surface. It retains the 't' in dtseries from CIFTI-1 naming conventions.
833859
"""
834-
suffix = '.dtseries.nii'
860+
header_class = CiftiDenseDataSeriesHeader
861+
valid_exts = ('.dtseries.nii',)
862+
files_types = (('image', '.dtseries.nii'),)
835863

836864

837865
def load(filename):
@@ -852,8 +880,8 @@ def load(filename):
852880
ImageFileError: if `filename` doesn't look like cifti
853881
IOError : if `filename` does not exist
854882
"""
855-
from ..nifti2 import load as Nifti2load
856-
return Nifti2load(filename).as_cifti()
883+
from .parse_cifti_fast import _CiftiAsNiftiImage
884+
return _CiftiAsNiftiImage.from_filename(filename)
857885

858886

859887
def save(img, filename):
@@ -865,5 +893,3 @@ def save(img, filename):
865893
filename to which to save image
866894
"""
867895
CiftiImage.instance_to_filename(img, filename)
868-
869-

0 commit comments

Comments
 (0)