Skip to content

Proposal: affine_source (or header_source) in output File traits #2223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
effigies opened this issue Oct 10, 2017 · 1 comment
Open

Proposal: affine_source (or header_source) in output File traits #2223

effigies opened this issue Oct 10, 2017 · 1 comment

Comments

@effigies
Copy link
Member

Several packages handle NIfTI headers with insufficient reverence, ending up with affines that don't really match the expected result of an operation. For example, AFNI converts NIfTI to BRIK+HEAD, performs its operation, and makes a somewhat wild stab at the correct qform/sform codes based on an environment variable, so operations that don't move the data might still change the affine. ANTs' dependence on ITK means they don't recognize sforms as legitimate. Meanwhile the standard's order of precedence (sform > qform > pixdims) means that only updating the sform is fairly common practice by still other software (I believe FSL only updates sforms).

All of this means that mixing and matching these tools, one of the primary use-cases of nipype, can result in some profound disagreements of how the same input file is aligned and how to write a header in the output file. In practice this can mean that two files with the same affine (as far as the standard is concerned), with the same transform applied by the same software can end up misaligned.

While an incomplete solution for qforms/sforms that get out of sync, at least preventing affine corruption would be a start to handling issues like this. We have addressed this previously in N4BiasFieldCorrection (#2034), but a consistent interface across tools would be very useful.

I propose:

class XInputSpec(BaseInterfaceSpec):
    ref_file = File(desc='file defining target space')

class XOutputSpec(TraitedSpec):
    out_file = File(affine_source=['ref_file'], desc='output file in target space')

A post-run hook would then copy the affines from inputs.ref_file to outputs.out_file, with the following:

try:
    ref_img = nib.load(ref_file)
    out_img = nib.load(out_file)
    affine = ref_img.afffine
    new_img = out_img.__class__(out_img.dataobj, affine, out_img.header)
except:
    iflogger.warn("Could not copy affine!")
try:
    sform, sform_code = ref_img.header.get_sform(coded=True)
    qform, qform_code = ref_img.header.get_qform(coded=True)
    new_img.header.set_sform(sform, sform_code)
    new_img.header.set_qform(qform, qform_code)
except:
    # Input file or output file is not NIfTI
    pass
new_img.to_filename(out_file)
@oesteban
Copy link
Contributor

+1

I was talking of the same solution here with Ross last week, and then confirmed with what I understood from @satra in his reply to #2218

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants