@@ -570,3 +570,87 @@ def _list_outputs(self):
570570 'subjectToTemplateLogJacobian.' +
571571 self .inputs .image_suffix )
572572 return outputs
573+
574+ class JointFusionInputSpec (ANTSCommandInputSpec ):
575+ dimension = traits .Enum (3 , 2 , 4 , argstr = '%d' , position = 0 , usedefault = True , mandatory = True ,
576+ desc = 'image dimension (2, 3, or 4)' )
577+ modalities = traits .Int (argstr = '%d' , position = 1 , mandatory = True , desc = 'Number of modalities or features' )
578+ warped_intensity_images = InputMultiPath (File (exists = True ), argstr = "-g %s..." , mandatory = True , desc = 'Warped atlas images' )
579+ target_image = InputMultiPath (File (exists = True ), argstr = '-tg %s...' , mandatory = True , desc = 'Target image(s)' )
580+ warped_label_images = InputMultiPath (File (exists = True ), argstr = "-l %s..." , mandatory = True , desc = 'Warped atlas segmentations' )
581+ method = traits .Str (default = 'Joint' , argstr = '-m %s' , usedefault = True , desc = 'Select voting method. Options: Joint (Joint Label Fusion). May be followed by optional parameters in brackets, e.g., -m Joint[0.1,2]' )
582+ alpha = traits .Float (default = 0.1 , usedefault = True , requires = ['method' ], desc = 'Regularization term added to matrix Mx for inverse' )
583+ beta = traits .Int (default = 2 , usedefault = True , requires = ['method' ], desc = 'Exponent for mapping intensity difference to joint error' )
584+ output_label_image = File (argstr = '%s' , mandatory = True , position = - 1 , desc = 'Output fusion label map image' )
585+ patch_radius = traits .ListInt (minlen = 3 , maxlen = 3 , argstr = '-rp %s' , desc = 'Patch radius for similarity measures, scalar or vector. Default: 2x2x2' )
586+ search_radius = traits .ListInt (minlen = 3 , maxlen = 3 , argstr = '-rs %s' , desc = 'Local search radius. Default: 3x3x3' )
587+ exclusion_region = File (exists = True , argstr = '-x %s' , desc = 'Specify an exclusion region for the given label.' )
588+ output_posteriors_name_template = traits .Str ('POSTERIOR_%02d.nii.gz' , argstr = '-p %s' ,
589+ desc = "Save the posterior maps (probability that each voxel belongs to each " + \
590+ "label) as images. The number of images saved equals the number of labels. " + \
591+ "The filename pattern must be in C printf format, e.g. posterior%04d.nii.gz" )
592+ output_voting_weights_name_template = traits .Str ('WEIGHTED_%04d.nii.gz' , argstr = '-w %s' , desc = "Save the voting weights as " + \
593+ "images. The number of images saved equals the number of atlases. The " + \
594+ "filename pattern must be in C printf format, e.g. weight%04d.nii.gz" )
595+ atlas_group_id = traits .ListInt (argstr = '-gp %d...' , desc = 'Assign a group ID for each atlas' )
596+ atlas_group_weights = traits .ListInt (argstr = '-gpw %d...' , desc = 'Assign the voting weights to each atlas group' )
597+
598+
599+ class JointFusionOutputSpec (TraitedSpec ):
600+ output_label_image = File (exists = True )
601+ # TODO: optional outputs - output_posteriors, output_voting_weights
602+
603+
604+ class JointFusion (ANTSCommand ):
605+ """
606+ Examples
607+ --------
608+
609+ >>> from nipype.interfaces.ants import JointFusion
610+ >>> at = JointFusion()
611+ >>> at.inputs.dimension = 3
612+ >>> at.inputs.modalities = 1
613+ >>> at.inputs.method = 'Joint[0.1,2]'
614+ >>> at.inputs.output_label_image ='fusion_labelimage_output.nii'
615+ >>> at.inputs.warped_intensity_images = ['im1.nii',
616+ ... 'im2.nii']
617+ >>> at.inputs.warped_label_images = ['segmentation0.nii.gz',
618+ ... 'segmentation1.nii.gz']
619+ >>> at.inputs.target_image = 'T1.nii'
620+ >>> at.inputs.patch_radius = [3,2,1]
621+ >>> at.inputs.search_radius = [1,2,3]
622+ >>> at.cmdline
623+ 'jointfusion 3 1 -m Joint[0.1,2] -rp 3x2x1 -rs 1x2x3 -tg T1.nii -g im1.nii -g im2.nii -l segmentation0.nii.gz -l segmentation1.nii.gz fusion_labelimage_output.nii'
624+
625+ Alternately, you can specify the voting method and parameters more 'Pythonically':
626+
627+ >>> at.inputs.method = 'Joint'
628+ >>> at.inputs.alpha = 0.5
629+ >>> at.inputs.beta = 1
630+ >>> at.cmdline
631+ 'jointfusion 3 1 -m Joint[0.5,1] -rp 3x2x1 -rs 1x2x3 -tg T1.nii -g im1.nii -g im2.nii -l segmentation0.nii.gz -l segmentation1.nii.gz fusion_labelimage_output.nii'
632+ """
633+ input_spec = JointFusionInputSpec
634+ output_spec = JointFusionOutputSpec
635+ _cmd = 'jointfusion'
636+
637+ def _format_arg (self , opt , spec , val ):
638+ if opt == 'method' :
639+ if '[' in val :
640+ retval = '-m {0}' .format (val )
641+ else :
642+ retval = '-m {0}[{1},{2}]' .format (self .inputs .method , self .inputs .alpha , self .inputs .beta )
643+ elif opt == 'patch_radius' :
644+ retval = '-rp {0}' .format (self ._format_xarray (val ))
645+ elif opt == 'search_radius' :
646+ retval = '-rs {0}' .format (self ._format_xarray (val ))
647+ else :
648+ if opt == 'warped_intensity_images' :
649+ assert len (val ) == len (self .inputs .warped_label_images ), "Number of intensity images and label maps must be the same"
650+ return super (ANTSCommand , self )._format_arg (opt , spec , val )
651+ return retval
652+
653+ def _list_outputs (self ):
654+ outputs = self ._outputs ().get ()
655+ outputs ['output_label_image' ] = os .path .abspath (self .inputs .output_label_image )
656+ return outputs
0 commit comments