Skip to content
Snippets Groups Projects
Commit 1da36b03 authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

Merge branch 'rf/compressed_voxelwise_evs' into 'master'

Rf/compressed voxelwise evs

See merge request fsl/fslpy!115
parents e8f0a5ad 06cd6916
No related branches found
No related tags found
No related merge requests found
Pipeline #3571 passed
......@@ -2,6 +2,27 @@ This document contains the ``fslpy`` release history in reverse chronological
order.
2.1.0 (Under development)
-------------------------
Added
^^^^^
* New tensor conversion routines in the :mod:`.dtifit` module (Michiel
Cottaar).
Fixed
^^^^^
* The :class:`.FeatDesign` class now handles "compressed" voxelwise EV files,
such as those generated by `PNM
<https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/PNM>`_.
2.0.1 (Monday April 1st 2019)
-----------------------------
......
......@@ -3,6 +3,7 @@
# dtifit.py - The DTIFitTensor class, and some related utility functions.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
# Author: Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk>
#
"""This module provides the :class:`.DTIFitTensor` class, which encapsulates
the diffusion tensor data generated by the FSL ``dtifit`` tool.
......
......@@ -214,7 +214,7 @@ class FEATFSFDesign(object):
'for ev {}'.format(ev.index))
continue
design[:, ev.index] = ev.image[x, y, z, :]
design[:, ev.index] = ev.getData(x, y, z)
return design
......@@ -228,6 +228,17 @@ class VoxelwiseEVMixin(object):
``filename`` Path to the image file containing the data for this EV
``image`` Reference to the :class:`.Image` object
============ ======================================================
Some FSL tools (e.g. `PNM
<https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/PNM>`_) generate *compressed*
voxelwise EVs, where there is only one voxel per slice. For example,
if the input data has shape ``(x, y, z, t)``, and slices are acquired
along the Z plane, voxelwise EV files generated by PNM will have shape
``(1, 1, z, t)``.
Therefore, using the :meth:`getData` method is preferable to accessing
the :meth:`image` directly, as ``getData`` will check for compressed
images, and adjust the voxel coordinates accordingly.
"""
def __init__(self, filename):
......@@ -272,6 +283,29 @@ class VoxelwiseEVMixin(object):
return self.__image
def getData(self, x, y, z):
"""Returns the data at the specified voxel, taking into account
compressed voxelwise EVs.
"""
image = self.image
if image is None:
return None
dx, dy, dz = image.shape[:3]
# "Compressed" images have one voxel
# per slice, i.e. they have shape
# [1, 1, nslices, ntimepoints] (if
# Z is the slice plane).
if sum((dx == 1, dy == 1, dz == 1)) == 2:
if dx == 1: x = 0
if dy == 1: y = 0
if dz == 1: z = 0
return image[x, y, z, :]
class EV(object):
"""Class representing an explanatory variable in a FEAT design matrix.
......
......@@ -412,3 +412,19 @@ def test_VoxelwiseEVs():
exp = img.dataobj[x, y, z, :]
assert np.all(ev1.image[x, y, z, :] == exp)
assert np.all(ev2.image[x, y, z, :] == exp)
def test_compressed_voxelwise_ev():
testcases = [((1, 1, 10, 10), (0, 0, 5)),
((1, 10, 1, 10), (0, 5, 0)),
((10, 1, 1, 10), (5, 0, 0))]
with tempdir():
for shape, vox in testcases:
img = tests.make_random_image('vev.nii.gz', shape)
vev = featdesign.VoxelwiseEV(0, 0, 'ev1', 'vev.nii.gz')
x, y, z = vox
assert np.all(vev.getData(5, 5, 5) == img.dataobj[x, y, z, :])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment