From 72da9475f6b4f8c1e9b0fb906e6482e98fae9dec Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Wed, 1 Nov 2017 09:44:22 +0000 Subject: [PATCH] Resample methods explicitly raises an error when num dims is wrong. Cleaned up related code in atlas classes --- fsl/data/atlases.py | 59 +++++++++++++++++++++++++++++---------------- fsl/data/image.py | 6 ++++- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/fsl/data/atlases.py b/fsl/data/atlases.py index 59122134f..6ed038f1a 100644 --- a/fsl/data/atlases.py +++ b/fsl/data/atlases.py @@ -675,6 +675,42 @@ class Atlas(fslimage.Image): return self.desc.find(*args, **kwargs) + def prepareMask(self, mask): + """Makes sure that the given mask has the same resolution as this + atlas, so it can be used for querying. Used by the + :meth:`.LabelAtlas.maskLabels` and + :meth:`.ProbabilisticAtlas.maskProportions` methods. + + :arg mask: A :class:`.Image` + + :returns: A ``numpy`` array containing the resampled mask data. + + :raises: A :exc:`MaskError` if the mask is not in the same space as + this atlas, or does not have three dimensions. + """ + + # Make sure that the mask has the same + # number of voxels as the atlas image. + # Use nearest neighbour interpolation + # for resampling, as it is most likely + # that the mask is binary. + try: + mask, xform = mask.resample(self.shape[:3], + dtype=np.float32, + order=0) + + except ValueError: + raise MaskError('Mask has wrong number of dimensions') + + # TODO allow non-aligned mask - as long as it overlaps + # in world coordinates, it should be allowed + if not fslimage.Image(mask, xform=xform).sameSpace(self): + raise MaskError('Mask is not in the same space as atlas') + + return mask + + + class MaskError(Exception): """Exception raised by the :meth:`LabelAtlas.maskLabel` and :meth:`ProbabilisticAtlas.maskProportions` when a mask is provided which @@ -781,23 +817,10 @@ class LabelAtlas(Atlas): associated with each returned value. """ - # Make sure that the mask has the same - # number of voxels as the atlas image. - # Use nearest neighbour interpolation - # for resampling, as it is most likely - # that the mask is binary. - mask, xform = mask.resample(self.shape[:3], dtype=np.float32, order=0) - - if not fslimage.Image(mask, xform=xform).sameSpace(self): - raise MaskError('Mask is not in the same space as atlas') - - # TODO allow non-aligned mask - as long as it overlaps - # in world coordinates, it should be allowed - - # Extract the values that are in # the mask, and their corresponding # mask weights + mask = self.prepareMask(mask) boolmask = mask > 0 vals = self[boolmask] weights = mask[boolmask] @@ -924,13 +947,7 @@ class ProbabilisticAtlas(Atlas): props = [] - # Make sure that the mask has the same - # number of voxels as the atlas image - mask, xform = mask.resample(self.shape[:3], dtype=np.float32, order=0) - - if not fslimage.Image(mask, xform=xform).sameSpace(self): - raise MaskError('Mask is not in the same space as atlas') - + mask = self.prepareMask(mask) boolmask = mask > 0 weights = mask[boolmask] weightsum = weights.sum() diff --git a/fsl/data/image.py b/fsl/data/image.py index b1c93c087..3b3e87041 100644 --- a/fsl/data/image.py +++ b/fsl/data/image.py @@ -1149,7 +1149,8 @@ class Image(Nifti): :arg sliceobj: Slice into this ``Image``. If ``None``, the whole image is resampled, and it is assumed that it has the - same number of dimensions as ``shape``. + same number of dimensions as ``shape``. A + :exc:`ValueError` is raised if this is not the case. :arg dtype: ``numpy`` data type of the resampled data. If ``None``, the :meth:`dtype` of this ``Image`` is used. @@ -1184,6 +1185,9 @@ class Image(Nifti): oldShape = np.array(data.shape, dtype=np.float) newShape = np.array(newShape, dtype=np.float) + if len(oldShape) != len(newShape): + raise ValueError('Shapes don\'t match') + if not np.all(np.isclose(oldShape, newShape)): ratio = oldShape / newShape -- GitLab