From 053d1ca502a0525b07e1b1439eaff2237e309ee9 Mon Sep 17 00:00:00 2001 From: Horea Christian Date: Wed, 26 Jul 2017 17:15:03 +0200 Subject: [PATCH] added interface for MeasureImageSimilarity --- nipype/interfaces/ants/__init__.py | 2 +- nipype/interfaces/ants/registration.py | 122 ++++++++++++++++++ .../tests/test_auto_MeasureImageSimilarity.py | 61 +++++++++ 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 nipype/interfaces/ants/tests/test_auto_MeasureImageSimilarity.py diff --git a/nipype/interfaces/ants/__init__.py b/nipype/interfaces/ants/__init__.py index 11c7ae724a..01591c8817 100644 --- a/nipype/interfaces/ants/__init__.py +++ b/nipype/interfaces/ants/__init__.py @@ -5,7 +5,7 @@ """Top-level namespace for ants.""" # Registraiton programs -from .registration import ANTS, Registration +from .registration import ANTS, Registration, MeasureImageSimilarity # Resampling Programs from .resampling import (ApplyTransforms, ApplyTransformsToPoints, WarpImageMultiTransform, diff --git a/nipype/interfaces/ants/registration.py b/nipype/interfaces/ants/registration.py index cf5c18333e..6ee12c263d 100644 --- a/nipype/interfaces/ants/registration.py +++ b/nipype/interfaces/ants/registration.py @@ -1034,3 +1034,125 @@ def _list_outputs(self): if len(self.inputs.save_state): outputs['save_state'] = os.path.abspath(self.inputs.save_state) return outputs + + +class MeasureImageSimilarityInputSpec(ANTSCommandInputSpec): + dimension = traits.Enum( + 2, 3, 4, + argstr='--dimensionality %d', position=1, + desc='Dimensionality of the fixed/moving image pair', + ) + fixed_image = File( + exists=True, mandatory=True, + desc='Image to which the moving image is warped', + ) + moving_image = File( + exists=True, mandatory=True, + desc='Image to apply transformation to (generally a coregistered functional)', + ) + metric = traits.Enum( + "CC", "MI", "Mattes", "MeanSquares", "Demons", "GC", + argstr="%s", mandatory=True, + ) + metric_weight = traits.Float( + requires=['metric'], default=1.0, usedefault=True, + desc='The "metricWeight" variable is not used.', + ) + radius_or_number_of_bins = traits.Int( + requires=['metric'], mandatory=True, + desc='The number of bins in each stage for the MI and Mattes metric, ' + 'or the radius for other metrics', + ) + sampling_strategy = traits.Enum( + "None", "Regular", "Random", + requires=['metric'], default="None", usedefault=True, + desc='Manner of choosing point set over which to optimize the metric. ' + 'Defaults to "None" (i.e. a dense sampling of one sample per voxel).' + ) + sampling_percentage = traits.Either( + traits.Range(low=0.0, high=1.0), + requires=['metric'], mandatory=True, + desc='Percentage of points accessible to the sampling strategy over which ' + 'to optimize the metric.' + ) + fixed_image_mask = File( + exists=True, argstr='%s', + desc='mask used to limit metric sampling region of the fixed image', + ) + moving_image_mask = File( + exists=True, requires=['fixed_image_mask'], + desc='mask used to limit metric sampling region of the moving image', + ) + + +class MeasureImageSimilarityOutputSpec(TraitedSpec): + similarity = traits.Float() + + +class MeasureImageSimilarity(ANTSCommand): + """ + + + Examples + -------- + + >>> from nipype.interfaces.ants import MeasureImageSimilarity + >>> sim = MeasureImageSimilarity() + >>> sim.inputs.dimension = 3 + >>> sim.inputs.metric = 'MI' + >>> sim.inputs.fixed_image = 'T1.nii' + >>> sim.inputs.moving_image = 'resting.nii' + >>> sim.inputs.metric_weight = 1.0 + >>> sim.inputs.radius_or_number_of_bins = 5 + >>> sim.inputs.sampling_strategy = 'Regular' + >>> sim.inputs.sampling_percentage = 1.0 + >>> sim.inputs.fixed_image_mask = 'mask.nii' + >>> sim.inputs.moving_image_mask = 'mask.nii.gz' + >>> sim.cmdline # doctest: +ALLOW_UNICODE + u'MeasureImageSimilarity --dimensionality 3 --masks ["mask.nii","mask.nii.gz"] \ +--metric MI["T1.nii","resting.nii",1.0,5,Regular,1.0]' + """ + _cmd = 'MeasureImageSimilarity' + input_spec = MeasureImageSimilarityInputSpec + output_spec = MeasureImageSimilarityOutputSpec + + def _metric_constructor(self): + retval = '--metric {metric}["{fixed_image}","{moving_image}",{metric_weight},'\ + '{radius_or_number_of_bins},{sampling_strategy},{sampling_percentage}]'\ + .format( + metric=self.inputs.metric, + fixed_image=self.inputs.fixed_image, + moving_image=self.inputs.moving_image, + metric_weight=self.inputs.metric_weight, + radius_or_number_of_bins=self.inputs.radius_or_number_of_bins, + sampling_strategy=self.inputs.sampling_strategy, + sampling_percentage=self.inputs.sampling_percentage, + ) + return retval + + def _mask_constructor(self): + if self.inputs.moving_image_mask: + retval = '--masks ["{fixed_image_mask}","{moving_image_mask}"]'\ + .format( + fixed_image_mask=self.inputs.fixed_image_mask, + moving_image_mask=self.inputs.moving_image_mask, + ) + else: + retval = '--masks "{fixed_image_mask}"'\ + .format( + fixed_image_mask=self.inputs.fixed_image_mask, + ) + return retval + + def _format_arg(self, opt, spec, val): + if opt == 'metric': + return self._metric_constructor() + elif opt == 'fixed_image_mask': + return self._mask_constructor() + return super(MeasureImageSimilarity, self)._format_arg(opt, spec, val) + + def aggregate_outputs(self, runtime=None, needed_outputs=None): + outputs = self._outputs() + stdout = runtime.stdout.split('\n') + outputs.similarity = float(stdout[0]) + return outputs diff --git a/nipype/interfaces/ants/tests/test_auto_MeasureImageSimilarity.py b/nipype/interfaces/ants/tests/test_auto_MeasureImageSimilarity.py new file mode 100644 index 0000000000..3dba65d8bb --- /dev/null +++ b/nipype/interfaces/ants/tests/test_auto_MeasureImageSimilarity.py @@ -0,0 +1,61 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..registration import MeasureImageSimilarity + + +def test_MeasureImageSimilarity_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + dimension=dict(argstr='--dimensionality %d', + position=1, + ), + environ=dict(nohash=True, + usedefault=True, + ), + fixed_image=dict(mandatory=True, + ), + fixed_image_mask=dict(argstr='%s', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + metric=dict(argstr='%s', + mandatory=True, + ), + metric_weight=dict(requires=['metric'], + usedefault=True, + ), + moving_image=dict(mandatory=True, + ), + moving_image_mask=dict(requires=['fixed_image_mask'], + ), + num_threads=dict(nohash=True, + usedefault=True, + ), + radius_or_number_of_bins=dict(mandatory=True, + requires=['metric'], + ), + sampling_percentage=dict(mandatory=True, + requires=['metric'], + ), + sampling_strategy=dict(requires=['metric'], + usedefault=True, + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = MeasureImageSimilarity.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value + + +def test_MeasureImageSimilarity_outputs(): + output_map = dict(similarity=dict(), + ) + outputs = MeasureImageSimilarity.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value