Skip to content

Commit 269987d

Browse files
committed
Inital commit to add niftyseg
1 parent d387481 commit 269987d

32 files changed

+2800
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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 .base import no_niftyseg, get_custom_path
12+
from .em import EM
13+
from .label_fusion import LabelFusion, CalcTopNCC
14+
from .lesions import FillLesions
15+
from .maths import (UnaryMaths, BinaryMaths, BinaryMathsInteger, TupleMaths,
16+
Merge)
17+
from .patchmatch import PatchMatch
18+
from .stats import UnaryStats, BinaryStats

nipype/interfaces/niftyseg/base.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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+
8+
These are the base tools for working with niftyseg.
9+
10+
EM Statistical Segmentation tool is found in niftyseg/em.py
11+
Fill lesions tool is found in niftyseg/lesions.py
12+
Mathematical operation tool is found in niftyseg/maths.py
13+
Patch Match tool is found in niftyseg/patchmatch.py
14+
Statistical operation tool is found in niftyseg/stats.py
15+
Label Fusion and CalcTopNcc tools are in niftyseg/steps.py
16+
17+
Examples
18+
--------
19+
See the docstrings of the individual classes for examples.
20+
21+
"""
22+
23+
from nipype.interfaces.base import CommandLine, isdefined
24+
from nipype.utils.filemanip import split_filename
25+
import os
26+
import subprocess
27+
import warnings
28+
29+
30+
warn = warnings.warn
31+
warnings.filterwarnings('always', category=UserWarning)
32+
33+
34+
def get_custom_path(command):
35+
"""Get path of niftyseg."""
36+
try:
37+
specific_dir = os.environ['NIFTYSEGDIR']
38+
command = os.path.join(specific_dir, command)
39+
return command
40+
except KeyError:
41+
return command
42+
43+
44+
def no_niftyseg(cmd='seg_LabFusion'):
45+
"""Check if niftyseg is installed."""
46+
if True in [os.path.isfile(os.path.join(path, cmd)) and
47+
os.access(os.path.join(path, cmd), os.X_OK)
48+
for path in os.environ["PATH"].split(os.pathsep)]:
49+
return False
50+
return True
51+
52+
53+
class NiftySegCommand(CommandLine):
54+
"""
55+
Base support interface for NiftySeg commands.
56+
"""
57+
_suffix = '_ns'
58+
59+
def __init__(self, **inputs):
60+
super(NiftySegCommand, self).__init__(**inputs)
61+
62+
def get_version(self):
63+
if no_niftyseg(cmd=self.cmd):
64+
return None
65+
# exec_cmd = ''.join((self.cmd, ' --version'))
66+
exec_cmd = 'seg_EM --version'
67+
# Using seg_EM for version (E.G: seg_stats --version doesn't work)
68+
return subprocess.check_output(exec_cmd, shell=True).strip('\n')
69+
70+
@property
71+
def version(self):
72+
return self.get_version()
73+
74+
def exists(self):
75+
if self.get_version() is None:
76+
return False
77+
return True
78+
79+
def _gen_fname(self, basename, out_dir=None, suffix=None, ext=None):
80+
if basename == '':
81+
msg = 'Unable to generate filename for command %s. ' % self.cmd
82+
msg += 'basename is not set!'
83+
raise ValueError(msg)
84+
_, final_bn, final_ext = split_filename(basename)
85+
if out_dir is None:
86+
out_dir = os.getcwd()
87+
if ext is not None:
88+
final_ext = ext
89+
if suffix is not None:
90+
final_bn = ''.join((final_bn, suffix))
91+
return os.path.abspath(os.path.join(out_dir, final_bn + final_ext))
92+
93+
def _gen_filename(self, name):
94+
if name == 'out_file':
95+
return self._gen_fname(self.inputs.in_file, suffix=self._suffix)
96+
return None
97+
98+
def _list_outputs(self):
99+
outputs = self.output_spec().get()
100+
if isdefined(self.inputs.out_file):
101+
outputs['out_file'] = self.inputs.out_file
102+
else:
103+
outputs['out_file'] = self._gen_filename('out_file')
104+
return outputs

nipype/interfaces/niftyseg/em.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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+
15+
import os
16+
17+
from ..base import (TraitedSpec, File, traits, isdefined, CommandLineInputSpec,
18+
InputMultiPath)
19+
from .base import NiftySegCommand, get_custom_path
20+
21+
22+
class EMInputSpec(CommandLineInputSpec):
23+
"""Input Spec for EM."""
24+
in_file = File(argstr='-in %s',
25+
exists=True,
26+
mandatory=True,
27+
desc='Input image to segment',
28+
position=4)
29+
30+
mask_file = File(argstr='-mask %s',
31+
exists=True,
32+
desc='Filename of the ROI for label fusion')
33+
34+
# Priors
35+
no_prior = traits.Int(argstr='-nopriors %s',
36+
mandatory=True,
37+
desc='Number of classes to use without prior',
38+
xor=['prior_4D', 'priors'])
39+
40+
prior_4D = File(argstr='-prior4D %s',
41+
exists=True,
42+
mandatory=True,
43+
desc='4D file containing the priors',
44+
xor=['no_prior', 'priors'])
45+
46+
desc = 'List of priors filepaths.'
47+
priors = InputMultiPath(argstr='%s',
48+
mandatory=True,
49+
desc=desc,
50+
xor=['no_prior', 'prior_4D'])
51+
52+
# iterations
53+
max_iter = traits.Int(argstr='-max_iter %s', default=100,
54+
desc='Maximum number of iterations')
55+
56+
min_iter = traits.Int(argstr='-min_iter %s', default=0,
57+
desc='Minimun number of iterations')
58+
59+
# other options
60+
bc_order_val = traits.Int(argstr='-bc_order %s', default=3,
61+
desc='Polynomial order for the bias field')
62+
63+
mrf_beta_val = traits.Float(argstr='-mrf_beta %s',
64+
desc='Weight of the Markov Random Field')
65+
66+
desc = 'Bias field correction will run only if the ratio of improvement \
67+
is below bc_thresh. (default=0 [OFF])'
68+
bc_thresh_val = traits.Float(argstr='-bc_thresh %s', default=0, desc=desc)
69+
70+
desc = 'Amount of regularization over the diagonal of the covariance \
71+
matrix [above 1]'
72+
reg_val = traits.Float(argstr='-reg %s', desc=desc)
73+
74+
desc = 'Outlier detection as in (Van Leemput TMI 2003). <fl1> is the \
75+
Mahalanobis threshold [recommended between 3 and 7] <fl2> is a convergence \
76+
ratio below which the outlier detection is going to be done [recommended 0.01]'
77+
outlier_val = traits.Tuple(traits.Float(), traits.Float(),
78+
argstr='-outlier %s %s',
79+
desc=desc)
80+
81+
desc = 'Relax Priors [relaxation factor: 0<rf<1 (recommended=0.5), \
82+
gaussian regularization: gstd>0 (recommended=2.0)] /only 3D/'
83+
relax_priors = traits.Tuple(traits.Float(), traits.Float(),
84+
argstr='-rf %s %s',
85+
desc=desc)
86+
87+
# outputs
88+
out_file = File(argstr='-out %s',
89+
genfile=True,
90+
desc='Output segmentation')
91+
out_bc_file = File(argstr='-bc_out %s',
92+
genfile=True,
93+
desc='Output bias corrected image')
94+
out_outlier_file = File(argstr='-out_outlier %s',
95+
genfile=True,
96+
desc='Output outlierness image')
97+
98+
99+
class EMOutputSpec(TraitedSpec):
100+
"""Output Spec for EM."""
101+
out_file = File(desc="Output segmentation")
102+
out_bc_file = File(desc="Output bias corrected image")
103+
out_outlier_file = File(desc='Output outlierness image')
104+
105+
106+
class EM(NiftySegCommand):
107+
"""Interface for executable seg_EM from NiftySeg platform.
108+
109+
seg_EM is a general purpose intensity based image segmentation tool. In
110+
it's simplest form, it takes in one 2D or 3D image and segments it in n
111+
classes.
112+
113+
For source code, see http://cmictig.cs.ucl.ac.uk/wiki/index.php/NiftySeg
114+
For Documentation, see:
115+
http://cmictig.cs.ucl.ac.uk/wiki/index.php/NiftySeg_documentation
116+
117+
Examples
118+
--------
119+
>>> from nipype.interfaces.niftyseg import EM
120+
>>> node = EM()
121+
>>> node.inputs.in_file = 'im1.nii' # doctest: +SKIP
122+
>>> node.inputs.no_prior = 4
123+
>>> node.cmdline # doctest: +SKIP
124+
'seg_EM -in im1.nii -nopriors 4 -bc_out im1_bc_em.nii -out im1_em.nii \
125+
-out_outlier im1_outlier_em.nii'
126+
127+
"""
128+
_cmd = get_custom_path('seg_EM')
129+
_suffix = '_em'
130+
input_spec = EMInputSpec
131+
output_spec = EMOutputSpec
132+
133+
def _format_arg(self, opt, spec, val):
134+
"""Convert input to appropriate format for seg_EM."""
135+
if opt == 'priors':
136+
_nb_priors = len(self.inputs.priors)
137+
return '-priors %d %s' % (_nb_priors, ' '.join(self.inputs.priors))
138+
else:
139+
return super(EM, self)._format_arg(opt, spec, val)
140+
141+
def _list_outputs(self):
142+
outputs = self.output_spec().get()
143+
outputs['out_file'] = self.inputs.out_file
144+
if not isdefined(self.inputs.out_file):
145+
outputs['out_file'] = self._gen_fname(self.inputs.in_file,
146+
suffix=self._suffix)
147+
outputs['out_file'] = os.path.abspath(outputs['out_file'])
148+
outputs['out_bc_file'] = self.inputs.out_bc_file
149+
if not isdefined(self.inputs.out_bc_file):
150+
outputs['out_bc_file'] = self._gen_fname(
151+
self.inputs.in_file, suffix=('_bc%s' % self._suffix))
152+
outputs['out_bc_file'] = os.path.abspath(outputs['out_bc_file'])
153+
outputs['out_outlier_file'] = self.inputs.out_outlier_file
154+
if not isdefined(self.inputs.out_outlier_file):
155+
outputs['out_outlier_file'] = self._gen_fname(
156+
self.inputs.in_file, suffix=('_outlier%s' % self._suffix))
157+
outputs['out_outlier_file'] = os.path.abspath(
158+
outputs['out_outlier_file'])
159+
return outputs
160+
161+
def _gen_filename(self, name):
162+
if name == 'out_file':
163+
return self._list_outputs()['out_file']
164+
if name == 'out_bc_file':
165+
return self._list_outputs()['out_bc_file']
166+
if name == 'out_outlier_file':
167+
return self._list_outputs()['out_outlier_file']
168+
return None

0 commit comments

Comments
 (0)