@@ -570,3 +570,87 @@ def _list_outputs(self):
570
570
'subjectToTemplateLogJacobian.' +
571
571
self .inputs .image_suffix )
572
572
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