Skip to content

Commit 90d1d35

Browse files
committed
ENH: Enable antsRegistration 2.2.0+ masking
1 parent b9c75fb commit 90d1d35

File tree

2 files changed

+54
-5
lines changed

2 files changed

+54
-5
lines changed

nipype/interfaces/ants/registration.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from builtins import range, str
1212
import os
1313

14+
from ...utils.filemanip import filename_to_list
1415
from ..base import TraitedSpec, File, Str, traits, InputMultiPath, isdefined
1516
from .base import ANTSCommand, ANTSCommandInputSpec
1617

@@ -219,12 +220,22 @@ class RegistrationInputSpec(ANTSCommandInputSpec):
219220
usedefault=True, desc='image dimension (2 or 3)')
220221
fixed_image = InputMultiPath(File(exists=True), mandatory=True,
221222
desc='image to apply transformation to (generally a coregistered functional)')
222-
fixed_image_mask = File(argstr='%s', exists=True,
223-
desc='mask used to limit metric sampling region of the fixed image')
223+
fixed_image_mask = File(
224+
exists=True, argstr='%s', max_ver='2.1.0', xor=['fixed_image_masks'],
225+
desc='mask used to limit metric sampling region of the fixed image')
226+
fixed_image_masks = InputMultiPath(
227+
traits.Either('NULL', File(exists=True)), min_ver='2.2.0', xor=['fixed_image_mask'],
228+
desc='mask used to limit metric sampling region of the fixed image '
229+
'(Use "NULL" to omit a mask at a given stage)')
224230
moving_image = InputMultiPath(File(exists=True), mandatory=True,
225231
desc='image to apply transformation to (generally a coregistered functional)')
226-
moving_image_mask = File(requires=['fixed_image_mask'],
227-
exists=True, desc='mask used to limit metric sampling region of the moving image')
232+
moving_image_mask = File(
233+
exists=True, requires=['fixed_image_mask'], max_ver='2.1.0', xor=['moving_image_masks'],
234+
desc='mask used to limit metric sampling region of the moving image')
235+
moving_image_masks = InputMultiPath(
236+
traits.Either('NULL', File(exists=True)), min_ver='2.2.0', xor=['moving_image_mask'],
237+
desc='mask used to limit metric sampling region of the moving image '
238+
'(Use "NULL" to omit a mask at a given stage)')
228239

229240
save_state = File(argstr='--save-state %s', exists=False,
230241
desc='Filename for saving the internal restorable state of the registration')
@@ -648,6 +659,20 @@ class Registration(ANTSCommand):
648659
--metric Mattes[ fixed1.nii, moving1.nii, 1, 32 ] --convergence [ 100x50x30, 1e-09, 20 ] \
649660
--smoothing-sigmas 2.0x1.0x0.0vox --shrink-factors 3x2x1 --use-estimate-learning-rate-once 1 \
650661
--use-histogram-matching 1 --winsorize-image-intensities [ 0.0, 1.0 ] --write-composite-transform 1'
662+
663+
>>> # Test masking
664+
>>> reg9 = copy.deepcopy(reg)
665+
>>> reg9.inputs.fixed_image_masks = ['NULL', 'fixed1.nii']
666+
>>> reg9.cmdline # doctest: +ALLOW_UNICODE
667+
'antsRegistration --collapse-output-transforms 0 --dimensionality 3 --initial-moving-transform [ trans.mat, 1 ] \
668+
--initialize-transforms-per-stage 0 --interpolation Linear --output [ output_, output_warped_image.nii.gz ] \
669+
--transform Affine[ 2.0 ] --metric Mattes[ fixed1.nii, moving1.nii, 1, 32, Random, 0.05 ] \
670+
--convergence [ 1500x200, 1e-08, 20 ] --smoothing-sigmas 1.0x0.0vox --shrink-factors 2x1 \
671+
--use-estimate-learning-rate-once 1 --use-histogram-matching 1 --masks [ NULL, NULL ] \
672+
--transform SyN[ 0.25, 3.0, 0.0 ] --metric Mattes[ fixed1.nii, moving1.nii, 1, 32 ] \
673+
--convergence [ 100x50x30, 1e-09, 20 ] --smoothing-sigmas 2.0x1.0x0.0vox --shrink-factors 3x2x1 \
674+
--use-estimate-learning-rate-once 1 --use-histogram-matching 1 --masks [ fixed1.nii, NULL ] \
675+
--winsorize-image-intensities [ 0.0, 1.0 ] --write-composite-transform 1'
651676
"""
652677
DEF_SAMPLING_STRATEGY = 'None'
653678
"""The default sampling strategy argument."""
@@ -783,6 +808,20 @@ def _format_registration(self):
783808
if isdefined(self.inputs.restrict_deformation):
784809
retval.append('--restrict-deformation %s' %
785810
self._format_xarray(self.inputs.restrict_deformation[ii]))
811+
if any((isdefined(self.inputs.fixed_image_masks),
812+
isdefined(self.inputs.moving_image_masks))):
813+
if isdefined(self.inputs.fixed_image_masks):
814+
fixed_masks = filename_to_list(self.inputs.fixed_image_masks)
815+
fixed_mask = fixed_masks[ii if len(fixed_masks) > 1 else 0]
816+
else:
817+
fixed_mask = 'NULL'
818+
819+
if isdefined(self.inputs.moving_image_masks):
820+
moving_masks = filename_to_list(self.inputs.moving_image_masks)
821+
moving_mask = moving_masks[ii if len(moving_masks) > 1 else 0]
822+
else:
823+
moving_mask = 'NULL'
824+
retval.append('--masks [ %s, %s ]' % (fixed_mask, moving_mask))
786825
return " ".join(retval)
787826

788827
def _get_outputfilenames(self, inverse=False):

nipype/interfaces/ants/tests/test_auto_Registration.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ def test_Registration_inputs():
2424
fixed_image=dict(mandatory=True,
2525
),
2626
fixed_image_mask=dict(argstr='%s',
27+
max_ver='2.1.0',
28+
xor=['fixed_image_masks'],
29+
),
30+
fixed_image_masks=dict(min_ver='2.2.0',
31+
xor=['fixed_image_mask'],
2732
),
2833
float=dict(argstr='--float %d',
2934
),
@@ -58,7 +63,12 @@ def test_Registration_inputs():
5863
metric_weight_stage_trait=dict(),
5964
moving_image=dict(mandatory=True,
6065
),
61-
moving_image_mask=dict(requires=['fixed_image_mask'],
66+
moving_image_mask=dict(max_ver='2.1.0',
67+
requires=['fixed_image_mask'],
68+
xor=['moving_image_masks'],
69+
),
70+
moving_image_masks=dict(min_ver='2.2.0',
71+
xor=['moving_image_mask'],
6272
),
6373
num_threads=dict(nohash=True,
6474
usedefault=True,

0 commit comments

Comments
 (0)