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

Merge branch 'enh/nifti-adjust' into 'master'

Enh/nifti adjust

See merge request fsl/fslpy!183
parents 9ea752cb 5f31b9e5
No related branches found
No related tags found
No related merge requests found
Pipeline #4799 failed
...@@ -22,6 +22,8 @@ Fixed ...@@ -22,6 +22,8 @@ Fixed
* Improved the algorithm used by the :func:`.mesh.needsFixing` function. * Improved the algorithm used by the :func:`.mesh.needsFixing` function.
* The :meth:`.fslmaths.run` method now accepts :attr:`.wrappers.LOAD` as an
output specification.
Deprecated Deprecated
......
...@@ -63,11 +63,11 @@ if we want to FLIRT two images and get the result, we can do this:: ...@@ -63,11 +63,11 @@ if we want to FLIRT two images and get the result, we can do this::
Similarly, we can run a ``fslmaths`` command on in-memory images:: Similarly, we can run a ``fslmaths`` command on in-memory images::
import nibabel as nib import nibabel as nib
from fsl.wrappers import fslmaths, LOAD from fsl.wrappers import fslmaths
image = nib.load('image.nii') image = nib.load('image.nii')
mask = nib.load('mask.nii') mask = nib.load('mask.nii')
output = fslmaths(image).mas(mask).bin().run(LOAD) output = fslmaths(image).mas(mask).bin().run()
If you are *writing* wrapper functions, take a look at the If you are *writing* wrapper functions, take a look at the
......
...@@ -13,7 +13,28 @@ from . import wrapperutils as wutils ...@@ -13,7 +13,28 @@ from . import wrapperutils as wutils
class fslmaths(object): class fslmaths(object):
"""Perform mathematical manipulation of images.""" """Perform mathematical manipulation of images.
``fslmaths`` is unlike the other FSL wrapper tools in that it provides an
object-oriented method-chaining interface, which is hopefully easier to
use than constructing a ``fslmaths`` command-line call. For example, the
following call to the ``fslmaths`` wrapper function::
fslmaths('input.nii').thr(0.25).mul(-1).run('output.nii')
will be translated into the following command-line call::
fslmaths input.nii -thr 0.25 -mul -1 output.nii
The ``fslmaths`` wrapper function can also be used with in-memory
images. If no output file name is passed to the :meth:`run` method, the
result is loaded into memory and returned as a ``nibabel`` image. For
example::
import nibabel as nib
input = nib.load('input.nii')
output = fslmaths(input).thr(0.25).mul(-1).run()
"""
def __init__(self, input): def __init__(self, input):
"""Constructor.""" """Constructor."""
...@@ -138,20 +159,24 @@ class fslmaths(object): ...@@ -138,20 +159,24 @@ class fslmaths(object):
return self return self
def run(self, output=None): def run(self, output=None):
"""Save output of operations to image.""" """Save output of operations to image. Set ``output`` to a filename to have
the result saved to file, or omit ``output`` entirely to have the
result returned as a ``nibabel`` image.
"""
cmd = ['fslmaths', self.__input] + self.__args cmd = ['fslmaths', self.__input] + self.__args
if output is None: cmd += [wutils.LOAD] if output is None:
else: cmd += [output] output = wutils.LOAD
cmd += [output]
result = self.__run(*cmd) result = self.__run(*cmd)
# if output is LOADed, there # if output is LOADed, there
# will only be one entry in # will only be one entry in
# the result dict. # the result dict.
if output is None: return list(result.values())[0] if output == wutils.LOAD: return list(result.values())[0]
else: return result else: return result
@wutils.fileOrImage() @wutils.fileOrImage()
@wutils.fslwrapper @wutils.fslwrapper
......
...@@ -50,7 +50,10 @@ def mockFSLDIR(**kwargs): ...@@ -50,7 +50,10 @@ def mockFSLDIR(**kwargs):
if not op.isdir(subdir): if not op.isdir(subdir):
os.makedirs(subdir) os.makedirs(subdir)
for fname in files: for fname in files:
touch(op.join(subdir, fname)) fname = op.join(subdir, fname)
touch(fname)
if subdir == bindir:
os.chmod(fname, 0o755)
fslplatform.fsldir = fsldir fslplatform.fsldir = fsldir
fslplatform.fsldevdir = None fslplatform.fsldevdir = None
......
...@@ -5,14 +5,19 @@ ...@@ -5,14 +5,19 @@
# Author: Paul McCarthy <pauldmccarthy@gmail.com> # Author: Paul McCarthy <pauldmccarthy@gmail.com>
# #
import os
import os.path as op import os.path as op
import itertools as it import itertools as it
import textwrap as tw
import numpy as np
import fsl.wrappers as fw import fsl.wrappers as fw
import fsl.utils.assertions as asrt import fsl.utils.assertions as asrt
import fsl.utils.run as run import fsl.utils.run as run
from fsl.utils.tempdir import tempdir
from . import mockFSLDIR from . import mockFSLDIR, make_random_image
def checkResult(cmd, base, args, stripdir=None): def checkResult(cmd, base, args, stripdir=None):
...@@ -272,7 +277,23 @@ def test_fslmaths(): ...@@ -272,7 +277,23 @@ def test_fslmaths():
assert result.output[0] == expected assert result.output[0] == expected
# TODO test LOAD output # test LOAD output
with tempdir() as td, mockFSLDIR(bin=('fslmaths',)) as fsldir:
expect = make_random_image(op.join(td, 'output.nii.gz'))
with open(op.join(fsldir, 'bin', 'fslmaths'), 'wt') as f:
f.write(tw.dedent("""
#!/usr/bin/env python
import sys
import shutil
shutil.copy('{}', sys.argv[2])
""".format(op.join(td, 'output.nii.gz'))).strip())
os.chmod(op.join(fsldir, 'bin', 'fslmaths'), 0o755)
got = fw.fslmaths('input').run()
assert np.all(expect.dataobj[:] == got.dataobj[:])
got = fw.fslmaths('input').run(fw.LOAD)
assert np.all(expect.dataobj[:] == got.dataobj[:])
def test_fast(): def test_fast():
with asrt.disabled(), run.dryrun(), mockFSLDIR(bin=('fast',)) as fsldir: with asrt.disabled(), run.dryrun(), mockFSLDIR(bin=('fast',)) as fsldir:
......
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