Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
fslpy
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Analyze
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
FSL
fslpy
Commits
0f60a744
Commit
0f60a744
authored
5 years ago
by
Paul McCarthy
Browse files
Options
Downloads
Patches
Plain Diff
ENH: Fleshed out x5 implementation
parent
d3cf8335
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
fsl/transform/x5.py
+246
-101
246 additions, 101 deletions
fsl/transform/x5.py
with
246 additions
and
101 deletions
fsl/transform/x5.py
+
246
−
101
View file @
0f60a744
...
...
@@ -344,11 +344,89 @@ X5_FORMAT = 'X5'
X5_VERSION
=
'
0.0.1
'
class
InvalidFile
Error
(
Exception
):
class
X5
Error
(
Exception
):
"""
Error raised if an invalid/incompatible file is detected.
"""
pass
def
readLinearX5
(
fname
):
"""
Read a linear X5 transformation file from ``fname``.
:arg fname: File name to read from
:returns: A tuple containing:
- A ``(4, 4)`` ``numpy`` array containing the affine
transformation
- A :class:`.Nifti` instance representing the source space
- A :class:`.Nifti` instance representing the reference space
"""
with
h5py
.
File
(
fname
,
'
r
'
)
as
f
:
_validateMetadata
(
f
[
'
/
'
])
xform
=
_readAffine
(
f
[
'
/
'
])
src
=
_readSpace
(
f
[
'
/From
'
])
ref
=
_readSpace
(
f
[
'
/To
'
])
return
xform
,
src
,
ref
def
writeLinearX5
(
fname
,
xform
,
src
,
ref
):
"""
Write a linear transformation to the specified file.
:arg fname: File name to write to
:arg xform: ``(4, 4)`` ``numpy`` array containing the affine transformation
:arg src: :class:`.Nifti` image representing the source space
:arg ref: :class:`.Nifti` image representing the reference
"""
with
h5py
.
File
(
fname
,
'
w
'
)
as
f
:
_writeMetadata
(
f
)
_writeAffine
(
f
,
xform
)
from_
=
f
.
create_group
(
'
/From
'
)
to
=
f
.
create_group
(
'
/To
'
)
_writeSpace
(
from_
,
src
)
_writeSpace
(
to
,
ref
)
def
readNonLinearX5
(
fname
):
"""
Read a nonlinear X5 transformation file from ``fname``.
:arg fname: File name to read from
:returns: A :class:`.DisplacementField` or :class:`.CoefficientField`
"""
with
h5py
.
File
(
fname
,
'
r
'
)
as
f
:
root
=
f
[
'
/
'
]
_validateNonLinearTransform
(
root
)
if
root
[
'
SubType
'
]
==
'
displacement
'
:
field
=
_readDisplacementField
(
root
)
elif
root
[
'
SubType
'
]
==
'
coefficient
'
:
field
=
_readCoefficientField
(
root
)
return
field
def
writeNonLinearX5
(
fname
,
field
):
"""
Write a nonlinear X5 transformation file to ``fname``.
:arg fname: File name to write to
:arg field: A :class:`.DisplacementField` or :class:`.CoefficientField`
"""
with
h5py
.
File
(
fname
,
'
w
'
)
as
f
:
_writeMetadata
(
f
)
f
.
attrs
[
'
Type
'
]
=
'
nonlinear
'
if
isinstance
(
field
,
nonlinear
.
DisplacementField
):
_writeDisplacementField
(
f
,
field
)
elif
isinstance
(
field
,
nonlinear
.
CoefficientField
):
_writeCoefficientField
(
f
,
field
)
def
_writeMetadata
(
group
):
"""
Writes a metadata block into the given group.
...
...
@@ -360,8 +438,10 @@ def _writeMetadata(group):
def
_validateMetadata
(
group
):
"""
Reads a metadata block from the given group, and raises an
:exc:`InvalidFileError` if it does not look valid.
"""
Reads a metadata block from the given group, and raises a :exc:`X5Error`
if it does not look valid.
:arg group: A ``h5py.Group`` object.
"""
try
:
...
...
@@ -369,30 +449,30 @@ def _validateMetadata(group):
version
=
group
.
attrs
[
'
Version
'
]
except
Exception
:
raise
InvalidFile
Error
(
'
File does not appear to be an X5 file
'
)
raise
X5
Error
(
'
File does not appear to be an X5 file
'
)
if
(
format
!=
X5_FORMAT
)
or
(
version
!=
X5_VERSION
):
raise
InvalidFile
Error
(
'
Incompatible format/version (required: {}/{},
'
'
present: {}/{})
'
.
format
(
X5_FORMAT
,
X5_VERSION
,
format
,
version
))
raise
X5
Error
(
'
Incompatible format/version (required: {}/{},
'
'
present: {}/{})
'
.
format
(
X5_FORMAT
,
X5_VERSION
,
format
,
version
))
def
_readAffine
(
group
):
"""
Reads an affine from the given group
,
"""
Reads an affine from the given group
.
:arg group: A ``h5py.Group`` object.
:returns: ``numpy`` array containing a ``(4, 4)`` affine transformation.
"""
if
group
.
attrs
[
'
Type
'
]
!=
'
linear
'
:
raise
Value
Error
(
'
Not a linear transform
'
)
raise
X5
Error
(
'
Not a linear transform
'
)
xform
=
np
.
array
(
group
[
'
Transform
'
]
)
xform
=
group
[
'
Transform
'
]
if
xform
.
shape
!=
(
4
,
4
):
raise
Value
Error
(
'
Not a linear transform
'
)
raise
X5
Error
(
'
Not a linear transform
'
)
return
xform
return
np
.
array
(
xform
)
def
_writeAffine
(
group
,
xform
):
...
...
@@ -421,7 +501,7 @@ def _readSpace(group):
import
fsl.data.image
as
fslimage
if
group
.
attrs
[
'
Type
'
]
!=
'
image
'
:
raise
Value
Error
(
'
Not an image
mapping
'
)
raise
X5
Error
(
'
Not an image
space
'
)
shape
=
group
.
attrs
[
'
Size
'
]
pixdim
=
group
.
attrs
[
'
Scales
'
]
...
...
@@ -448,130 +528,195 @@ def _writeSpace(group, img):
_writeAffine
(
mapping
,
img
.
getAffine
(
'
voxel
'
,
'
world
'
))
def
_readDisplacementField
(
group
):
"""
def
_validateNonLinearTransform
(
group
):
"""
Checks that the attributes of the given group, assumed to contain a
nonlinear transform, are valid. Raises a :exc:`X5Error` if not.
:arg group: A ``h5py.Group`` object.
"""
field
=
np
.
array
(
group
[
'
Transform
'
])
dispType
=
group
.
attrs
[
'
Representation
'
]
src
=
_readSpace
(
group
[
'
From
'
])
ref
=
_readSpace
(
group
[
'
To
'
])
pre
=
_readAffine
(
group
[
'
Pre
'
])
post
=
_readAffine
(
group
[
'
Post
'
])
srcToRef
=
_readAffine
(
group
[
'
InitialAlignment
'
])
type
=
group
.
attrs
[
'
Type
'
]
subtype
=
group
.
attrs
[
'
SubType
'
]
repr
=
group
.
attrs
[
'
Representation
'
]
refSpace
=
affine
.
identify
(
ref
,
pre
,
from_
=
'
world
'
)[
1
]
srcSpace
=
affine
.
identify
(
src
,
post
,
to
=
'
world
'
)[
0
]
if
type
!=
'
nonlinear
'
:
raise
X5Error
(
'
Not a nonlinear transform
'
)
return
nonlinear
.
DisplacementField
(
field
,
src
,
ref
,
srcSpace
=
srcSpace
,
refSpace
=
refSpace
,
srcToRefMat
=
srcToRef
,
dispType
=
dispType
)
if
subtype
not
in
(
'
displacement
'
,
'
coefficient
'
):
raise
X5Error
(
'
Unrecognised nonlinear subtype: {}
'
.
format
(
subtype
))
if
(
subtype
==
'
displacement
'
)
and
\
(
repr
not
in
(
'
absolute
'
,
'
relative
'
)):
raise
X5Error
(
'
Unrecognised nonlinear representation:
'
'
{}
'
.
format
(
repr
))
def
_readCoefficientField
(
group
):
"""
if
(
subtype
==
'
coefficient
'
)
and
\
(
repr
not
in
(
'
quadratic bspline
'
,
'
cubic bspline
'
)):
raise
X5Error
(
'
Unrecognised nonlinear representation:
'
'
{}
'
.
format
(
repr
))
def
_readNonLinearCommon
(
group
):
"""
Reads the spaces and affines from the given group, assumed to contain a
nonlinear transform.
:arg group: A ``h5py.Group`` object.
:returns: A tuple containing:
- A :class:`.Nifti` representing the source
- A :class:`.Nifti` representing the reference
- A ``(4, 4)`` ``numpy`` array containing the pre affine, or
``None`` if there is not one.
- A ``(4, 4)`` ``numpy`` array containing the post affine, or
``None`` if there is not one.
- A ``(4, 4)`` ``numpy`` array containing the initial
alignment affine, or ``None`` if there is not one.
- A string describing the source space - see
:meth:`.Nifti.getAffine`
- A string describing the reference space - see
:meth:`.Nifti.getAffine`
"""
field
=
np
.
array
(
group
[
'
Transform
'
])
fieldType
=
group
.
attrs
[
'
Representation
'
]
src
=
_readSpace
(
group
[
'
From
'
])
ref
=
_readSpace
(
group
[
'
To
'
])
pre
=
_readAffine
(
group
[
'
Pre
'
])
post
=
_readAffine
(
group
[
'
Post
'
])
srcToRef
=
_readAffine
(
group
[
'
InitialAlignment
'
])
spacing
=
group
[
'
Parameters
'
].
attrs
[
'
Spacing
'
]
refToField
=
_readAffine
(
group
[
'
Parameters
'
][
'
ReferenceToField
'
])
fieldToRef
=
affine
.
inverse
(
refToField
)
src
=
_readSpace
(
group
[
'
From
'
])
ref
=
_readSpace
(
group
[
'
To
'
])
refSpace
=
affine
.
identify
(
ref
,
pre
,
from_
=
'
world
'
)[
1
]
srcSpace
=
affine
.
identify
(
src
,
post
,
to
=
'
world
'
)[
0
]
pre
=
group
.
get
(
'
Pre
'
)
post
=
group
.
get
(
'
Post
'
)
init
=
group
.
get
(
'
InitialAlignment
'
)
return
nonlinear
.
CoefficientField
(
field
,
src
,
ref
,
srcSpace
=
srcSpace
,
refSpace
=
refSpace
,
fieldType
=
fieldType
,
knotSpacing
=
spacing
,
srcToRefMat
=
srcToRef
,
fieldToRefMat
=
fieldToRef
)
if
pre
is
not
None
:
pre
=
_readAffine
(
pre
)
if
post
is
not
None
:
post
=
_readAffine
(
post
)
if
init
is
not
None
:
init
=
_readAffine
(
init
)
refSpace
=
'
world
'
srcSpace
=
'
world
'
try
:
if
pre
is
not
None
:
refSpace
=
affine
.
identify
(
ref
,
pre
,
from_
=
'
world
'
)[
1
]
if
post
is
not
None
:
srcSpace
=
affine
.
identify
(
src
,
post
,
to
=
'
world
'
)[
0
]
except
ValueError
:
raise
X5Error
(
'
Invalid pre/post affine
'
)
return
src
,
ref
,
pre
,
post
,
init
,
srcSpace
,
refSpace
def
readLinearX5
(
fname
):
"""
Read a linear X5 transformation file from ``fname``.
:return: A tuple containing:
def
_writeNonLinearCommon
(
group
,
field
):
"""
Writes the spaces and affines for the given nonlinear transform to the
given group.
- A ``(4, 4)`` ``numpy`` array containing the affine
transformation
- A :class:`.Nifti` instance representing the source space
- A :class:`.Nifti` instance representing the reference space
:arg group: A ``h5py.Group`` object.
:arg field: A :class:`.NonLinearTransform` object
"""
with
h5py
.
File
(
fname
,
'
r
'
)
as
f
:
_validateMetadata
(
f
[
'
/
'
])
xform
=
_readAffine
(
f
[
'
/
'
])
src
=
_readSpace
(
f
[
'
/From
'
])
ref
=
_readSpace
(
f
[
'
/To
'
])
return
xform
,
src
,
ref
_writeSpace
(
group
.
create_group
(
'
From
'
),
field
.
src
)
_writeSpace
(
group
.
create_group
(
'
To
'
),
field
.
ref
)
pre
=
field
.
ref
.
getAffine
(
'
world
'
,
field
.
refSpace
)
post
=
field
.
src
.
getAffine
(
field
.
srcSpace
,
'
world
'
)
def
writeLinearX5
(
fname
,
xform
,
src
,
ref
):
"""
Write a linear transformation to the specified file.
_writeAffine
(
group
.
create_group
(
'
Pre
'
),
pre
)
_writeAffine
(
group
.
create_group
(
'
Post
'
),
post
)
:arg fname: File name to write to
:arg xform: ``(4, 4)`` ``numpy`` array containing the affine transformation
:arg src: :class:`.Nifti` image representing the source space
:arg ref: :class:`.Nifti` image representing the reference
"""
if
field
.
srcToRefMat
is
not
None
:
_writeAffine
(
group
.
create_group
(
'
InitialAlignment
'
,
field
.
srcToRefMat
))
with
h5py
.
File
(
fname
,
'
w
'
)
as
f
:
_writeMetadata
(
f
)
_writeAffine
(
f
,
xform
)
from_
=
f
.
create_group
(
'
/From
'
)
to
=
f
.
create_group
(
'
/To
'
)
def
_readDisplacementField
(
group
):
"""
Reads a nonlinear displacement field from the given group.
_writeSpace
(
from_
,
src
)
_writeSpace
(
to
,
ref
)
:arg group: A ``h5py.Group`` object.
:returns: A :class:`.DisplacementField` object
"""
src
,
ref
,
pre
,
post
,
init
,
srcSpace
,
refSpace
=
_readNonLinearCommon
(
group
)
field
=
np
.
array
(
group
[
'
Transform
'
])
dtype
=
group
[
'
Representation
'
]
field
=
nonlinear
.
DisplacementField
(
field
,
src
=
src
,
ref
=
ref
,
srcSpace
=
srcSpace
,
refSpace
=
refSpace
,
dispType
=
dtype
,
srcToRefMat
=
init
)
return
field
def
readNonLinearX5
(
fname
):
def
_writeDisplacementField
(
group
,
field
):
"""
Writes a nonlinear displacement field to the given group.
:arg group: A ``h5py.Group`` object.
:arg field: A :class:`.DisplacementField` object
"""
_writeNonLinearCommon
(
group
,
field
)
group
.
attrs
[
'
SubType
'
]
=
'
displacement
'
group
.
attrs
[
'
Representation
'
]
=
field
.
displacementType
xform
=
np
.
field
.
data
.
astype
(
np
.
float64
)
group
.
create_dataset
(
'
Transform
'
,
data
=
xform
)
def
_readCoefficientField
(
group
):
"""
Reads a nonlinear coefficient field from the given group.
:arg group: A ``h5py.Group`` object.
:returns: A :class:`.CoefficientField` object
"""
from
.
import
n
on
l
inear
src
,
ref
,
pre
,
post
,
init
,
srcSpace
,
refSpace
=
_readN
on
L
inear
Common
(
group
)
with
h5py
.
File
(
fname
,
'
r
'
)
as
f
:
field
=
_readNonLinearTransform
(
f
[
'
/
'
])
src
=
_readSpace
(
f
[
'
/From
'
])
ref
=
_readSpace
(
f
[
'
/To
'
])
field
=
np
.
array
(
group
[
'
Transform
'
])
ftype
=
group
[
'
Representation
'
]
spacing
=
group
[
'
Parameters/Spacing
'
]
refToField
=
_readAffine
(
group
[
'
Parameters/ReferenceToField
'
])
fieldToRef
=
affine
.
invert
(
refToField
)
if
ftype
==
'
quadratic bspline
'
:
ftype
=
'
quadratic
'
elif
ftype
==
'
cubic bspline
'
:
ftype
=
'
cubic
'
# TODO coefficient fields
return
nonlinear
.
DisplacementField
(
field
,
if
spacing
.
shape
!=
3
:
raise
X5Error
(
'
Invalid spacing: {}
'
.
format
(
spacing
))
field
=
nonlinear
.
CoefficientField
(
field
,
src
=
src
,
ref
=
ref
,
srcSpace
=
'
world
'
,
refSpace
=
'
world
'
)
srcSpace
=
srcSpace
,
refSpace
=
refSpace
,
fieldType
=
ftype
,
knotSpacing
=
spacing
,
fieldToRefMat
=
fieldToRef
,
srcToRefMat
=
init
)
return
field
def
writeNonLinearX5
(
fname
,
field
):
"""
def
_writeCoefficientField
(
group
,
field
):
"""
Writes a nonlinear coefficient field to the given group.
:arg group: A ``h5py.Group`` object.
:arg field: A :class:`.CoefficientField` object
"""
# TODO coefficient
field
s
_writeNonLinearCommon
(
group
,
field
)
with
h5py
.
File
(
fname
,
'
w
'
)
as
f
:
_writeMetadata
(
f
)
_writeNonLinearTransform
(
f
,
field
.
data
)
group
.
attrs
[
'
SubType
'
]
=
'
coefficient
'
from_
=
f
.
create_group
(
'
/From
'
)
to
=
f
.
create_group
(
'
/To
'
)
if
field
.
fieldType
==
'
cubic
'
:
group
.
attrs
[
'
Representation
'
]
=
'
cubic bspline
'
elif
field
.
fieldType
==
'
quadratic
'
:
group
.
attrs
[
'
Representation
'
]
=
'
quadratic bspline
'
xform
=
np
.
field
.
data
.
astype
(
np
.
float64
)
group
.
create_dataset
(
'
Transform
'
,
data
=
xform
)
params
=
group
.
create_group
(
'
Parameters
'
)
refToField
=
params
.
create_group
(
'
ReferenceToField
'
)
_writeLinearMapping
(
from_
,
field
.
src
)
_write
LinearMapping
(
to
,
field
.
ref
)
params
.
attrs
[
'
Spacing
'
]
=
field
.
knotSpacing
_write
Affine
(
refToField
,
field
.
refToFieldMat
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment