Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions nipype/interfaces/niftyseg/__init__.py
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
Copy link
Contributor

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

Copy link
Contributor Author

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.

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
91 changes: 91 additions & 0 deletions nipype/interfaces/niftyseg/base.py
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))
146 changes: 146 additions & 0 deletions nipype/interfaces/niftyseg/em.py
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.'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not setting this string directly on the argument? (this holds for many traits defined below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it was for style and not go over 80 chars when they are very long but I should put this one back there as well as the other one.

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)
Loading