From 309da9517e0cb534aa88f44e0e658e68c84c1e42 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Sun, 21 Jul 2019 16:31:20 +0100 Subject: [PATCH] ENH: New fsl_apply_x5 script, to apply a X5 transformation to an image --- fsl/scripts/fsl_apply_x5.py | 135 ++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 fsl/scripts/fsl_apply_x5.py diff --git a/fsl/scripts/fsl_apply_x5.py b/fsl/scripts/fsl_apply_x5.py new file mode 100644 index 000000000..8128ec348 --- /dev/null +++ b/fsl/scripts/fsl_apply_x5.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# +# fsl_apply_x5.py - Apply an X5 transformation to an image. +# +# Author: Paul McCarthy <pauldmccarthy@gmail.com> +# +"""The ``fsl_apply_x5`` script can be used to apply an X5 transformation file +to resample an image. +""" + + +import functools as ft +import sys +import argparse + +import fsl.transform.x5 as x5 +import fsl.transform.nonlinear as nonlinear +import fsl.utils.parse_data as parse_data +import fsl.utils.image.resample as resample +import fsl.data.image as fslimage + + +def parseArgs(args=None): + """Parses command-line arguments. + + :arg args: Sequence of command-line arguments. If ``None``, ``sys.argv`` + is used + :returns: An ``argparse.Namespace`` object containing parsed arguments + """ + + parser = argparse.ArgumentParser('fsl_apply_x5') + flags = { + 'input' : ('input',), + 'xform' : ('xform',), + 'output' : ('output',), + 'interp' : ('-i', '--interp'), + 'ref' : ('-r', '--ref'), + } + + helps = { + 'input' : 'Input image', + 'xform' : 'X5 transformation file', + 'output' : 'Output image', + 'interp' : 'Interpolation (default: linear)', + 'ref' : 'Alternate reference image (default: ' + 'reference specified in X5 file)', + } + opts = { + 'input' : dict(helps['input'], + type=parse_data.Image), + 'xform' : dict(helps['xform']), + 'output' : dict(helps['output'], + type=parse_data.ImageOut), + 'interp' : dict(helps['interp'], + choices=('nearest', 'linear', 'cubic'), + default='linear'), + 'ref' : dict(helps['ref'], + type=ft.partial(parse_data.Image, loadData=False)), + } + + parser.add_argument(*flags['input'], **opts['input']) + parser.add_argument(*flags['xform'], **opts['xform']) + parser.add_argument(*flags['output'], **opts['output']) + parser.add_argument(*flags['interp'], **opts['interp']) + parser.add_argument(*flags['ref'], **opts['ref']) + + args = parser.parse_args(args) + + if args.interp == 'nearest': args.interp = 0 + elif args.interp == 'linear': args.interp = 1 + elif args.interp == 'cubic': args.interp = 3 + + return args + + +def applyLinear(args): + """Applies a linear X5 transformation file to the input. + + :arg args: ``argparse.Namespace`` object + :returns: The transformed input as an :class:`.Image` object + """ + + input = args.input + xform, src, ref = x5.readLinearX5(args.xform) + + if args.ref is not None: + ref = args.ref + + res, xform = resample.resampleToReference(input, + ref, + matrix=xform, + order=args.interp) + + return fslimage.Image(res, xform=xform, header=ref.header) + + +def applyNonlinear(args): + """Applies a non-linear X5 transformation file to the input. + + :arg args: ``argparse.Namespace`` object + :returns: The transformed input as an :class:`.Image` object + """ + + field = x5.readNonLinearX5(args.xform) + + if args.ref is None: ref = field.ref + else: ref = args.ref + + result = nonlinear.applyDeformation(args.input, + field, + ref=ref, + order=args.interp, + mode='constant') + + return fslimage.Image(result, header=ref.header) + + +def main(args=None): + """Entry point. Parse command-line arguments, then calls + :func:`applyLinear` or :func:`applyNonlinear` depending on the x5 file + type. + """ + + args = parseArgs(args) + + if x5.inferType(args.xform) == 'linear': + result = applyLinear(args) + else: + result = applyNonlinear(args) + + result.save(args.output) + + +if __name__ == '__main__': + sys.exit(main()) -- GitLab