Skip to content

Commit 3c75d63

Browse files
author
Oscar Esteban
committed
Merge branch 'master' into enh/ETSConfigTookit
2 parents 2448821 + 70a5128 commit 3c75d63

26 files changed

+1407
-205
lines changed

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ Next release
22
============
33

44
* FIX: Prevent crash when tvtk is loaded - ETS_TOOLKIT=null (https://github.com/nipy/nipype/pull/973)
5+
* ENH: New interfaces in dipy: RESTORE, EstimateResponseSH, CSD and StreamlineTractography
6+
(https://github.com/nipy/nipype/pull/1090)
57
* ENH: Added interfaces of AFNI (https://github.com/nipy/nipype/pull/1360,
68
https://github.com/nipy/nipype/pull/1361)
9+
* ENH: Provides a Nipype wrapper for antsJointFusion (https://github.com/nipy/nipype/pull/1351)
710
* ENH: Added support for PETPVC (https://github.com/nipy/nipype/pull/1335)
811
* ENH: Merge S3DataSink into DataSink, added AWS documentation (https://github.com/nipy/nipype/pull/1316)
912
* TST: Cache APT in CircleCI (https://github.com/nipy/nipype/pull/1333)

circle.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ dependencies:
99
pre:
1010
# Let CircleCI cache the apt archive
1111
- sudo rm -rf /var/cache/apt/archives && sudo ln -s ~/.apt-cache /var/cache/apt/archives && mkdir -p ~/.apt-cache/partial
12-
- wget -O- http://neuro.debian.net/lists/precise.us-ca.full | sudo tee /etc/apt/sources.list.d/neurodebian.sources.list
13-
- sudo apt-key adv --recv-keys --keyserver hkp://pgp.mit.edu:80 0xA5D32F012649A5A9
14-
- sudo apt-get update
12+
- bash <(wget -q -O- http://neuro.debian.net/_files/neurodebian-travis.sh)
1513
override:
1614
# Install apt packages
1715
- sudo apt-get install -y fsl-core fsl-atlases fsl-mni152-templates fsl-feeds afni swig python-vtk xvfb
@@ -23,7 +21,7 @@ dependencies:
2321
# Set up python environment
2422
- pip install --upgrade pip
2523
- pip install -e .
26-
- pip install matplotlib sphinx ipython boto coverage
24+
- pip install matplotlib sphinx ipython boto coverage dipy
2725
# Add tvtk
2826
- pip install http://effbot.org/downloads/Imaging-1.1.7.tar.gz
2927
- pip install -e git+https://github.com/enthought/etsdevtools.git#egg=etsdevtools

nipype/interfaces/ants/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
# Segmentation Programs
1414
from .segmentation import (Atropos, LaplacianThickness, N4BiasFieldCorrection, JointFusion, CorticalThickness,
15-
BrainExtraction, DenoiseImage)
15+
BrainExtraction, DenoiseImage, AntsJointFusion)
1616

1717
# Visualization Programs
1818
from .visualization import ConvertScalarImageToRGB, CreateTiledMosaic

nipype/interfaces/ants/segmentation.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,3 +869,201 @@ def _format_arg(self, name, trait_spec, value):
869869

870870
return super(DenoiseImage,
871871
self)._format_arg(name, trait_spec, value)
872+
873+
874+
class AntsJointFusionInputSpec(ANTSCommandInputSpec):
875+
dimension = traits.Enum(3, 2, 4, argstr='-d %d', usedefault=False,
876+
desc='This option forces the image to be treated '
877+
'as a specified-dimensional image. If not '
878+
'specified, the program tries to infer the '
879+
'dimensionality from the input image.')
880+
target_image = traits.List(InputMultiPath(File(exists=True)), argstr='-t %s',
881+
mandatory=True, desc='The target image (or '
882+
'multimodal target images) assumed to be '
883+
'aligned to a common image domain.')
884+
atlas_image = traits.List(InputMultiPath(File(exists=True)), argstr="-g %s...",
885+
mandatory=True, desc='The atlas image (or '
886+
'multimodal atlas images) assumed to be '
887+
'aligned to a common image domain.')
888+
atlas_segmentation_image = InputMultiPath(File(exists=True), argstr="-l %s...",
889+
mandatory=True, desc='The atlas segmentation '
890+
'images. For performing label fusion the number '
891+
'of specified segmentations should be identical '
892+
'to the number of atlas image sets.')
893+
alpha = traits.Float(default_value=0.1, usedefault=True, argstr='-a %s', desc=('Regularization '
894+
'term added to matrix Mx for calculating the inverse. Default = 0.1'))
895+
beta = traits.Float(default_value=2.0, usedefault=True, argstr='-b %s', desc=('Exponent for mapping '
896+
'intensity difference to the joint error. Default = 2.0'))
897+
retain_label_posterior_images = traits.Bool(False, argstr='-r', usedefault=True,
898+
requires=['atlas_segmentation_image'],
899+
desc=('Retain label posterior probability images. Requires '
900+
'atlas segmentations to be specified. Default = false'))
901+
retain_atlas_voting_images = traits.Bool(False, argstr='-f', usedefault=True,
902+
desc=('Retain atlas voting images. Default = false'))
903+
constrain_nonnegative = traits.Bool(False, argstr='-c', usedefault=True,
904+
desc=('Constrain solution to non-negative weights.'))
905+
patch_radius = traits.ListInt(minlen=3, maxlen=3, argstr='-p %s',
906+
desc=('Patch radius for similarity measures.'
907+
'Default: 2x2x2'))
908+
patch_metric = traits.Enum('PC', 'MSQ', argstr='-m %s', usedefault=False,
909+
desc=('Metric to be used in determining the most similar '
910+
'neighborhood patch. Options include Pearson\'s '
911+
'correlation (PC) and mean squares (MSQ). Default = '
912+
'PC (Pearson correlation).'))
913+
search_radius = traits.List([3,3,3], minlen=1, maxlen=3, argstr='-s %s', usedefault=True,
914+
desc=('Search radius for similarity measures. Default = 3x3x3. '
915+
'One can also specify an image where the value at the '
916+
'voxel specifies the isotropic search radius at that voxel.'))
917+
exclusion_image_label = traits.List(traits.Str(), argstr='-e %s', requires=['exclusion_image'],
918+
desc=('Specify a label for the exclusion region.'))
919+
exclusion_image = traits.List(File(exists=True),
920+
desc=('Specify an exclusion region for the given label.'))
921+
mask_image = File(argstr='-x %s', exists=True, desc='If a mask image '
922+
'is specified, fusion is only performed in the mask region.')
923+
out_label_fusion = File(argstr="%s", hash_files=False,
924+
desc='The output label fusion image.')
925+
out_intensity_fusion_name_format = traits.Str('antsJointFusionIntensity_%d.nii.gz',
926+
argstr="", desc='Optional intensity fusion '
927+
'image file name format.')
928+
out_label_post_prob_name_format = traits.Str('antsJointFusionPosterior_%d.nii.gz',
929+
requires=['out_label_fusion',
930+
'out_intensity_fusion_name_format'],
931+
desc='Optional label posterior probability '
932+
'image file name format.')
933+
out_atlas_voting_weight_name_format = traits.Str('antsJointFusionVotingWeight_%d.nii.gz',
934+
requires=['out_label_fusion',
935+
'out_intensity_fusion_name_format',
936+
'out_label_post_prob_name_format'],
937+
desc='Optional atlas voting weight image '
938+
'file name format.')
939+
verbose = traits.Bool(False, argstr="-v", desc=('Verbose output.'))
940+
941+
942+
class AntsJointFusionOutputSpec(TraitedSpec):
943+
out_label_fusion = File(exists=True)
944+
out_intensity_fusion_name_format = traits.Str()
945+
out_label_post_prob_name_format = traits.Str()
946+
out_atlas_voting_weight_name_format = traits.Str()
947+
948+
949+
class AntsJointFusion(ANTSCommand):
950+
"""
951+
Examples
952+
--------
953+
954+
>>> from nipype.interfaces.ants import AntsJointFusion
955+
>>> antsjointfusion = AntsJointFusion()
956+
>>> antsjointfusion.inputs.out_label_fusion = 'ants_fusion_label_output.nii'
957+
>>> antsjointfusion.inputs.atlas_image = [ ['rc1s1.nii','rc1s2.nii'] ]
958+
>>> antsjointfusion.inputs.atlas_segmentation_image = ['segmentation0.nii.gz']
959+
>>> antsjointfusion.inputs.target_image = ['im1.nii']
960+
>>> antsjointfusion.cmdline
961+
"antsJointFusion -a 0.1 -g ['rc1s1.nii', 'rc1s2.nii'] -l segmentation0.nii.gz \
962+
-b 2.0 -o ants_fusion_label_output.nii -s 3x3x3 -t ['im1.nii']"
963+
964+
>>> antsjointfusion.inputs.target_image = [ ['im1.nii', 'im2.nii'] ]
965+
>>> antsjointfusion.cmdline
966+
"antsJointFusion -a 0.1 -g ['rc1s1.nii', 'rc1s2.nii'] -l segmentation0.nii.gz \
967+
-b 2.0 -o ants_fusion_label_output.nii -s 3x3x3 -t ['im1.nii', 'im2.nii']"
968+
969+
>>> antsjointfusion.inputs.atlas_image = [ ['rc1s1.nii','rc1s2.nii'],
970+
... ['rc2s1.nii','rc2s2.nii'] ]
971+
>>> antsjointfusion.inputs.atlas_segmentation_image = ['segmentation0.nii.gz',
972+
... 'segmentation1.nii.gz']
973+
>>> antsjointfusion.cmdline
974+
"antsJointFusion -a 0.1 -g ['rc1s1.nii', 'rc1s2.nii'] -g ['rc2s1.nii', 'rc2s2.nii'] \
975+
-l segmentation0.nii.gz -l segmentation1.nii.gz -b 2.0 -o ants_fusion_label_output.nii \
976+
-s 3x3x3 -t ['im1.nii', 'im2.nii']"
977+
978+
>>> antsjointfusion.inputs.dimension = 3
979+
>>> antsjointfusion.inputs.alpha = 0.5
980+
>>> antsjointfusion.inputs.beta = 1.0
981+
>>> antsjointfusion.inputs.patch_radius = [3,2,1]
982+
>>> antsjointfusion.inputs.search_radius = [3]
983+
>>> antsjointfusion.cmdline
984+
"antsJointFusion -a 0.5 -g ['rc1s1.nii', 'rc1s2.nii'] -g ['rc2s1.nii', 'rc2s2.nii'] \
985+
-l segmentation0.nii.gz -l segmentation1.nii.gz -b 1.0 -d 3 -o ants_fusion_label_output.nii \
986+
-p 3x2x1 -s 3 -t ['im1.nii', 'im2.nii']"
987+
988+
>>> antsjointfusion.inputs.search_radius = ['mask.nii']
989+
>>> antsjointfusion.inputs.verbose = True
990+
>>> antsjointfusion.inputs.exclusion_image = ['roi01.nii', 'roi02.nii']
991+
>>> antsjointfusion.inputs.exclusion_image_label = ['1','2']
992+
>>> antsjointfusion.cmdline
993+
"antsJointFusion -a 0.5 -g ['rc1s1.nii', 'rc1s2.nii'] -g ['rc2s1.nii', 'rc2s2.nii'] \
994+
-l segmentation0.nii.gz -l segmentation1.nii.gz -b 1.0 -d 3 -e 1[roi01.nii] -e 2[roi02.nii] \
995+
-o ants_fusion_label_output.nii -p 3x2x1 -s mask.nii -t ['im1.nii', 'im2.nii'] -v"
996+
997+
>>> antsjointfusion.inputs.out_label_fusion = 'ants_fusion_label_output.nii'
998+
>>> antsjointfusion.inputs.out_intensity_fusion_name_format = 'ants_joint_fusion_intensity_%d.nii.gz'
999+
>>> antsjointfusion.inputs.out_label_post_prob_name_format = 'ants_joint_fusion_posterior_%d.nii.gz'
1000+
>>> antsjointfusion.inputs.out_atlas_voting_weight_name_format = 'ants_joint_fusion_voting_weight_%d.nii.gz'
1001+
>>> antsjointfusion.cmdline
1002+
"antsJointFusion -a 0.5 -g ['rc1s1.nii', 'rc1s2.nii'] -g ['rc2s1.nii', 'rc2s2.nii'] \
1003+
-l segmentation0.nii.gz -l segmentation1.nii.gz -b 1.0 -d 3 -e 1[roi01.nii] -e 2[roi02.nii] \
1004+
-o [ants_fusion_label_output.nii, ants_joint_fusion_intensity_%d.nii.gz, \
1005+
ants_joint_fusion_posterior_%d.nii.gz, ants_joint_fusion_voting_weight_%d.nii.gz] \
1006+
-p 3x2x1 -s mask.nii -t ['im1.nii', 'im2.nii'] -v"
1007+
1008+
"""
1009+
input_spec = AntsJointFusionInputSpec
1010+
output_spec = AntsJointFusionOutputSpec
1011+
_cmd = 'antsJointFusion'
1012+
1013+
def _format_arg(self, opt, spec, val):
1014+
if opt == 'exclusion_image_label':
1015+
retval = []
1016+
for ii in range(len(self.inputs.exclusion_image_label)):
1017+
retval.append('-e {0}[{1}]'.format(
1018+
self.inputs.exclusion_image_label[ii],
1019+
self.inputs.exclusion_image[ii]))
1020+
retval = ' '.join(retval)
1021+
elif opt == 'patch_radius':
1022+
retval = '-p {0}'.format(self._format_xarray(val))
1023+
elif opt == 'search_radius':
1024+
retval = '-s {0}'.format(self._format_xarray(val))
1025+
elif opt == 'out_label_fusion':
1026+
if isdefined(self.inputs.out_intensity_fusion_name_format):
1027+
if isdefined(self.inputs.out_label_post_prob_name_format):
1028+
if isdefined(self.inputs.out_atlas_voting_weight_name_format):
1029+
retval = '-o [{0}, {1}, {2}, {3}]'.format(self.inputs.out_label_fusion,
1030+
self.inputs.out_intensity_fusion_name_format,
1031+
self.inputs.out_label_post_prob_name_format,
1032+
self.inputs.out_atlas_voting_weight_name_format)
1033+
else:
1034+
retval = '-o [{0}, {1}, {2}]'.format(self.inputs.out_label_fusion,
1035+
self.inputs.out_intensity_fusion_name_format,
1036+
self.inputs.out_label_post_prob_name_format)
1037+
else:
1038+
retval = '-o [{0}, {1}]'.format(self.inputs.out_label_fusion,
1039+
self.inputs.out_intensity_fusion_name_format)
1040+
else:
1041+
retval = '-o {0}'.format(self.inputs.out_label_fusion)
1042+
elif opt == 'out_intensity_fusion_name_format':
1043+
retval = ''
1044+
if not isdefined(self.inputs.out_label_fusion):
1045+
retval = '-o {0}'.format(self.inputs.out_intensity_fusion_name_format)
1046+
else:
1047+
if opt == 'atlas_segmentation_image':
1048+
assert len(val) == len(self.inputs.atlas_image), "Number of specified " \
1049+
"segmentations should be identical to the number of atlas image " \
1050+
"sets {0}!={1}".format(len(val), len(self.inputs.atlas_image))
1051+
return super(ANTSCommand, self)._format_arg(opt, spec, val)
1052+
return retval
1053+
1054+
def _list_outputs(self):
1055+
outputs = self._outputs().get()
1056+
if isdefined(self.inputs.out_label_fusion):
1057+
outputs['out_label_fusion'] = os.path.abspath(
1058+
self.inputs.out_label_fusion)
1059+
if isdefined(self.inputs.out_intensity_fusion_name_format):
1060+
outputs['out_intensity_fusion_name_format'] = os.path.abspath(
1061+
self.inputs.out_intensity_fusion_name_format)
1062+
if isdefined(self.inputs.out_label_post_prob_name_format):
1063+
outputs['out_label_post_prob_name_format'] = os.path.abspath(
1064+
self.inputs.out_label_post_prob_name_format)
1065+
if isdefined(self.inputs.out_atlas_voting_weight_name_format):
1066+
outputs['out_atlas_voting_weight_name_format'] = os.path.abspath(
1067+
self.inputs.out_atlas_voting_weight_name_format)
1068+
1069+
return outputs
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from ....testing import assert_equal
3+
from ..segmentation import AntsJointFusion
4+
5+
6+
def test_AntsJointFusion_inputs():
7+
input_map = dict(alpha=dict(argstr='-a %s',
8+
usedefault=True,
9+
),
10+
args=dict(argstr='%s',
11+
),
12+
atlas_image=dict(argstr='-g %s...',
13+
mandatory=True,
14+
),
15+
atlas_segmentation_image=dict(argstr='-l %s...',
16+
mandatory=True,
17+
),
18+
beta=dict(argstr='-b %s',
19+
usedefault=True,
20+
),
21+
constrain_nonnegative=dict(argstr='-c',
22+
usedefault=True,
23+
),
24+
dimension=dict(argstr='-d %d',
25+
usedefault=False,
26+
),
27+
environ=dict(nohash=True,
28+
usedefault=True,
29+
),
30+
exclusion_image=dict(),
31+
exclusion_image_label=dict(argstr='-e %s',
32+
requires=['exclusion_image'],
33+
),
34+
ignore_exception=dict(nohash=True,
35+
usedefault=True,
36+
),
37+
mask_image=dict(argstr='-x %s',
38+
),
39+
num_threads=dict(nohash=True,
40+
usedefault=True,
41+
),
42+
out_atlas_voting_weight_name_format=dict(requires=['out_label_fusion', 'out_intensity_fusion_name_format', 'out_label_post_prob_name_format'],
43+
),
44+
out_intensity_fusion_name_format=dict(argstr='',
45+
),
46+
out_label_fusion=dict(argstr='%s',
47+
hash_files=False,
48+
),
49+
out_label_post_prob_name_format=dict(requires=['out_label_fusion', 'out_intensity_fusion_name_format'],
50+
),
51+
patch_metric=dict(argstr='-m %s',
52+
usedefault=False,
53+
),
54+
patch_radius=dict(argstr='-p %s',
55+
maxlen=3,
56+
minlen=3,
57+
),
58+
retain_atlas_voting_images=dict(argstr='-f',
59+
usedefault=True,
60+
),
61+
retain_label_posterior_images=dict(argstr='-r',
62+
requires=['atlas_segmentation_image'],
63+
usedefault=True,
64+
),
65+
search_radius=dict(argstr='-s %s',
66+
usedefault=True,
67+
),
68+
target_image=dict(argstr='-t %s',
69+
mandatory=True,
70+
),
71+
terminal_output=dict(nohash=True,
72+
),
73+
verbose=dict(argstr='-v',
74+
),
75+
)
76+
inputs = AntsJointFusion.input_spec()
77+
78+
for key, metadata in list(input_map.items()):
79+
for metakey, value in list(metadata.items()):
80+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
81+
82+
83+
def test_AntsJointFusion_outputs():
84+
output_map = dict(out_atlas_voting_weight_name_format=dict(),
85+
out_intensity_fusion_name_format=dict(),
86+
out_label_fusion=dict(),
87+
out_label_post_prob_name_format=dict(),
88+
)
89+
outputs = AntsJointFusion.output_spec()
90+
91+
for key, metadata in list(output_map.items()):
92+
for metakey, value in list(metadata.items()):
93+
yield assert_equal, getattr(outputs.traits()[key], metakey), value

nipype/interfaces/dipy/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from .tracks import TrackDensityMap
1+
from .tracks import StreamlineTractography, TrackDensityMap
22
from .tensors import TensorMode, DTI
33
from .preprocess import Resample, Denoise
4+
from .reconstruction import RESTORE, EstimateResponseSH, CSD
45
from .simulate import SimulateMultiTensor

0 commit comments

Comments
 (0)