nipype.interfaces.mixins.fixheader module¶
CopyHeaderInterface¶
Bases: BaseInterface
Copy headers if the copy_header input is
True
This interface mixin adds a post-run hook that allows for copying an input header to an output file. The subclass should specify a
_copy_header_map
that maps the output image to the input image whose header should be copied.This feature is intended for tools that are intended to adjust voxel data without modifying the header, but for some reason do not reliably preserve the header.
Here we show an example interface that takes advantage of the mixin by simply setting the data block:
>>> import os >>> import numpy as np >>> import nibabel as nb >>> from nipype.interfaces.base import SimpleInterface, TraitedSpec, File >>> from nipype.interfaces.mixins import CopyHeaderInputSpec, CopyHeaderInterface>>> class ZerofileInputSpec(CopyHeaderInputSpec): ... in_file = File(mandatory=True, exists=True)>>> class ZerofileOutputSpec(TraitedSpec): ... out_file = File()>>> class ZerofileInterface(SimpleInterface, CopyHeaderInterface): ... input_spec = ZerofileInputSpec ... output_spec = ZerofileOutputSpec ... _copy_header_map = {'out_file': 'in_file'} ... ... def _run_interface(self, runtime): ... img = nb.load(self.inputs.in_file) ... # Just set the data. Let the CopyHeaderInterface mixin fix the affine and header. ... nb.Nifti1Image(np.zeros(img.shape, dtype=np.uint8), None).to_filename('out.nii') ... self._results = {'out_file': os.path.abspath('out.nii')} ... return runtimeConsider a file of all ones and a non-trivial affine:
>>> in_file = 'test.nii' >>> nb.Nifti1Image(np.ones((5,5,5), dtype=np.int16), ... affine=np.diag((4, 3, 2, 1))).to_filename(in_file)The default behavior would produce a file with similar data:
>>> res = ZerofileInterface(in_file=in_file).run() >>> out_img = nb.load(res.outputs.out_file) >>> out_img.shape (5, 5, 5) >>> np.all(out_img.get_fdata() == 0) TrueAn updated data type:
>>> out_img.get_data_dtype() dtype('uint8')But a different affine:
>>> np.array_equal(out_img.affine, np.diag((4, 3, 2, 1))) FalseWith
copy_header=True
, then the affine is also equal:>>> res = ZerofileInterface(in_file=in_file, copy_header=True).run() >>> out_img = nb.load(res.outputs.out_file) >>> np.array_equal(out_img.affine, np.diag((4, 3, 2, 1))) TrueThe data properties remain as expected:
>>> out_img.shape (5, 5, 5) >>> out_img.get_data_dtype() dtype('uint8') >>> np.all(out_img.get_fdata() == 0) TrueBy default, the data type of the output file is permitted to vary from the inputs. That is, the data type is preserved. If the data type of the original file is preferred, the
_copy_header_map
can indicate the output data type should not be preserved by providing a tuple of the input andFalse
.>>> ZerofileInterface._copy_header_map['out_file'] = ('in_file', False)>>> res = ZerofileInterface(in_file=in_file, copy_header=True).run() >>> out_img = nb.load(res.outputs.out_file) >>> out_img.get_data_dtype() dtype('<i2')Again, the affine is updated.
>>> np.array_equal(out_img.affine, np.diag((4, 3, 2, 1))) True >>> out_img.shape (5, 5, 5) >>> np.all(out_img.get_fdata() == 0) TrueProviding a tuple where the second value is
True
is also permissible to achieve the default behavior.