diff --git a/fsl/utils/transform.py b/fsl/utils/transform.py
index 459fae425328d5b80a0b1622a3364fe8a4bf0bf4..e3e4a7e748652bf1db796c64ffa13827a86ba0ab 100644
--- a/fsl/utils/transform.py
+++ b/fsl/utils/transform.py
@@ -123,34 +123,109 @@ def compose(scales, offsets, rotations, origin=None):
 
 def decompose(xform):
     """Decomposes the given transformation matrix into separate offsets,
-    scales, and rotations.
+    scales, and rotations, according to the algorithm described in:
 
-    .. note:: Shears are not yet supported, and may never be supported.
-    """
+    Spencer W. Thomas, Decomposing a matrix into simple transformations, pp
+    320-323 in *Graphics Gems II*, James Arvo (editor), Academic Press, 1991,
+    ISBN: 0120644819.
 
-    offsets = xform[:3, 3]
-    scales  = [np.sqrt(np.sum(xform[:3, 0] ** 2)),
-               np.sqrt(np.sum(xform[:3, 1] ** 2)),
-               np.sqrt(np.sum(xform[:3, 2] ** 2))]
-    
-    rotmat         = np.copy(xform[:3, :3])
-    rotmat[:, 0] /= scales[0]
-    rotmat[:, 1] /= scales[1]
-    rotmat[:, 2] /= scales[2]
+    It is assumed that the given transform has no perspective components. Any
+    shears in the affine are discarded.
 
-    rots = rotMatToAxisAngles(rotmat)
+    :arg xform: A ``(4, 4)`` affine transformation matrix.
 
-    return scales, offsets, rots
+    :returns: The following:
+                - A sequence of three scales
+                - A sequence of three translations
+                - A sequence of three rotations, in radians
+    """
+ 
+    # The inline comments in the code below are taken verbatim from
+    # the referenced article, [except for notes in square brackets].
+    
+    # The next step is to extract the translations. This is trivial;
+    # we find t_x = M_{4,1}, t_y = M_{4,2}, and t_z = M_{4,3}. At this
+    # point we are left with a 3*3 matrix M' = M_{1..3,1..3}.
+    xform        = xform.T
+    translations = xform[ 3, :3]
+    xform        = xform[:3, :3]
+
+    M1 = xform[0]
+    M2 = xform[1]
+    M3 = xform[2]
+
+    # The process of finding the scaling factors and shear parameters
+    # is interleaved. First, find s_x = |M'_1|. 
+    sx = np.sqrt(np.dot(M1, M1))
+
+    # Then, compute an initial value for the xy shear factor,
+    # s_xy = M'_1 * M'_2. (this is too large by the y scaling factor).
+    sxy = np.dot(M1, M2)
+
+    # The second row of the matrix is made orthogonal to the first by
+    # setting M'_2 = M'_2 - s_xy * M'_1.
+    M2 = M2 - sxy * M1
+
+    # Then the y scaling factor, s_y, is the length of the modified
+    # second row.
+    sy = np.sqrt(np.dot(M2, M2))
+
+    # The second row is normalized, and s_xy is divided by s_y to
+    # get its final value.
+    M2  = M2  / sy
+    sxy = sxy / sy
+
+    # The xz and yz shear factors are computed as in the preceding,
+    sxz = np.dot(M1, M3)
+    syz = np.dot(M2, M3)
+
+    # the third row is made orthogonal to the first two rows,
+    M3 = M3 - sxz * M1 - syz * M2
+
+    # the z scaling factor is computed,
+    sz = np.sqrt(np.dot(M3, M3))
+
+    # the third row is normalized, and the xz and yz shear factors are
+    # rescaled.
+    M3  = M3  / sz
+    sxz = sxz / sz
+    syz = sxz / sz
+
+    # The resulting matrix now is a pure rotation matrix, except that it 
+    # might still include a scale factor of -1. If the determinant of the
+    # matrix is -1, negate the matrix and all three scaling factors. Call
+    # the resulting matrix R.
+    #
+    # [We do things different here - if the rotation matrix has negative
+    #  determinant, the flip is encoded in the x scaling factor.]
+    R = np.array([M1, M2, M3])
+    if linalg.det(R) < 0:
+        R[0] = -R[0]
+        sx   = -sx
+
+    # Finally, we need to decompose the rotation matrix into a sequence
+    # of rotations about the x, y, and z axes. [This is done in the
+    # rotMatToAxisAngles function]
+    rx, ry, rz = rotMatToAxisAngles(R.T)
+
+    return [sx, sy, sz], translations, [rx, ry, rz]
 
 
 def rotMatToAxisAngles(rotmat):
     """Given a ``(3, 3)`` rotation matrix, decomposes the rotations into
     an angle in radians about each axis.
     """
-    xrot = np.arctan2(rotmat[2, 1], rotmat[2, 2])
-    yrot = np.sqrt(   rotmat[2, 1] ** 2 + rotmat[2, 2] ** 2)
-    yrot = np.arctan2(rotmat[2, 0], yrot)
-    zrot = np.arctan2(rotmat[1, 0], rotmat[0, 0])
+
+    yrot = np.sqrt(rotmat[0, 0] ** 2 + rotmat[1, 0] ** 2)
+
+    if np.isclose(yrot, 0):
+        xrot = np.arctan2(-rotmat[1, 2], rotmat[1, 1])
+        yrot = np.arctan2(-rotmat[2, 0], yrot)
+        zrot = 0
+    else:
+        xrot = np.arctan2( rotmat[2, 1], rotmat[2, 2])
+        yrot = np.arctan2(-rotmat[2, 0], yrot)
+        zrot = np.arctan2( rotmat[1, 0], rotmat[0, 0]) 
 
     return [xrot, yrot, zrot]