Skip to content
Merged
2 changes: 1 addition & 1 deletion nipype/interfaces/freesurfer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
MRIFill, MRIsInflate, Sphere, FixTopology, EulerNumber,
RemoveIntersection, MakeSurfaces, Curvature, CurvatureStats,
Jacobian, MRIsCalc, VolumeMask, ParcellationStats, Contrast,
RelabelHypointensities, Aparc2Aseg, Apas2Aseg, MRIsExpand)
RelabelHypointensities, Aparc2Aseg, Apas2Aseg, MRIsExpand, MRIsCombine)
from .longitudinal import (RobustTemplate, FuseSegmentations)
from .registration import (MPRtoMNI305, RegisterAVItoTalairach, EMRegister, Register,
Paint)
46 changes: 46 additions & 0 deletions nipype/interfaces/freesurfer/tests/test_auto_MRIsCombine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
from __future__ import unicode_literals
from ..utils import MRIsCombine


def test_MRIsCombine_inputs():
input_map = dict(args=dict(argstr='%s',
),
environ=dict(nohash=True,
usedefault=True,
),
ignore_exception=dict(nohash=True,
usedefault=True,
),
in_file1=dict(argstr='--combinesurfs %s',
mandatory=True,
position=1,
),
in_file2=dict(argstr='%s',
mandatory=True,
position=2,
),
out_file=dict(argstr='%s',
genfile=True,
mandatory=True,
position=-1,
),
subjects_dir=dict(),
terminal_output=dict(nohash=True,
),
)
inputs = MRIsCombine.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_MRIsCombine_outputs():
output_map = dict(out_file=dict(),
)
outputs = MRIsCombine.output_spec()

for key, metadata in list(output_map.items()):
for metakey, value in list(metadata.items()):
assert getattr(outputs.traits()[key], metakey) == value
57 changes: 57 additions & 0 deletions nipype/interfaces/freesurfer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,63 @@ def _gen_outfilename(self):
return name + ext + "_converted." + self.inputs.out_datatype


class MRIsCombineInputSpec(FSTraitedSpec):
"""
Uses Freesurfer's mris_convert to combine two surface files into one.
"""
in_file1 = File(exists=True, mandatory=True, position=1,
argstr='--combinesurfs %s',
desc='File to be combined with in_file2')
in_file2 = File(exists=True, mandatory=True, position=2,
argstr='%s',
desc='File to be combined with in_file1')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you specifically want in_file1 and in_file2 ports? This could be made a list like so:

in_files = List(File(Exists=True), maxlen=2, minlen=2, mandatory=True, position=1, argstr='--combinesurfs %s', desc="...")

(I think. I'd check this syntax.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize traits.List allowed for maxlen and minlen. I definitely prefer it your way. Just tested it and it works, so I'll commit it in a second.

out_file = File(argstr='%s', position=-1, genfile=True,
mandatory=True,
desc='Output filename. Combined surfaces from in_file1 and '
'in_file2.')


class MRIsCombineOutputSpec(TraitedSpec):
"""
Uses Freesurfer's mris_convert to combine two surface files into one.
"""
out_file = File(exists=True, desc='Output filename. Combined surfaces from '
'in_file1 and in_file2.')


class MRIsCombine(FSCommand):
"""
Uses Freesurfer's mris_convert to combine two surface files into one.

For complete details, see the `mris_convert Documentation.
<https://surfer.nmr.mgh.harvard.edu/fswiki/mris_convert>`_

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here might be a good place to add a comment about outputs (so it shows up in the docs):

If given an out_file that does not begin with 'lh.' or 'rh.', mris_convert will prepend 'lh.' to the file name. To avoid this behavior, consider setting out_file = './<filename>', or leaving out_file blank. 
Example
-------

>>> import nipype.interfaces.freesurfer as fs
>>> mris = fs.MRIsCombine()
>>> mris.inputs.in_file1 = 'lh.pial'
>>> mris.inputs.in_file2 = 'rh.pial'
>>> mris.inputs.out_file = 'out.stl'
>>> mris.cmdline # doctest: +ALLOW_UNICODE
'mris_convert --combinesurfs lh.pial rh.pial out.stl'
>>> mris.run() # doctest: +SKIP
"""
_cmd = 'mris_convert'
input_spec = MRIsCombineInputSpec
output_spec = MRIsCombineOutputSpec

def _list_outputs(self):
outputs = self.output_spec().get()
if any(self.inputs.out_file.startswith(pre) for pre in ['lh.', 'rh.']):
outputs['out_file'] = self.inputs.out_file
else:
outputs['out_file'] = 'lh.' + self.inputs.out_file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For your doctest example, you're going to get lh.out.stl. Is that what mris_convert produces? And if so, is that the same whether you pass lh.pial or rh.pial as in_file1?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I've seen:

  • mris_convert --combinesurfs lh.pial rh.pial out.stl creates lh.out.stl
  • mris_convert --combinesurfs rh.pial lh.pial out.stl creates lh.out.stl
  • mris_convert --combinesurfs rh.pial rh.smoothwm out.stl creates lh.out.stl
  • mris_convert --combinesurfs lh.pial rh.pial rh.out.stl creates rh.out.stl

So it doesn't seem to matter what order you pass in the files or even if both files are from the right hemisphere. As long as the output file doesn't start with lh. or rh., it will prepend lh. to the output filename.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha. That's awful. Can you add a short comment explaining that this is a FreeSurfer behavior you're accommodating?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an explanation to the docstring for _list_outputs in a7bafda. Should be clear now.


return outputs


class MRITessellateInputSpec(FSTraitedSpec):
"""
Uses Freesurfer's mri_tessellate to create surfaces by tessellating a given input volume
Expand Down
Empty file added nipype/testing/data/rh.pial
Empty file.