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

RF: fslstats returns a numpy array instead of lists

parent c383e2d3
No related branches found
No related tags found
No related merge requests found
...@@ -12,8 +12,9 @@ for the ``fslstats`` command-line tool. ...@@ -12,8 +12,9 @@ for the ``fslstats`` command-line tool.
""" """
import six import io
import functools as ft import functools as ft
import numpy as np
import fsl.data.image as fslimage import fsl.data.image as fslimage
from . import wrapperutils as wutils from . import wrapperutils as wutils
...@@ -122,23 +123,18 @@ class fslstats(object): ...@@ -122,23 +123,18 @@ class fslstats(object):
fslstats('image_4d.nii.gz', K='mask.nii.gz') fslstats('image_4d.nii.gz', K='mask.nii.gz')
then the value returned by :meth:`run` will contain a list-of-lists, then :meth:`run` will return a 2D ``numpy`` array of shape ``(nvols,
with each child list containing the results: nvals)`` if ``t`` is set, or ``(nlabels, nvals)`` if ``K`` is set.
- for each 3D volume contained within the input image (if ``t``
is set), or
- for each sub-mask contained within the mask image (if ``K``
is set)
If both of the ``t`` and ``K`` pre-options are set, e.g.:: If both of the ``t`` and ``K`` pre-options are set, e.g.::
fslstats('image_4d.nii.gz', t=True, K='mask.nii.gz') fslstats('image_4d.nii.gz', t=True, K='mask.nii.gz')
then the result will be a list-of-lists-of-lists, where each child then the result will be a 3D numpy array of shape ``(nvols, nlabels,
list corresponds to each 3D volume (``t``), and each grand-child list nvals)``.
corresponds to each sub-mask (``K``).
If neither ``t`` or ``K`` are set, then the result will be a scalar,
or a 1D ``numpy`` array.
:arg input: Input image - either a file name, or an :arg input: Input image - either a file name, or an
:class:`.Image` object, or a ``nibabel.Nifti1Image`` :class:`.Image` object, or a ``nibabel.Nifti1Image``
...@@ -166,7 +162,8 @@ class fslstats(object): ...@@ -166,7 +162,8 @@ class fslstats(object):
def __getattr__(self, name): def __getattr__(self, name):
"""Intercepts attribute accesses,... """Intercepts attribute accesses and stages ``fslstats`` command-line
flags accordingly.
""" """
# options which take no args # options which take no args
...@@ -198,53 +195,48 @@ class fslstats(object): ...@@ -198,53 +195,48 @@ class fslstats(object):
def run(self): def run(self):
"""Run the ``fslstats`` command-line tool. The results are returned as """Run the ``fslstats`` command-line tool. See :meth:`__init__` for a
floating point numbers. description of the return value.
"""
result = self.__run('fslstats', *self.__options, log=None) :returns: Result of ``fslstats`` as a scalar or ``numpy`` array.
result = result.stdout[0].strip() """
result = [line.split() for line in result.split('\n')]
# The parsing logic below will not work
# with versions of fslstats prior to fsl
# 6.0.2, due to a quirk in the output
# formatting of older versions.
# The default behaviour of run/runfsl
# is to tee the command output streams
# to the calling process streams. We
# can disable this via log=None.
result = self.__run('fslstats', *self.__options, log=None)
result = np.genfromtxt(io.StringIO(result.stdout[0].strip()))
sepvols = '-t' in self.__options sepvols = '-t' in self.__options
lblmask = '-K' in self.__options lblmask = '-K' in self.__options
# This parsing logic will not work with
# versions of fslstats prior to fsl 6.0.2,
# due to a quirk in the output formatting
# of older versions.
# One line of output for each volume and # One line of output for each volume and
# for each label (with volume the slowest # for each label (with volume the slowest
# changing). # changing). Reshape to 3D.
if sepvols and lblmask: if sepvols and lblmask:
# One line of output for
# each volume and label
result = [[float(v) for v in line] for line in result]
# We need know the number of volumes # We need know the number of volumes
# (or the number of labels) in order # (or the number of labels) in order
# to know how to nest the results. # to know how to shape the results.
img = fslimage.Image(self.__input, loadData=False) img = fslimage.Image(self.__input, loadData=False)
if img.ndim >= 4: nvols = img.shape[3] if img.ndim >= 4: nvols = img.shape[3]
else: nvols = 1 else: nvols = 1
# split the result up into # reshape the result into
# nlbls lines for each volume # (nvals, nvols, nlbls)
nlbls = len(result) / nvols nlbls = int(len(result) / nvols)
offsets = range(0, nvols * nlbls, nlbls) result = result.reshape((nvols, nlbls, -1))
result = [result[off:off + nlbls] for off in offsets]
# One line of output # Scalar - use numpy indexing weirdness
# for each volume/label # to get our single value out.
elif sepvols or lblmask: elif result.size == 1:
result = [[float(v) for v in line] for line in result] result = result[()]
# One line of output
else:
result = [float(v) for v in result[0]]
return result return result
......
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