Skip to content

Commit f383af2

Browse files
committed
ENH: Add mri_coreg interface
1 parent 32e724c commit f383af2

File tree

3 files changed

+244
-1
lines changed

3 files changed

+244
-1
lines changed

nipype/interfaces/freesurfer/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@
2424
RelabelHypointensities, Aparc2Aseg, Apas2Aseg, MRIsExpand, MRIsCombine)
2525
from .longitudinal import (RobustTemplate, FuseSegmentations)
2626
from .registration import (MPRtoMNI305, RegisterAVItoTalairach, EMRegister, Register,
27-
Paint)
27+
Paint, MRICoreg)

nipype/interfaces/freesurfer/registration.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,145 @@ def _list_outputs(self):
338338
outputs = self.output_spec().get()
339339
outputs['out_file'] = os.path.abspath(self.inputs.out_file)
340340
return outputs
341+
342+
343+
class MRICoregInputSpec(FSTraitedSpec):
344+
source_file = File(argstr='--mov %s', desc='source file to be registered',
345+
mandatory=True, copyfile=False)
346+
reference_file = File(argstr='--ref %s', desc='reference (target) file',
347+
mandatory=True, copyfile=False)
348+
out_lta_file = traits.Either(True, File, argstr='--lta %s', default=True,
349+
usedefault=True,
350+
desc='output registration file (LTA format)')
351+
out_reg_file = traits.Either(True, File, argstr='--regdat %s',
352+
desc='output registration file (REG format)')
353+
out_params_file = traits.Either(True, File, argstr='--params %s',
354+
desc='output parameters file')
355+
356+
subjects_dir = Directory(exists=True, argstr='--sd %s',
357+
desc='FreeSurfer SUBJECTS_DIR')
358+
subject_id = traits.Str(
359+
argstr='--s %s', position=1,
360+
desc='freesurfer subject ID (implies ``reference_mask == '
361+
'aparc+aseg.mgz`` unless otherwise specified)')
362+
dof = traits.Enum(6, 9, 12, argstr='--dof %d',
363+
desc='number of transform degrees of freedom')
364+
reference_mask = traits.Either(
365+
False, traits.Str, argstr='--ref-mask %s', position=2,
366+
desc='mask reference volume with given mask, or None if ``False``')
367+
source_mask = traits.Str(argstr='--mov-mask',
368+
desc='mask source file with given mask')
369+
num_threads = traits.Int(argstr='--threads %d',
370+
desc='number of OpenMP threads')
371+
no_coord_dithering = traits.Bool(argstr='--no-coord-dither',
372+
desc='turn off coordinate dithering')
373+
no_intensity_dithering = traits.Bool(argstr='--no-intensity-dither',
374+
desc='turn off intensity dithering')
375+
# Skipping: --sep
376+
initial_translation = traits.Tuple(
377+
traits.Float, traits.Float, traits.Float, argstr='--trans %g %g %g',
378+
desc='initial translation in mm (implies no_cras0)')
379+
initial_rotation = traits.Tuple(
380+
traits.Float, traits.Float, traits.Float, argstr='--rot %g %g %g',
381+
desc='initial rotation in degrees')
382+
initial_scale = traits.Tuple(
383+
traits.Float, traits.Float, traits.Float, argstr='--scale %g %g %g',
384+
desc='initial scale')
385+
initial_shear = traits.Tuple(
386+
traits.Float, traits.Float, traits.Float, argstr='--shear %g %g %g',
387+
desc='initial shear (Hxy, Hxz, Hyz)')
388+
no_cras0 = traits.Bool(argstr='--no-cras0',
389+
desc='do not set translation parameters to align '
390+
'centers of source and reference files')
391+
max_iters = traits.Range(low=1, argstr='--nitersmax %d',
392+
desc='maximum iterations (default: 4)')
393+
ftol = traits.Float(argstr='--ftol %e',
394+
desc='floating-point tolerance (default=1e-7)')
395+
linmintol = traits.Float(argstr='--linmintol %e')
396+
saturation_threshold = traits.Range(
397+
low=0.0, high=100.0, argstr='--sat %g',
398+
desc='saturation threshold (default=9.999)')
399+
conform_reference = traits.Bool(argstr='--conf-ref',
400+
desc='conform reference without rescaling')
401+
no_brute_force = traits.Bool(argstr='--no-bf',
402+
desc='do not brute force search')
403+
brute_force_limit = traits.Float(
404+
argstr='--bf-lim %g', xor=['no_brute_force'],
405+
desc='constrain brute force search to +/- lim')
406+
brute_force_samples = traits.Int(
407+
argstr='--bf-nsamp %d', xor=['no_brute_force'],
408+
desc='number of samples in brute force search')
409+
no_smooth = traits.Bool(
410+
argstr='--no-smooth',
411+
desc='do not apply smoothing to either reference or source file')
412+
ref_fwhm = traits.Float(argstr='--ref-fwhm',
413+
desc='apply smoothing to reference file')
414+
source_oob = traits.Bool(
415+
argstr='--mov-oob',
416+
desc='count source voxels that are out-of-bounds as 0')
417+
# Skipping mat2par
418+
419+
420+
class MRICoregOutputSpec(TraitedSpec):
421+
out_reg_file = File(exists=True, desc='output registration file')
422+
out_lta_file = File(exists=True, desc='output LTA-style registration file')
423+
out_params_file = File(exists=True, desc='output parameters file')
424+
425+
426+
class MRICoreg(FSCommand):
427+
""" This program registers one volume to another
428+
429+
mri_coreg is a C reimplementation of spm_coreg in FreeSurfer
430+
431+
Examples
432+
========
433+
>>> from nipype.interfaces.freesurfer import MRICoreg
434+
>>> coreg = MRICoreg()
435+
>>> coreg.inputs.source_file = 'moving1.nii'
436+
>>> coreg.inputs.reference_file = 'fixed1.nii'
437+
>>> coreg.inputs.subjects_dir = '.'
438+
>>> coreg.cmdline # doctest: +ALLOW_UNICODE +ELLIPSIS
439+
'mri_coreg --lta .../registration.lta --ref fixed1.nii --mov moving1.nii --sd .'
440+
441+
If passing a subject ID, the reference mask may be disabled:
442+
443+
>>> coreg.inputs.subject_id = 'fsaverage'
444+
>>> coreg.inputs.reference_mask = False
445+
>>> coreg.cmdline # doctest: +ALLOW_UNICODE +ELLIPSIS
446+
'mri_coreg --s fsaverage --no-ref-mask --lta .../registration.lta --ref fixed1.nii --mov moving1.nii --sd .'
447+
"""
448+
449+
_cmd = 'mri_coreg'
450+
input_spec = MRICoregInputSpec
451+
output_spec = MRICoregOutputSpec
452+
453+
def _format_arg(self, opt, spec, val):
454+
if opt in ('out_reg_file', 'out_lta_file',
455+
'out_params_file') and val is True:
456+
val = self._list_outputs()[opt]
457+
elif opt == 'reference_mask' and val is False:
458+
return '--no-ref-mask'
459+
return super(MRICoreg, self)._format_arg(opt, spec, val)
460+
461+
def _list_outputs(self):
462+
outputs = self.output_spec().get()
463+
464+
out_lta_file = self.inputs.out_lta_file
465+
if isdefined(out_lta_file):
466+
if out_lta_file is True:
467+
out_lta_file = 'registration.lta'
468+
outputs['out_lta_file'] = os.path.abspath(out_lta_file)
469+
470+
out_reg_file = self.inputs.out_reg_file
471+
if isdefined(out_reg_file):
472+
if out_reg_file is True:
473+
out_reg_file = 'registration.dat'
474+
outputs['out_reg_file'] = os.path.abspath(out_reg_file)
475+
476+
out_params_file = self.inputs.out_params_file
477+
if isdefined(out_params_file):
478+
if out_params_file is True:
479+
out_params_file = 'registration.par'
480+
outputs['out_params_file'] = os.path.abspath(out_params_file)
481+
482+
return outputs
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from __future__ import unicode_literals
3+
from ..registration import MRICoreg
4+
5+
6+
def test_MRICoreg_inputs():
7+
input_map = dict(args=dict(argstr='%s',
8+
),
9+
brute_force_limit=dict(argstr='--bf-lim %g',
10+
xor=['no_brute_force'],
11+
),
12+
brute_force_samples=dict(argstr='--bf-nsamp %d',
13+
xor=['no_brute_force'],
14+
),
15+
conform_reference=dict(argstr='--conf-ref',
16+
),
17+
dof=dict(argstr='--dof %d',
18+
),
19+
environ=dict(nohash=True,
20+
usedefault=True,
21+
),
22+
ftol=dict(argstr='--ftol %e',
23+
),
24+
ignore_exception=dict(nohash=True,
25+
usedefault=True,
26+
),
27+
initial_rotation=dict(argstr='--rot %g %g %g',
28+
),
29+
initial_scale=dict(argstr='--scale %g %g %g',
30+
),
31+
initial_shear=dict(argstr='--shear %g %g %g',
32+
),
33+
initial_translation=dict(argstr='--trans %g %g %g',
34+
),
35+
linmintol=dict(argstr='--linmintol %e',
36+
),
37+
max_iters=dict(argstr='--nitersmax %d',
38+
),
39+
no_brute_force=dict(argstr='--no-bf',
40+
),
41+
no_coord_dithering=dict(argstr='--no-coord-dither',
42+
),
43+
no_cras0=dict(argstr='--no-cras0',
44+
),
45+
no_intensity_dithering=dict(argstr='--no-intensity-dither',
46+
),
47+
no_smooth=dict(argstr='--no-smooth',
48+
),
49+
num_threads=dict(argstr='--threads %d',
50+
),
51+
out_lta_file=dict(argstr='--lta %s',
52+
usedefault=True,
53+
),
54+
out_params_file=dict(argstr='--params %s',
55+
),
56+
out_reg_file=dict(argstr='--regdat %s',
57+
),
58+
ref_fwhm=dict(argstr='--ref-fwhm',
59+
),
60+
reference_file=dict(argstr='--ref %s',
61+
copyfile=False,
62+
mandatory=True,
63+
),
64+
reference_mask=dict(argstr='--ref-mask %s',
65+
position=2,
66+
),
67+
saturation_threshold=dict(argstr='--sat %g',
68+
),
69+
source_file=dict(argstr='--mov %s',
70+
copyfile=False,
71+
mandatory=True,
72+
),
73+
source_mask=dict(argstr='--mov-mask',
74+
),
75+
source_oob=dict(argstr='--mov-oob',
76+
),
77+
subject_id=dict(argstr='--s %s',
78+
position=1,
79+
),
80+
subjects_dir=dict(argstr='--sd %s',
81+
),
82+
terminal_output=dict(nohash=True,
83+
),
84+
)
85+
inputs = MRICoreg.input_spec()
86+
87+
for key, metadata in list(input_map.items()):
88+
for metakey, value in list(metadata.items()):
89+
assert getattr(inputs.traits()[key], metakey) == value
90+
91+
92+
def test_MRICoreg_outputs():
93+
output_map = dict(out_lta_file=dict(),
94+
out_params_file=dict(),
95+
out_reg_file=dict(),
96+
)
97+
outputs = MRICoreg.output_spec()
98+
99+
for key, metadata in list(output_map.items()):
100+
for metakey, value in list(metadata.items()):
101+
assert getattr(outputs.traits()[key], metakey) == value

0 commit comments

Comments
 (0)