From 9fa9ee4b016eb8befae1e087fe66fc80df8f6771 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Thu, 1 Sep 2016 15:25:13 +0100
Subject: [PATCH] Fix to ImageWrapper to workaround nibabel truncating trailing
 dimensions of lenght 1.

---
 fsl/data/imagewrapper.py | 36 +++++++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/fsl/data/imagewrapper.py b/fsl/data/imagewrapper.py
index 6acf0c1ea..79a5b0c37 100644
--- a/fsl/data/imagewrapper.py
+++ b/fsl/data/imagewrapper.py
@@ -79,7 +79,10 @@ class ImageWrapper(notifier.Notifier):
     The ``ImageWrapper`` abstracts away trailing image dimensions of length 1.
     This means that if the header for a NIFTI image specifies that the image
     has four dimensions, but the fourth dimension is of length 1, you do not
-    need to worry about indexing that fourth dimension.
+    need to worry about indexing that fourth dimension. However, all NIFTI
+    images will be presented as having at least three dimensions, so if your
+    image header specifies a third dimension of length 1, you will still
+    need provide an index of 0 for that dimensions, for all data accesses.
 
 
     *Data range*
@@ -88,7 +91,7 @@ class ImageWrapper(notifier.Notifier):
     In order to avoid the computational overhead of calculating the image data
     range (its minimum/maximum values) when an image is first loaded in, an
     ``ImageWrapper`` incrementally updates the known image data range as data
-    is accessed. The ``ImageWrapper`` keeps track of the image data _coverage_,
+    is accessed. The ``ImageWrapper`` keeps track of the image data *coverage*,
     the portion of the image which has already been considered in the data
     range calculation. When data from a region of the image not in the coverage
     is accessed, the coverage is expanded to include this region. The coverage
@@ -204,11 +207,11 @@ class ImageWrapper(notifier.Notifier):
 
 
         .. note:: The ``dataRange`` parameter is intended for situations where
-                  the image data range is known (e.g. it was calculated
-                  earlier, and the image is being re-loaded). If a
+                  the image data range is known in advance (e.g. it was
+                  calculated earlier, and the image is being re-loaded). If a
                   ``dataRange`` is passed in, it will *not* be overwritten by
                   any range calculated from the data, unless the calculated
-                  data range is wider than the provided ``dataRange``. 
+                  data range is wider than the provided ``dataRange``.
         """
         
         if dataRange is None:
@@ -332,6 +335,14 @@ class ImageWrapper(notifier.Notifier):
         if isTuple:
             sliceobj = sliceTupleToSliceObj(sliceobj)
 
+        # Truncate some dimensions from the
+        # slice object if it has too many
+        # (e.g. trailing dims of length 1).
+        ndims = len(self.__image.shape)
+
+        if len(sliceobj) > ndims:
+            sliceobj = sliceobj[:ndims]
+
         # If the image has not been loaded
         # into memory, we can use the nibabel
         # ArrayProxy. Otheriwse if it is in
@@ -527,8 +538,19 @@ class ImageWrapper(notifier.Notifier):
 
         log.debug('Getting image data: {}'.format(sliceobj))
 
-        sliceobj = nib.fileslice.canonical_slicers(
-            sliceobj, self.__image.shape)
+        if not isinstance(sliceobj, tuple):
+            sliceobj = (sliceobj,)
+
+        # Truncate some dimensions from the
+        # slice object if it has too many
+        # (e.g. trailing dims of length 1).
+        shape = self.__image.shape
+        ndims = len(shape)
+
+        if len(sliceobj) > ndims:
+            sliceobj = sliceobj[:ndims]
+
+        sliceobj = nib.fileslice.canonical_slicers(sliceobj, shape)
 
         # TODO Cache 3D images for large 4D volumes, 
         #      so you don't have to hit the disk?
-- 
GitLab