Skip to content

Commit 6268f26

Browse files
committed
Merge branch 'AntsMultiModalFixSecondAttempt' of https://github.com/BRAINSia/nipype
* 'AntsMultiModalFixSecondAttempt' of https://github.com/BRAINSia/nipype: BUG: Restore registration interface failed multi-modal
2 parents e1ea144 + 36ec6a5 commit 6268f26

File tree

2 files changed

+53
-18
lines changed

2 files changed

+53
-18
lines changed

CHANGES

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

44
* ENH: New option in afni.3dRefit - zdel, ydel, zdel etc. (https://github.com/nipy/nipype/pull/1079)
55
* FIX: ants.Registration composite transform outputs are no longer returned as lists (https://github.com/nipy/nipype/pull/1183)
6+
* BUG: ANTs Registration interface failed with multi-modal inputs
7+
(https://github.com/nipy/nipype/pull/1176) (https://github.com/nipy/nipype/issues/1175)
68
* FIX: Bug in XFibres5 (https://github.com/nipy/nipype/pull/1168)
79
* ENH: Attempt to use hard links for data sink.
810
(https://github.com/nipy/nipype/pull/1161)

nipype/interfaces/ants/registration.py

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,26 @@ class ANTSInputSpec(ANTSCommandInputSpec):
2626
desc=('image to apply transformation to (generally a coregistered '
2727
'functional)'))
2828

29+
# Not all metrics are appropriate for all modalities. Also, not all metrics
30+
# are efficeint or appropriate at all resolution levels, Some metrics perform
31+
# well for gross global registraiton, but do poorly for small changes (i.e.
32+
# Mattes), and some metrics do well for small changes but don't work well for
33+
# gross level changes (i.e. 'CC').
34+
#
35+
# This is a two stage registration. in the first stage
36+
# [ 'Mattes', .................]
37+
# ^^^^^^ <- First stage
38+
# Do a unimodal registration of the first elements of the fixed/moving input
39+
# list use the"CC" as the metric.
40+
#
41+
# In the second stage
42+
# [ ....., ['Mattes','CC'] ]
43+
# ^^^^^^^^^^^^^^^ <- Second stage
44+
# Do a multi-modal registration where the first elements of fixed/moving
45+
# input list use 'CC' metric and that is added to 'Mattes' metric result of
46+
# the second elements of the fixed/moving input.
47+
#
48+
# Cost = Sum_i ( metricweight[i] Metric_i ( fixedimage[i], movingimage[i]) )
2949
metric = traits.List(traits.Enum('CC', 'MI', 'SMI', 'PR', 'SSD',
3050
'MSQ', 'PSE'), mandatory=True, desc='')
3151

@@ -438,13 +458,15 @@ class Registration(ANTSCommand):
438458
439459
>>> # Test multiple metrics per stage
440460
>>> reg5 = copy.deepcopy(reg)
441-
>>> reg5.inputs.metric = ['CC', ['CC', 'Mattes']]
442-
>>> reg5.inputs.metric_weight = [1, [.5]*2]
443-
>>> reg5.inputs.radius_or_number_of_bins = [4, [32]*2]
461+
>>> reg5.inputs.fixed_image = [ 'fixed1.nii', 'fixed2.nii' ]
462+
>>> reg5.inputs.moving_image = [ 'moving1.nii', 'moving2.nii' ]
463+
>>> reg5.inputs.metric = ['Mattes', ['Mattes', 'CC']]
464+
>>> reg5.inputs.metric_weight = [1, [.5,.5]]
465+
>>> reg5.inputs.radius_or_number_of_bins = [32, [32,4] ]
444466
>>> reg5.inputs.sampling_strategy = ['Random', None] # use default strategy in second stage
445467
>>> reg5.inputs.sampling_percentage = [0.05, [0.05, 0.10]]
446468
>>> reg5.cmdline
447-
'antsRegistration --collapse-output-transforms 0 --dimensionality 3 --initial-moving-transform [ trans.mat, 1 ] --initialize-transforms-per-stage 0 --interpolation Linear --output [ output_, output_warped_image.nii.gz ] --restore-state trans.mat --save-state trans.mat --transform Affine[ 2.0 ] --metric CC[ fixed1.nii, moving1.nii, 1, 4, Random, 0.05 ] --convergence [ 1500x200, 1e-08, 20 ] --smoothing-sigmas 1.0x0.0vox --shrink-factors 2x1 --use-estimate-learning-rate-once 1 --use-histogram-matching 1 --transform SyN[ 0.25, 3.0, 0.0 ] --metric CC[ fixed1.nii, moving1.nii, 0.5, 32, None, 0.05 ] --metric Mattes[ fixed1.nii, moving1.nii, 0.5, 32, None, 0.1 ] --convergence [ 100x50x30, 1e-09, 20 ] --smoothing-sigmas 2.0x1.0x0.0vox --shrink-factors 3x2x1 --use-estimate-learning-rate-once 1 --use-histogram-matching 1 --winsorize-image-intensities [ 0.0, 1.0 ] --write-composite-transform 1'
469+
'antsRegistration --collapse-output-transforms 0 --dimensionality 3 --initial-moving-transform [ trans.mat, 1 ] --initialize-transforms-per-stage 0 --interpolation Linear --output [ output_, output_warped_image.nii.gz ] --restore-state trans.mat --save-state trans.mat --transform Affine[ 2.0 ] --metric Mattes[ fixed1.nii, moving1.nii, 1, 32, Random, 0.05 ] --convergence [ 1500x200, 1e-08, 20 ] --smoothing-sigmas 1.0x0.0vox --shrink-factors 2x1 --use-estimate-learning-rate-once 1 --use-histogram-matching 1 --transform SyN[ 0.25, 3.0, 0.0 ] --metric Mattes[ fixed1.nii, moving1.nii, 0.5, 32, None, 0.05 ] --metric CC[ fixed2.nii, moving2.nii, 0.5, 4, None, 0.1 ] --convergence [ 100x50x30, 1e-09, 20 ] --smoothing-sigmas 2.0x1.0x0.0vox --shrink-factors 3x2x1 --use-estimate-learning-rate-once 1 --use-histogram-matching 1 --winsorize-image-intensities [ 0.0, 1.0 ] --write-composite-transform 1'
448470
"""
449471
DEF_SAMPLING_STRATEGY = 'None'
450472
"""The default sampling strategy argument."""
@@ -464,14 +486,12 @@ def _formatMetric(self, index):
464486
----------
465487
index: the stage index
466488
"""
467-
# The common fixed image.
468-
fixed = self.inputs.fixed_image[0]
469-
# The common moving image.
470-
moving = self.inputs.moving_image[0]
471489
# The metric name input for the current stage.
472490
name_input = self.inputs.metric[index]
473491
# The stage-specific input dictionary.
474492
stage_inputs = dict(
493+
fixed_image=self.inputs.fixed_image[0],
494+
moving_image=self.inputs.moving_image[0],
475495
metric=name_input,
476496
weight=self.inputs.metric_weight[index],
477497
radius_or_bins=self.inputs.radius_or_number_of_bins[index],
@@ -497,19 +517,32 @@ def _formatMetric(self, index):
497517
if isinstance(name_input, list):
498518
items = stage_inputs.items()
499519
indexes = range(0, len(name_input))
500-
# dict-comprehension only works with python 2.7 and up
501-
# specs = [{k: v[i] for k, v in items} for i in indexes]
502-
specs = [dict([(k, v[i]) for k, v in items]) for i in indexes]
520+
specs = list()
521+
for i in indexes:
522+
temp = dict([(k, v[i]) for k, v in items])
523+
if i > len( self.inputs.fixed_image ):
524+
temp["fixed_image"] = self.inputs.fixed_image[0]
525+
else:
526+
temp["fixed_image"] = self.inputs.fixed_image[i]
527+
528+
if i > len( self.inputs.moving_image ):
529+
temp["moving_image"] = self.inputs.moving_image[0]
530+
else:
531+
temp["moving_image"] = self.inputs.moving_image[i]
532+
533+
specs.append( temp )
503534
else:
504535
specs = [stage_inputs]
505536

506537
# Format the --metric command line metric arguments, one per
507538
# specification.
508-
return [self._formatMetricArgument(fixed, moving, **spec) for spec in specs]
539+
return [self._formatMetricArgument(**spec) for spec in specs]
509540

510-
def _formatMetricArgument(self, fixed, moving, **kwargs):
541+
def _formatMetricArgument(self, **kwargs):
511542
retval = '%s[ %s, %s, %g, %d' % (kwargs['metric'],
512-
fixed, moving, kwargs['weight'],
543+
kwargs['fixed_image'],
544+
kwargs['moving_image'],
545+
kwargs['weight'],
513546
kwargs['radius_or_bins'])
514547

515548
# The optional sampling strategy.
@@ -548,17 +581,17 @@ def _formatRegistration(self):
548581
retval.append('--metric %s' % metric)
549582
retval.append('--convergence %s' % self._formatConvergence(ii))
550583
if isdefined(self.inputs.sigma_units):
551-
retval.append('--smoothing-sigmas %s%s' %
584+
retval.append('--smoothing-sigmas %s%s' %
552585
(self._antsJoinList(self.inputs.smoothing_sigmas[
553586
ii]),
554587
self.inputs.sigma_units[ii]))
555588
else:
556-
retval.append('--smoothing-sigmas %s' %
589+
retval.append('--smoothing-sigmas %s' %
557590
self._antsJoinList(self.inputs.smoothing_sigmas[ii]))
558-
retval.append('--shrink-factors %s' %
591+
retval.append('--shrink-factors %s' %
559592
self._antsJoinList(self.inputs.shrink_factors[ii]))
560593
if isdefined(self.inputs.use_estimate_learning_rate_once):
561-
retval.append('--use-estimate-learning-rate-once %d' %
594+
retval.append('--use-estimate-learning-rate-once %d' %
562595
self.inputs.use_estimate_learning_rate_once[ii])
563596
if isdefined(self.inputs.use_histogram_matching):
564597
# use_histogram_matching is either a common flag for all transforms

0 commit comments

Comments
 (0)