add GenerateSamplingReference to niworkflows
@@ -12,6 +12,8 @@ import os
import shutil
import numpy as np
import nibabel as nb
+import nilearn.image as nli
+
from .. import __version__
from ..nipype import logging
from niworkflows.nipype.utils.filemanip import fname_presuffix
@@ -112,6 +114,35 @@ class NormalizeMotionParams(SimpleInterface):
return runtime
+class GenerateSamplingReferenceInputSpec(BaseInterfaceInputSpec):
+ fixed_image = File(exists=True, mandatory=True, desc='the reference file')
+ moving_image = File(exists=True, mandatory=True, desc='the pixel size reference')
+ xform_code = traits.Enum(None, 2, 4, usedefault=True,
+ desc='force xform code')
+
+
+class GenerateSamplingReferenceOutputSpec(TraitedSpec):
+ out_file = File(exists=True, desc='one file with all inputs flattened')
+
+
+class GenerateSamplingReference(SimpleInterface):
+ """
+ Generates a reference grid for resampling one image keeping original resolution,
+ but moving data to a different space (e.g. MNI)
+ """
+
+ input_spec = GenerateSamplingReferenceInputSpec
+ output_spec = GenerateSamplingReferenceOutputSpec
+
+ def _run_interface(self, runtime):
+ self._results['out_file'] = _gen_reference(
+ self.inputs.fixed_image,
+ self.inputs.moving_image,
+ force_xform_code=self.inputs.xform_code,
+ message='%s of niworkflows v%s' % (self.__class__.__name__, __version__))
+ return runtime
+
+
def _copyxform(ref_image, out_image, message=None):
# Read in reference and output
resampled = nb.load(out_image)
@@ -132,3 +163,44 @@ def _copyxform(ref_image, out_image, message=None):
newimg = resampled.__class__(resampled.get_data(), orig.affine, header)
newimg.to_filename(out_image)
+
+
+def _gen_reference(fixed_image, moving_image, out_file=None, message=None,
+ force_xform_code=None):
+ """
+ Generates a sampling reference, and makes sure xform matrices/codes are
+ correct
+ """
+
+ if out_file is None:
+ out_file = fname_presuffix(fixed_image,
+ suffix='_reference',
+ newpath=os.getcwd())
+
+ new_zooms = nli.load_img(moving_image).header.get_zooms()[:3]
+ # Avoid small differences in reported resolution to cause changes to
+ # FOV. See https://github.com/poldracklab/fmriprep/issues/512
+ new_zooms_round = np.round(new_zooms, 3)
+
+ resampled = nli.resample_img(fixed_image,
+ target_affine=np.diag(new_zooms_round),
+ interpolation='nearest')
+
+ xform = resampled.affine # nibabel will pick the best affine
+ _, qform_code = resampled.header.get_qform(coded=True)
+ _, sform_code = resampled.header.get_sform(coded=True)
+
+ xform_code = sform_code if sform_code > 0 else qform_code
+ if xform_code == 1:
+ xform_code = 2
+
+ if force_xform_code is not None:
+ xform_code = force_xform_code
+
+ # Keep 0, 2, 3, 4 unchanged
+ resampled.header.set_qform(xform, xform_code)
+ resampled.header.set_sform(xform, xform_code)
+ resampled.header['descrip'] = 'reference image generated by %s.' % (
+ message or '(unknown software)')
+ resampled.to_filename(out_file)
+ return out_file
