@@ -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