-
Notifications
You must be signed in to change notification settings - Fork 536
Adding niftyseg #1911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding niftyseg #1911
Changes from 13 commits
269987d
013bf72
f431e0c
c7e43ea
135da56
b9610cb
55e555e
ee44a57
3ab6250
84adfcd
23dccd8
be7c489
ef14ef5
c40b673
3389a28
cf30734
617eb48
3fb818f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- | ||
# vi: set ft=python sts=4 ts=4 sw=4 et: | ||
|
||
""" | ||
The niftyseg module provides classes for interfacing with the `NIFTYSEG | ||
<https://sourceforge.net/projects/niftyseg/>`_ command line tools. | ||
|
||
Top-level namespace for niftyseg. | ||
""" | ||
|
||
from .base import no_niftyseg, get_custom_path | ||
from .em import EM | ||
from .label_fusion import LabelFusion, CalcTopNCC | ||
from .lesions import FillLesions | ||
from .maths import (UnaryMaths, BinaryMaths, BinaryMathsInteger, TupleMaths, | ||
Merge) | ||
from .patchmatch import PatchMatch | ||
from .stats import UnaryStats, BinaryStats |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- | ||
# vi: set ft=python sts=4 ts=4 sw=4 et: | ||
|
||
""" | ||
The niftyseg module provides classes for interfacing with `niftyseg | ||
<https://sourceforge.net/projects/niftyseg/>`_ command line tools. | ||
|
||
These are the base tools for working with niftyseg. | ||
|
||
EM Statistical Segmentation tool is found in niftyseg/em.py | ||
Fill lesions tool is found in niftyseg/lesions.py | ||
Mathematical operation tool is found in niftyseg/maths.py | ||
Patch Match tool is found in niftyseg/patchmatch.py | ||
Statistical operation tool is found in niftyseg/stats.py | ||
Label Fusion and CalcTopNcc tools are in niftyseg/steps.py | ||
|
||
Examples | ||
-------- | ||
See the docstrings of the individual classes for examples. | ||
|
||
""" | ||
|
||
from nipype.interfaces.base import CommandLine | ||
from nipype.utils.filemanip import split_filename | ||
import os | ||
import subprocess | ||
import warnings | ||
|
||
|
||
warn = warnings.warn | ||
warnings.filterwarnings('always', category=UserWarning) | ||
|
||
|
||
def get_custom_path(command): | ||
"""Get path of niftyseg.""" | ||
try: | ||
specific_dir = os.environ['NIFTYSEGDIR'] | ||
command = os.path.join(specific_dir, command) | ||
return command | ||
except KeyError: | ||
return command | ||
|
||
|
||
def no_niftyseg(cmd='seg_LabFusion'): | ||
"""Check if niftyseg is installed.""" | ||
if True in [os.path.isfile(os.path.join(path, cmd)) and | ||
os.access(os.path.join(path, cmd), os.X_OK) | ||
for path in os.environ["PATH"].split(os.pathsep)]: | ||
return False | ||
return True | ||
|
||
|
||
class NiftySegCommand(CommandLine): | ||
""" | ||
Base support interface for NiftySeg commands. | ||
""" | ||
_suffix = '_ns' | ||
|
||
def __init__(self, **inputs): | ||
super(NiftySegCommand, self).__init__(**inputs) | ||
|
||
def get_version(self): | ||
if no_niftyseg(cmd=self.cmd): | ||
return None | ||
# exec_cmd = ''.join((self.cmd, ' --version')) | ||
exec_cmd = 'seg_EM --version' | ||
# Using seg_EM for version (E.G: seg_stats --version doesn't work) | ||
return subprocess.check_output(exec_cmd, shell=True).strip('\n') | ||
|
||
@property | ||
def version(self): | ||
return self.get_version() | ||
|
||
def exists(self): | ||
if self.get_version() is None: | ||
return False | ||
return True | ||
|
||
def _gen_fname(self, basename, out_dir=None, suffix=None, ext=None): | ||
if basename == '': | ||
msg = 'Unable to generate filename for command %s. ' % self.cmd | ||
msg += 'basename is not set!' | ||
raise ValueError(msg) | ||
_, final_bn, final_ext = split_filename(basename) | ||
if out_dir is None: | ||
out_dir = os.getcwd() | ||
if ext is not None: | ||
final_ext = ext | ||
if suffix is not None: | ||
final_bn = ''.join((final_bn, suffix)) | ||
return os.path.abspath(os.path.join(out_dir, final_bn + final_ext)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- | ||
# vi: set ft=python sts=4 ts=4 sw=4 et: | ||
|
||
""" | ||
Nipype interface for seg_EM. | ||
|
||
The em module provides higher-level interfaces to some of the operations | ||
that can be performed with the seg_em command-line program. | ||
|
||
Examples | ||
-------- | ||
See the docstrings of the individual classes for examples. | ||
|
||
Change directory to provide relative paths for doctests | ||
>>> import os | ||
>>> filepath = os.path.dirname( os.path.realpath( __file__ ) ) | ||
>>> datadir = os.path.realpath(os.path.join(filepath, '../../testing/data')) | ||
>>> os.chdir(datadir) | ||
""" | ||
|
||
from ..base import (TraitedSpec, File, traits, CommandLineInputSpec, | ||
InputMultiPath) | ||
from .base import NiftySegCommand, get_custom_path | ||
|
||
|
||
class EMInputSpec(CommandLineInputSpec): | ||
"""Input Spec for EM.""" | ||
in_file = File(argstr='-in %s', | ||
exists=True, | ||
mandatory=True, | ||
desc='Input image to segment', | ||
position=4) | ||
|
||
mask_file = File(argstr='-mask %s', | ||
exists=True, | ||
desc='Filename of the ROI for label fusion') | ||
|
||
# Priors | ||
no_prior = traits.Int(argstr='-nopriors %s', | ||
mandatory=True, | ||
desc='Number of classes to use without prior', | ||
xor=['prior_4D', 'priors']) | ||
|
||
prior_4D = File(argstr='-prior4D %s', | ||
exists=True, | ||
mandatory=True, | ||
desc='4D file containing the priors', | ||
xor=['no_prior', 'priors']) | ||
|
||
desc = 'List of priors filepaths.' | ||
|
||
priors = InputMultiPath(argstr='%s', | ||
mandatory=True, | ||
desc=desc, | ||
xor=['no_prior', 'prior_4D']) | ||
|
||
# iterations | ||
max_iter = traits.Int(argstr='-max_iter %s', default=100, | ||
desc='Maximum number of iterations') | ||
|
||
min_iter = traits.Int(argstr='-min_iter %s', default=0, | ||
desc='Minimun number of iterations') | ||
|
||
# other options | ||
bc_order_val = traits.Int(argstr='-bc_order %s', default=3, | ||
desc='Polynomial order for the bias field') | ||
|
||
mrf_beta_val = traits.Float(argstr='-mrf_beta %s', | ||
desc='Weight of the Markov Random Field') | ||
|
||
desc = 'Bias field correction will run only if the ratio of improvement \ | ||
is below bc_thresh. (default=0 [OFF])' | ||
bc_thresh_val = traits.Float(argstr='-bc_thresh %s', default=0, desc=desc) | ||
|
||
desc = 'Amount of regularization over the diagonal of the covariance \ | ||
matrix [above 1]' | ||
reg_val = traits.Float(argstr='-reg %s', desc=desc) | ||
|
||
desc = 'Outlier detection as in (Van Leemput TMI 2003). <fl1> is the \ | ||
Mahalanobis threshold [recommended between 3 and 7] <fl2> is a convergence \ | ||
ratio below which the outlier detection is going to be done [recommended 0.01]' | ||
outlier_val = traits.Tuple(traits.Float(), traits.Float(), | ||
argstr='-outlier %s %s', | ||
desc=desc) | ||
|
||
desc = 'Relax Priors [relaxation factor: 0<rf<1 (recommended=0.5), \ | ||
gaussian regularization: gstd>0 (recommended=2.0)] /only 3D/' | ||
relax_priors = traits.Tuple(traits.Float(), traits.Float(), | ||
argstr='-rf %s %s', | ||
desc=desc) | ||
|
||
# outputs | ||
out_file = File(name_source=['in_file'], | ||
name_template='%s_em.nii.gz', | ||
argstr='-out %s', | ||
desc='Output segmentation') | ||
out_bc_file = File(name_source=['in_file'], | ||
name_template='%s_bc_em.nii.gz', | ||
argstr='-bc_out %s', | ||
desc='Output bias corrected image') | ||
out_outlier_file = File(name_source=['in_file'], | ||
name_template='%s_outlier_em.nii.gz', | ||
argstr='-out_outlier %s', | ||
desc='Output outlierness image') | ||
|
||
|
||
class EMOutputSpec(TraitedSpec): | ||
"""Output Spec for EM.""" | ||
out_file = File(desc="Output segmentation") | ||
out_bc_file = File(desc="Output bias corrected image") | ||
out_outlier_file = File(desc='Output outlierness image') | ||
|
||
|
||
class EM(NiftySegCommand): | ||
"""Interface for executable seg_EM from NiftySeg platform. | ||
|
||
seg_EM is a general purpose intensity based image segmentation tool. In | ||
it's simplest form, it takes in one 2D or 3D image and segments it in n | ||
classes. | ||
|
||
For source code, see http://cmictig.cs.ucl.ac.uk/wiki/index.php/NiftySeg | ||
For Documentation, see: | ||
http://cmictig.cs.ucl.ac.uk/wiki/index.php/NiftySeg_documentation | ||
|
||
Examples | ||
-------- | ||
>>> from nipype.interfaces import niftyseg | ||
>>> node = niftyseg.EM() | ||
>>> node.inputs.in_file = 'im1.nii' | ||
>>> node.inputs.no_prior = 4 | ||
>>> node.cmdline # doctest: +ALLOW_UNICODE | ||
'seg_EM -in im1.nii -nopriors 4 -bc_out im1_bc_em.nii.gz \ | ||
-out im1_em.nii.gz -out_outlier im1_outlier_em.nii.gz' | ||
|
||
""" | ||
_cmd = get_custom_path('seg_EM') | ||
_suffix = '_em' | ||
input_spec = EMInputSpec | ||
output_spec = EMOutputSpec | ||
|
||
def _format_arg(self, opt, spec, val): | ||
"""Convert input to appropriate format for seg_EM.""" | ||
if opt == 'priors': | ||
_nb_priors = len(self.inputs.priors) | ||
return '-priors %d %s' % (_nb_priors, ' '.join(self.inputs.priors)) | ||
else: | ||
return super(EM, self)._format_arg(opt, spec, val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these used outside the module? If not, I'd remove them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm I don't think so. I will remove them.