Skip to content

Commit a4cc711

Browse files
authored
Merge pull request #1911 from mmodat/adding_niftyseg
Adding niftyseg
2 parents a092cde + 3fb818f commit a4cc711

36 files changed

+2827
-16
lines changed

nipype/interfaces/niftyreg/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
Top-level namespace for niftyreg.
1010
"""
1111

12-
from .base import no_niftyreg, get_custom_path
12+
from .base import no_nifty_package, get_custom_path
1313
from .reg import RegAladin, RegF3D
1414
from .regutils import (RegResample, RegJacobian, RegAverage, RegTools,
1515
RegTransform, RegMeasure)

nipype/interfaces/niftyreg/base.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
from ...utils.filemanip import split_filename
3131

3232

33-
def get_custom_path(command):
34-
return os.path.join(os.getenv('NIFTYREGDIR', ''), command)
33+
def get_custom_path(command, env_dir='NIFTYREGDIR'):
34+
return os.path.join(os.getenv(env_dir, ''), command)
3535

3636

37-
def no_niftyreg(cmd='reg_f3d'):
37+
def no_nifty_package(cmd='reg_f3d'):
3838
try:
3939
return shutil.which(cmd) is None
4040
except AttributeError: # Python < 3.3
@@ -64,7 +64,8 @@ def __init__(self, required_version=None, **inputs):
6464
_version = self.get_version()
6565
if _version:
6666
_version = _version.decode("utf-8")
67-
if StrictVersion(_version) < StrictVersion(self._min_version):
67+
if self._min_version is not None and \
68+
StrictVersion(_version) < StrictVersion(self._min_version):
6869
msg = 'A later version of Niftyreg is required (%s < %s)'
6970
warn(msg % (_version, self._min_version))
7071
if required_version is not None:
@@ -89,7 +90,7 @@ def check_version(self):
8990
raise ValueError(err % (_version, self.required_version))
9091

9192
def get_version(self):
92-
if no_niftyreg(cmd=self.cmd):
93+
if no_nifty_package(cmd=self.cmd):
9394
return None
9495
exec_cmd = ''.join((self.cmd, ' -v'))
9596
return subprocess.check_output(exec_cmd, shell=True).strip()

nipype/interfaces/niftyreg/tests/test_reg.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
import pytest
66

7-
from nipype.interfaces.niftyreg import (no_niftyreg, get_custom_path,
7+
from nipype.interfaces.niftyreg import (no_nifty_package, get_custom_path,
88
RegAladin, RegF3D)
99
from nipype.testing import example_data
1010

1111

1212
@pytest.mark.skipif(
13-
no_niftyreg(cmd='reg_aladin'),
13+
no_nifty_package(cmd='reg_aladin'),
1414
reason="niftyreg is not installed. reg_aladin not found.")
1515
def test_reg_aladin():
1616
""" tests for reg_aladin interface"""
@@ -48,7 +48,7 @@ def test_reg_aladin():
4848

4949

5050
@pytest.mark.skipif(
51-
no_niftyreg(cmd='reg_f3d'),
51+
no_nifty_package(cmd='reg_f3d'),
5252
reason="niftyreg is not installed. reg_f3d not found.")
5353
def test_reg_f3d():
5454
""" tests for reg_f3d interface"""

nipype/interfaces/niftyreg/tests/test_regutils.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
33
# vi: set ft=python sts=4 ts=4 sw=4 et:
44

5-
from nipype.interfaces.niftyreg import (no_niftyreg, get_custom_path,
5+
from nipype.interfaces.niftyreg import (no_nifty_package, get_custom_path,
66
RegAverage, RegResample, RegJacobian,
77
RegTools, RegMeasure, RegTransform)
88
from nipype.testing import example_data
@@ -11,7 +11,7 @@
1111

1212

1313
@pytest.mark.skipif(
14-
no_niftyreg(cmd='reg_resample'),
14+
no_nifty_package(cmd='reg_resample'),
1515
reason="niftyreg is not installed. reg_resample not found.")
1616
def test_reg_resample_res():
1717
""" tests for reg_resample interface """
@@ -68,7 +68,7 @@ def test_reg_resample_res():
6868

6969

7070
@pytest.mark.skipif(
71-
no_niftyreg(cmd='reg_jacobian'),
71+
no_nifty_package(cmd='reg_jacobian'),
7272
reason="niftyreg is not installed. reg_jacobian not found.")
7373
def test_reg_jacobian_jac():
7474
""" Test interface for RegJacobian """
@@ -132,7 +132,7 @@ def test_reg_jacobian_jac():
132132

133133

134134
@pytest.mark.skipif(
135-
no_niftyreg(cmd='reg_tools'),
135+
no_nifty_package(cmd='reg_tools'),
136136
reason="niftyreg is not installed. reg_tools not found.")
137137
def test_reg_tools_mul():
138138
""" tests for reg_tools interface """
@@ -175,7 +175,7 @@ def test_reg_tools_mul():
175175

176176

177177
@pytest.mark.skipif(
178-
no_niftyreg(cmd='reg_average'),
178+
no_nifty_package(cmd='reg_average'),
179179
reason="niftyreg is not installed. reg_average not found.")
180180
def test_reg_average():
181181
""" tests for reg_average interface """
@@ -318,7 +318,7 @@ def test_reg_average():
318318

319319

320320
@pytest.mark.skipif(
321-
no_niftyreg(cmd='reg_transform'),
321+
no_nifty_package(cmd='reg_transform'),
322322
reason="niftyreg is not installed. reg_transform not found.")
323323
def test_reg_transform_def():
324324
""" tests for reg_transform interface """
@@ -427,7 +427,7 @@ def test_reg_transform_def():
427427

428428

429429
@pytest.mark.skipif(
430-
no_niftyreg(cmd='reg_measure'),
430+
no_nifty_package(cmd='reg_measure'),
431431
reason="niftyreg is not installed. reg_measure not found.")
432432
def test_reg_measure():
433433
""" tests for reg_measure interface """
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
4+
"""
5+
The niftyseg module provides classes for interfacing with the `NIFTYSEG
6+
<https://sourceforge.net/projects/niftyseg/>`_ command line tools.
7+
8+
Top-level namespace for niftyseg.
9+
"""
10+
11+
from .em import EM
12+
from .label_fusion import LabelFusion, CalcTopNCC
13+
from .lesions import FillLesions
14+
from .maths import (UnaryMaths, BinaryMaths, BinaryMathsInteger, TupleMaths,
15+
Merge)
16+
from .patchmatch import PatchMatch
17+
from .stats import UnaryStats, BinaryStats

nipype/interfaces/niftyseg/base.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
4+
"""
5+
The niftyseg module provides classes for interfacing with `niftyseg
6+
<https://sourceforge.net/projects/niftyseg/>`_ command line tools.
7+
These are the base tools for working with niftyseg.
8+
EM Statistical Segmentation tool is found in niftyseg/em.py
9+
Fill lesions tool is found in niftyseg/lesions.py
10+
Mathematical operation tool is found in niftyseg/maths.py
11+
Patch Match tool is found in niftyseg/patchmatch.py
12+
Statistical operation tool is found in niftyseg/stats.py
13+
Label Fusion and CalcTopNcc tools are in niftyseg/steps.py
14+
Examples
15+
--------
16+
See the docstrings of the individual classes for examples.
17+
"""
18+
19+
from nipype.interfaces.niftyreg.base import NiftyRegCommand, no_nifty_package
20+
import subprocess
21+
import warnings
22+
23+
24+
warn = warnings.warn
25+
warnings.filterwarnings('always', category=UserWarning)
26+
27+
28+
class NiftySegCommand(NiftyRegCommand):
29+
"""
30+
Base support interface for NiftySeg commands.
31+
"""
32+
_suffix = '_ns'
33+
_min_version = None
34+
35+
def __init__(self, **inputs):
36+
super(NiftySegCommand, self).__init__(**inputs)
37+
38+
def get_version(self):
39+
if no_nifty_package(cmd=self.cmd):
40+
return None
41+
# exec_cmd = ''.join((self.cmd, ' --version'))
42+
exec_cmd = 'seg_EM --version'
43+
# Using seg_EM for version (E.G: seg_stats --version doesn't work)
44+
return subprocess.check_output(exec_cmd, shell=True).strip('\n')

nipype/interfaces/niftyseg/em.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
4+
"""
5+
Nipype interface for seg_EM.
6+
7+
The em module provides higher-level interfaces to some of the operations
8+
that can be performed with the seg_em command-line program.
9+
10+
Examples
11+
--------
12+
See the docstrings of the individual classes for examples.
13+
14+
Change directory to provide relative paths for doctests
15+
>>> import os
16+
>>> filepath = os.path.dirname( os.path.realpath( __file__ ) )
17+
>>> datadir = os.path.realpath(os.path.join(filepath, '../../testing/data'))
18+
>>> os.chdir(datadir)
19+
"""
20+
21+
from ..base import (TraitedSpec, File, traits, CommandLineInputSpec,
22+
InputMultiPath)
23+
from .base import NiftySegCommand
24+
from ..niftyreg.base import get_custom_path
25+
26+
27+
class EMInputSpec(CommandLineInputSpec):
28+
"""Input Spec for EM."""
29+
in_file = File(argstr='-in %s',
30+
exists=True,
31+
mandatory=True,
32+
desc='Input image to segment',
33+
position=4)
34+
35+
mask_file = File(argstr='-mask %s',
36+
exists=True,
37+
desc='Filename of the ROI for label fusion')
38+
39+
# Priors
40+
no_prior = traits.Int(argstr='-nopriors %s',
41+
mandatory=True,
42+
desc='Number of classes to use without prior',
43+
xor=['prior_4D', 'priors'])
44+
45+
prior_4D = File(argstr='-prior4D %s',
46+
exists=True,
47+
mandatory=True,
48+
desc='4D file containing the priors',
49+
xor=['no_prior', 'priors'])
50+
51+
priors = InputMultiPath(argstr='%s',
52+
mandatory=True,
53+
desc='List of priors filepaths.',
54+
xor=['no_prior', 'prior_4D'])
55+
56+
# iterations
57+
max_iter = traits.Int(argstr='-max_iter %s', default=100,
58+
desc='Maximum number of iterations')
59+
60+
min_iter = traits.Int(argstr='-min_iter %s', default=0,
61+
desc='Minimun number of iterations')
62+
63+
# other options
64+
bc_order_val = traits.Int(argstr='-bc_order %s', default=3,
65+
desc='Polynomial order for the bias field')
66+
67+
mrf_beta_val = traits.Float(argstr='-mrf_beta %s',
68+
desc='Weight of the Markov Random Field')
69+
70+
desc = 'Bias field correction will run only if the ratio of improvement \
71+
is below bc_thresh. (default=0 [OFF])'
72+
bc_thresh_val = traits.Float(argstr='-bc_thresh %s', default=0, desc=desc)
73+
74+
desc = 'Amount of regularization over the diagonal of the covariance \
75+
matrix [above 1]'
76+
reg_val = traits.Float(argstr='-reg %s', desc=desc)
77+
78+
desc = 'Outlier detection as in (Van Leemput TMI 2003). <fl1> is the \
79+
Mahalanobis threshold [recommended between 3 and 7] <fl2> is a convergence \
80+
ratio below which the outlier detection is going to be done [recommended 0.01]'
81+
outlier_val = traits.Tuple(traits.Float(), traits.Float(),
82+
argstr='-outlier %s %s',
83+
desc=desc)
84+
85+
desc = 'Relax Priors [relaxation factor: 0<rf<1 (recommended=0.5), \
86+
gaussian regularization: gstd>0 (recommended=2.0)] /only 3D/'
87+
relax_priors = traits.Tuple(traits.Float(), traits.Float(),
88+
argstr='-rf %s %s',
89+
desc=desc)
90+
91+
# outputs
92+
out_file = File(name_source=['in_file'],
93+
name_template='%s_em.nii.gz',
94+
argstr='-out %s',
95+
desc='Output segmentation')
96+
out_bc_file = File(name_source=['in_file'],
97+
name_template='%s_bc_em.nii.gz',
98+
argstr='-bc_out %s',
99+
desc='Output bias corrected image')
100+
out_outlier_file = File(name_source=['in_file'],
101+
name_template='%s_outlier_em.nii.gz',
102+
argstr='-out_outlier %s',
103+
desc='Output outlierness image')
104+
105+
106+
class EMOutputSpec(TraitedSpec):
107+
"""Output Spec for EM."""
108+
out_file = File(desc="Output segmentation")
109+
out_bc_file = File(desc="Output bias corrected image")
110+
out_outlier_file = File(desc='Output outlierness image')
111+
112+
113+
class EM(NiftySegCommand):
114+
"""Interface for executable seg_EM from NiftySeg platform.
115+
116+
seg_EM is a general purpose intensity based image segmentation tool. In
117+
it's simplest form, it takes in one 2D or 3D image and segments it in n
118+
classes.
119+
120+
For source code, see http://cmictig.cs.ucl.ac.uk/wiki/index.php/NiftySeg
121+
For Documentation, see:
122+
http://cmictig.cs.ucl.ac.uk/wiki/index.php/NiftySeg_documentation
123+
124+
Examples
125+
--------
126+
>>> from nipype.interfaces import niftyseg
127+
>>> node = niftyseg.EM()
128+
>>> node.inputs.in_file = 'im1.nii'
129+
>>> node.inputs.no_prior = 4
130+
>>> node.cmdline # doctest: +ALLOW_UNICODE
131+
'seg_EM -in im1.nii -nopriors 4 -bc_out im1_bc_em.nii.gz \
132+
-out im1_em.nii.gz -out_outlier im1_outlier_em.nii.gz'
133+
134+
"""
135+
_cmd = get_custom_path('seg_EM', env_dir='NIFTYSEGDIR')
136+
_suffix = '_em'
137+
input_spec = EMInputSpec
138+
output_spec = EMOutputSpec
139+
140+
def _format_arg(self, opt, spec, val):
141+
"""Convert input to appropriate format for seg_EM."""
142+
if opt == 'priors':
143+
_nb_priors = len(self.inputs.priors)
144+
return '-priors %d %s' % (_nb_priors, ' '.join(self.inputs.priors))
145+
else:
146+
return super(EM, self)._format_arg(opt, spec, val)

0 commit comments

Comments
 (0)