From 65a51503713685764497e7d5f47c139d49c50314 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauldmccarthy@gmail.com>
Date: Sun, 21 Jul 2019 14:32:36 +0100
Subject: [PATCH] ENH: parse_data.Image allows additional Image.__init__
 arguments to be passed. Used by fsl_convert_x5

---
 fsl/scripts/fsl_convert_x5.py | 42 ++++++++++++++++++++---------------
 fsl/transform/x5.py           | 20 ++++++++++++++++-
 fsl/utils/parse_data.py       | 12 ++++++----
 3 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/fsl/scripts/fsl_convert_x5.py b/fsl/scripts/fsl_convert_x5.py
index 33f063c15..f7bf84981 100644
--- a/fsl/scripts/fsl_convert_x5.py
+++ b/fsl/scripts/fsl_convert_x5.py
@@ -9,17 +9,18 @@ transformation file formats.
 """
 
 
-import os.path as       op
-import                  sys
-import                  shutil
-import                  logging
-import                  argparse
-from collections import OrderedDict
+import os.path   as op
+import functools as ft
+import              sys
+import              shutil
+import              logging
+import              argparse
 
-import fsl.data.image      as fslimage
-import fsl.transform.flirt as flirt
-import fsl.transform.fnirt as fnirt
-import fsl.transform.x5    as x5
+import fsl.data.image       as fslimage
+import fsl.utils.parse_data as parse_data
+import fsl.transform.flirt  as flirt
+import fsl.transform.fnirt  as fnirt
+import fsl.transform.x5     as x5
 
 
 log = logging.getLogger(__name__)
@@ -49,11 +50,14 @@ def parseArgs(args):
     subparsers = parser.add_subparsers(dest='ctype')
     flirt      = subparsers.add_parser('flirt')
     fnirt      = subparsers.add_parser('fnirt')
+    imgtype    = ft.partial(parse_data.Image, loadData=False)
 
     flirt.add_argument('input',                  help=helps['input'])
     flirt.add_argument('output',                 help=helps['output'])
-    flirt.add_argument('-s',  '--source',        help=helps['source'])
-    flirt.add_argument('-r',  '--reference',     help=helps['reference'])
+    flirt.add_argument('-s',  '--source',        help=helps['source'],
+                       type=imgtype)
+    flirt.add_argument('-r',  '--reference',     help=helps['reference'],
+                       type=imgtype)
     flirt.add_argument('-if', '--input_format',  help=helps['input_format'],
                        choices=('x5', 'mat'))
     flirt.add_argument('-of', '--output_format', help=helps['output_format'],
@@ -61,8 +65,10 @@ def parseArgs(args):
 
     fnirt  .add_argument('input',                  help=helps['input'])
     fnirt  .add_argument('output',                 help=helps['output'])
-    fnirt  .add_argument('-s',  '--source',        help=helps['source'])
-    fnirt  .add_argument('-r',  '--reference',     help=helps['reference'])
+    fnirt  .add_argument('-s',  '--source',        help=helps['source'],
+                         type=imgtype)
+    fnirt  .add_argument('-r',  '--reference',     help=helps['reference'],
+                         type=imgtype)
     fnirt  .add_argument('-if', '--input_format',  help=helps['input_format'],
                          choices=('x5', 'nii'))
     fnirt  .add_argument('-of', '--output_format', help=helps['output_format'],
@@ -109,8 +115,8 @@ def flirtToX5(args):
     """Convert a linear FLIRT transformation matrix to an X5 transformation
     file.
     """
-    src   = fslimage.Image(args.source,    loadData=False)
-    ref   = fslimage.Image(args.reference, loadData=False)
+    src   = args.source
+    ref   = args.reference
     xform = flirt.readFlirt(args.input)
     xform = flirt.fromFlirt(xform, src, ref, 'world', 'world')
     x5.writeLinearX5(args.output, xform, src, ref)
@@ -127,8 +133,8 @@ def fnirtToX5(args):
     """Convert a non-linear FNIRT transformation into an X5 transformation
     file.
     """
-    src   = fslimage.Image(args.source,    loadData=False)
-    ref   = fslimage.Image(args.reference, loadData=False)
+    src   = args.source
+    ref   = args.reference
     field = fnirt.readFnirt(args.input, src=src, ref=ref)
     field = fnirt.fromFnirt(field, 'world', 'world')
     x5.writeNonLinearX5(args.output, field)
diff --git a/fsl/transform/x5.py b/fsl/transform/x5.py
index 5d25dced4..f14a165a0 100644
--- a/fsl/transform/x5.py
+++ b/fsl/transform/x5.py
@@ -10,6 +10,7 @@ transformations from/to BIDS X5 files. The following functions are available:
 .. autosummary::
    :nosignatures:
 
+   inferType
    readLinearX5
    writeLinearX5
    readNonLinearX5
@@ -339,6 +340,23 @@ class X5Error(Exception):
     pass
 
 
+def inferType(fname):
+    """Return the type of the given X5 file - either ``'linear'``or
+    ``'nonlinear'``.
+
+    :arg fname: Name of a X5 file
+    :returns:   ``'linear'``or ``'nonlinear'``
+    """
+    with h5py.File(fname, 'r') as f:
+
+        ftype = f.attrs.get('Type')
+
+        if ftype not in ('linear', 'nonlinear'):
+            raise X5Error('Unknown type: {}'.format(ftype))
+
+    return ftype
+
+
 def readLinearX5(fname):
     """Read a linear X5 transformation file from ``fname``.
 
@@ -565,7 +583,7 @@ def _readDeformation(group):
 
 
 def _writeDeformation(group, field):
-    """Write a deformation fieldto the given group.
+    """Write a deformation field to the given group.
 
     :arg group: A ``h5py.Group`` object
     :arg field: A :class:`.DeformationField` object
diff --git a/fsl/utils/parse_data.py b/fsl/utils/parse_data.py
index 20e51d752..1c16e97de 100644
--- a/fsl/utils/parse_data.py
+++ b/fsl/utils/parse_data.py
@@ -8,8 +8,9 @@
 
 Argparse is the built-in python library for resolving command line arguments.
 
-The functions in this module can be passed on to the ``type`` argument in the ``ArgumentParser.add_command`` method
-to interpret command line arguments as neuroimageing objects (.e.g, NIFTI image files)
+The functions in this module can be passed on to the ``type`` argument in the
+``ArgumentParser.add_command`` method to interpret command line arguments as
+neuroimaging objects (.e.g, NIFTI image files)
 
 
 .. autosummary::
@@ -27,18 +28,21 @@ from fsl.utils import path
 import argparse
 
 
-def Image(filename):
+def Image(filename, *args, **kwargs):
     """
     Reads in an image from a NIFTI or Analyze file.
 
     :arg filename: filename provided by the user
     :return: fsl.data.image.Image object
+
+    All other arguments are passed through to the :class:`.Image` upon
+    creation.
     """
     try:
         full_filename = image.addExt(filename)
     except path.PathError as e:
         raise argparse.ArgumentTypeError(*e.args)
-    return image.Image(full_filename)
+    return image.Image(full_filename, *args, **kwargs)
 
 
 def ImageOut(basename):
-- 
GitLab