From fb4b597afc21149d1ea5b0e91cfa78b8da5f1edc Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Tue, 27 Feb 2018 13:43:56 +0000 Subject: [PATCH] Image.__init__ allows a data source to be specified - affects the initial save state. Image.save ensures that file name has an extension. MGHImage uses both of these changes so that its initial save state is accurate, and when it is saved, it is saved as a nifti --- fsl/data/image.py | 100 +++++++++++++++++++++++-------------------- fsl/data/mghimage.py | 19 +++++++- 2 files changed, 71 insertions(+), 48 deletions(-) diff --git a/fsl/data/image.py b/fsl/data/image.py index c6f83c598..c03618d85 100644 --- a/fsl/data/image.py +++ b/fsl/data/image.py @@ -771,60 +771,64 @@ class Image(Nifti): calcRange=True, indexed=False, threaded=False, + dataSource=None, **kwargs): """Create an ``Image`` object with the given image data or file name. - :arg image: A string containing the name of an image file to load, - or a :mod:`numpy` array, or a :mod:`nibabel` image - object. - - :arg name: A name for the image. - - :arg header: If not ``None``, assumed to be a - :class:`nibabel.nifti1.Nifti1Header` or - :class:`nibabel.nifti2.Nifti2Header` to be used as the - image header. Not applied to images loaded from file, - or existing :mod:`nibabel` images. - - :arg xform: A :math:`4\\times 4` affine transformation matrix - which transforms voxel coordinates into real world - coordinates. If not provided, and a ``header`` is - provided, the transformation in the header is used. - If neither a ``xform`` nor a ``header`` are provided, - an identity matrix is used. If both a ``xform`` and a - ``header`` are provided, the ``xform`` is used in - preference to the header transformation. - - :arg loadData: If ``True`` (the default) the image data is loaded - in to memory. Otherwise, only the image header - information is read, and the image data is kept - from disk. In either case, the image data is - accessed through an :class:`.ImageWrapper` instance. - The data may be loaded into memory later on via the - :meth:`loadData` method. - - :arg calcRange: If ``True`` (the default), the image range is - calculated immediately (vi a call to - :meth:`calcRange`). Otherwise, the image range is - incrementally updated as more data is read from memory - or disk. - - :arg indexed: If ``True``, and the file is gzipped, it is opened - using the :mod:`indexed_gzip` package. Otherwise the - file is opened by ``nibabel``. Ignored if ``loadData`` - is ``True``. - - :arg threaded: If ``True``, the :class:`.ImageWrapper` will use a - separate thread for data range calculation. Defaults - to ``False``. Ignored if ``loadData`` is ``True``. + :arg image: A string containing the name of an image file to load, + or a :mod:`numpy` array, or a :mod:`nibabel` image + object. + + :arg name: A name for the image. + + :arg header: If not ``None``, assumed to be a + :class:`nibabel.nifti1.Nifti1Header` or + :class:`nibabel.nifti2.Nifti2Header` to be used as the + image header. Not applied to images loaded from file, + or existing :mod:`nibabel` images. + + :arg xform: A :math:`4\\times 4` affine transformation matrix + which transforms voxel coordinates into real world + coordinates. If not provided, and a ``header`` is + provided, the transformation in the header is used. + If neither a ``xform`` nor a ``header`` are provided, + an identity matrix is used. If both a ``xform`` and a + ``header`` are provided, the ``xform`` is used in + preference to the header transformation. + + :arg loadData: If ``True`` (the default) the image data is loaded + in to memory. Otherwise, only the image header + information is read, and the image data is kept + from disk. In either case, the image data is + accessed through an :class:`.ImageWrapper` instance. + The data may be loaded into memory later on via the + :meth:`loadData` method. + + :arg calcRange: If ``True`` (the default), the image range is + calculated immediately (vi a call to + :meth:`calcRange`). Otherwise, the image range is + incrementally updated as more data is read from memory + or disk. + + :arg indexed: If ``True``, and the file is gzipped, it is opened + using the :mod:`indexed_gzip` package. Otherwise the + file is opened by ``nibabel``. Ignored if ``loadData`` + is ``True``. + + :arg threaded: If ``True``, the :class:`.ImageWrapper` will use a + separate thread for data range calculation. Defaults + to ``False``. Ignored if ``loadData`` is ``True``. + + :arg dataSource: If ``image`` is not a file name, this argument may be + used to specify the file from which the image was + loaded. All other arguments are passed through to the ``nibabel.load`` function (if it is called). """ - nibImage = None - dataSource = None - fileobj = None + nibImage = None + fileobj = None if loadData: indexed = False @@ -1132,6 +1136,10 @@ class Image(Nifti): filename = op.abspath(filename) + # make sure the extension is specified + if not looksLikeImage(filename): + filename = addExt(filename, mustExist=False) + log.debug('Saving {} to {}'.format(self.name, filename)) # If this Image is not managing its diff --git a/fsl/data/mghimage.py b/fsl/data/mghimage.py index c1530d493..ba352c3e6 100644 --- a/fsl/data/mghimage.py +++ b/fsl/data/mghimage.py @@ -19,6 +19,7 @@ import os.path as op import six import nibabel as nib +import fsl.utils.path as fslpath import fsl.data.image as fslimage @@ -54,7 +55,7 @@ class MGHImage(fslimage.Image): name = op.basename(filename) image = nib.load(image) else: - name = None + name = 'MGH image' filename = None data = image.get_data() @@ -63,12 +64,26 @@ class MGHImage(fslimage.Image): fslimage.Image.__init__(self, data, xform=affine, - name=name) + name=name, + dataSource=filename) if filename is not None: self.setMeta('mghImageFile', filename) + def save(self, filename=None): + """Overrides :meth:`.Image.save`. If a ``filename`` is not provided, + converts the original (MGH) file name into a NIFTI filename, before + passing it to the :meth:`.Image.save` method. + """ + if filename is None: + filename = self.dataSource + + filename = fslpath.removeExt(filename, ALLOWED_EXTENSIONS) + + return fslimage.Image.save(self, filename) + + @property def mghImageFile(self): """If this ``MGHImage`` was loaded from a file, returns the file -- GitLab