Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
FSL
fslpy
Commits
99cc593f
Commit
99cc593f
authored
Jan 10, 2019
by
Paul McCarthy
🚵
Browse files
RF,ENH: Support for GIFTI files with ultiple pointsets, and with vertex
data. Will prpbably need tweaking.
parent
e92f083a
Changes
1
Hide whitespace changes
Inline
Side-by-side
fsl/data/gifti.py
View file @
99cc593f
...
@@ -19,6 +19,7 @@ are available:
...
@@ -19,6 +19,7 @@ are available:
GiftiMesh
GiftiMesh
loadGiftiMesh
loadGiftiMesh
loadGiftiVertexData
loadGiftiVertexData
prepareGiftiVertexData
relatedFiles
relatedFiles
"""
"""
...
@@ -34,15 +35,13 @@ import fsl.data.constants as constants
...
@@ -34,15 +35,13 @@ import fsl.data.constants as constants
import
fsl.data.mesh
as
fslmesh
import
fsl.data.mesh
as
fslmesh
# We include '.gii' here because not all surface
ALLOWED_EXTENSIONS
=
[
'.gii'
]
# GIFTIs follow the file suffix convention.
ALLOWED_EXTENSIONS
=
[
'.surf.gii'
,
'.gii'
]
"""List of file extensions that a file containing Gifti surface data
"""List of file extensions that a file containing Gifti surface data
is expected to have.
is expected to have.
"""
"""
EXTENSION_DESCRIPTIONS
=
[
'GIFTI
surface file'
,
'GIFTI
file'
]
EXTENSION_DESCRIPTIONS
=
[
'GIFTI file'
]
"""A description for each of the :data:`ALLOWED_EXTENSIONS`. """
"""A description for each of the :data:`ALLOWED_EXTENSIONS`. """
...
@@ -60,7 +59,8 @@ class GiftiMesh(fslmesh.Mesh):
...
@@ -60,7 +59,8 @@ class GiftiMesh(fslmesh.Mesh):
"""Load the given GIFTI file using ``nibabel``, and extracts surface
"""Load the given GIFTI file using ``nibabel``, and extracts surface
data using the :func:`loadGiftiMesh` function.
data using the :func:`loadGiftiMesh` function.
:arg infile: A GIFTI surface file (``*.surf.gii``).
:arg infile: A GIFTI file (``*..gii``) which contains a surface
definition.
:arg fixWinding: Passed through to the :meth:`addVertices` method
:arg fixWinding: Passed through to the :meth:`addVertices` method
for the first vertex set.
for the first vertex set.
...
@@ -76,17 +76,20 @@ class GiftiMesh(fslmesh.Mesh):
...
@@ -76,17 +76,20 @@ class GiftiMesh(fslmesh.Mesh):
name
=
fslpath
.
removeExt
(
op
.
basename
(
infile
),
ALLOWED_EXTENSIONS
)
name
=
fslpath
.
removeExt
(
op
.
basename
(
infile
),
ALLOWED_EXTENSIONS
)
infile
=
op
.
abspath
(
infile
)
infile
=
op
.
abspath
(
infile
)
surfimg
,
vertices
,
indices
=
loadGiftiMesh
(
infile
)
surfimg
,
indices
,
vertices
,
vdata
=
loadGiftiMesh
(
infile
)
fslmesh
.
Mesh
.
__init__
(
self
,
fslmesh
.
Mesh
.
__init__
(
self
,
indices
,
indices
,
name
=
name
,
name
=
name
,
dataSource
=
infile
)
dataSource
=
infile
)
self
.
addVertices
(
vertices
,
infile
,
fixWinding
=
fixWinding
)
for
v
in
vertices
:
self
.
addVertices
(
v
,
infile
,
fixWinding
=
fixWinding
)
self
.
setMeta
(
infile
,
surfimg
)
self
.
setMeta
(
infile
,
surfimg
)
if
vdata
is
not
None
:
self
.
addVertexData
(
infile
,
vdata
)
# Find and load all other
# Find and load all other
# surfaces in the same directory
# surfaces in the same directory
# as the specfiied one.
# as the specfiied one.
...
@@ -157,9 +160,10 @@ def loadGiftiMesh(filename):
...
@@ -157,9 +160,10 @@ def loadGiftiMesh(filename):
The image is expected to contain the following``<DataArray>`` elements:
The image is expected to contain the following``<DataArray>`` elements:
- one comprising ``NIFTI_INTENT_POINTSET`` data (the surface vertices)
- one comprising ``NIFTI_INTENT_TRIANGLE`` data (vertex indices
- one comprising ``NIFTI_INTENT_TRIANGLE`` data (vertex indices
defining the triangles).
defining the triangles).
- one or more comprising ``NIFTI_INTENT_POINTSET`` data (the surface
vertices)
A ``ValueError`` will be raised if this is not the case.
A ``ValueError`` will be raised if this is not the case.
...
@@ -169,42 +173,62 @@ def loadGiftiMesh(filename):
...
@@ -169,42 +173,62 @@ def loadGiftiMesh(filename):
- The loaded ``nibabel.gifti.GiftiImage`` instance
- The loaded ``nibabel.gifti.GiftiImage`` instance
- A ``(N, 3)`` array containing ``N`` vertices.
- A ``(M, 3)`` array containing the vertex indices for
- A ``(M, 3))`` array containing the vertex indices for
``M`` triangles.
``M`` triangles.
"""
gimg
=
nib
.
load
(
filename
)
- A list of at least one ``(N, 3)`` arrays containing ``N``
vertices.
pointsetCode
=
constants
.
NIFTI_INTENT_POINTSET
- A ``(M, N)`` numpy array containing ``N`` data points for
triangleCode
=
constants
.
NIFTI_INTENT_TRIANGLE
``M`` vertices, or ``None`` if the file does not contain
any vertex data.
"""
pointsets
=
[
d
for
d
in
gimg
.
darrays
if
d
.
intent
==
pointsetCode
]
gimg
=
nib
.
load
(
filename
)
triangles
=
[
d
for
d
in
gimg
.
darrays
if
d
.
intent
==
triangleCode
]
if
len
(
gimg
.
darrays
)
!=
2
:
pscode
=
constants
.
NIFTI_INTENT_POINTSET
raise
ValueError
(
'{}: GIFTI surface files must contain '
tricode
=
constants
.
NIFTI_INTENT_TRIANGLE
'exactly one pointset array and one '
'triangle array'
.
format
(
filename
))
if
len
(
pointsets
)
!=
1
:
pointsets
=
[
d
for
d
in
gimg
.
darrays
if
d
.
intent
==
pscode
]
raise
ValueError
(
'{}: GIFTI surface files must contain '
triangles
=
[
d
for
d
in
gimg
.
darrays
if
d
.
intent
==
tricode
]
'exactly one pointset array'
.
format
(
filenam
e
)
)
vdata
=
[
d
for
d
in
gimg
.
darrays
if
d
.
intent
not
in
(
pscode
,
tricod
e
)
]
if
len
(
triangles
)
!=
1
:
if
len
(
triangles
)
!=
1
:
raise
ValueError
(
'{}: GIFTI surface files must contain '
raise
ValueError
(
'{}: GIFTI surface files must contain '
'exactly one triangle array'
.
format
(
filename
))
'exactly one triangle array'
.
format
(
filename
))
vertices
=
pointsets
[
0
].
data
if
len
(
pointsets
)
==
0
:
raise
ValueError
(
'{}: GIFTI surface files must contain '
'at least one pointset array'
.
format
(
filename
))
vertices
=
[
ps
.
data
for
ps
in
pointsets
]
indices
=
triangles
[
0
].
data
indices
=
triangles
[
0
].
data
return
gimg
,
vertices
,
indices
if
len
(
vdata
)
==
0
:
vdata
=
None
else
:
vdata
=
prepareGiftiVertexData
(
vdata
,
filename
)
return
gimg
,
indices
,
vertices
,
vdata
def
loadGiftiVertexData
(
filename
):
def
loadGiftiVertexData
(
filename
):
"""Loads vertex data from the given GIFTI file.
"""Loads vertex data from the given GIFTI file.
See :func:`prepareGiftiVertexData`.
Returns a tuple containing:
- The loaded ``nibabel.gifti.GiftiImage`` object
- A ``(M, N)`` numpy array containing ``N`` data points for ``M``
vertices
"""
gimg
=
nib
.
load
(
filename
)
return
gimg
,
prepareGiftiVertexData
(
gimg
.
darrays
,
filename
)
def
prepareGiftiVertexData
(
darrays
,
filename
=
None
):
"""Prepares vertex data from the given list of GIFTI data arrays.
It is assumed that the given file does not contain any
It is assumed that the given file does not contain any
``NIFTI_INTENT_POINTSET`` or ``NIFTI_INTENT_TRIANGLE`` data arrays, and
``NIFTI_INTENT_POINTSET`` or ``NIFTI_INTENT_TRIANGLE`` data arrays, and
which contains either:
which contains either:
...
@@ -215,17 +239,11 @@ def loadGiftiVertexData(filename):
...
@@ -215,17 +239,11 @@ def loadGiftiVertexData(filename):
- One or more ``(M, 1)`` data arrays each containing a single data point
- One or more ``(M, 1)`` data arrays each containing a single data point
for ``M`` vertices, and all with the same intent code
for ``M`` vertices, and all with the same intent code
Returns a tuple containing:
Returns a ``(M, N)`` numpy array containing ``N`` data points for ``M``
vertices.
- The loaded ``nibabel.gifti.GiftiImage`` object
- A ``(M, N)`` numpy array containing ``N`` data points for ``M``
vertices
"""
"""
gimg
=
nib
.
load
(
filename
)
intents
=
set
([
d
.
intent
for
d
in
darrays
])
intents
=
set
([
d
.
intent
for
d
in
gimg
.
darrays
])
if
len
(
intents
)
!=
1
:
if
len
(
intents
)
!=
1
:
raise
ValueError
(
'{} contains multiple (or no) intents'
raise
ValueError
(
'{} contains multiple (or no) intents'
...
@@ -235,20 +253,19 @@ def loadGiftiVertexData(filename):
...
@@ -235,20 +253,19 @@ def loadGiftiVertexData(filename):
if
intent
in
(
constants
.
NIFTI_INTENT_POINTSET
,
if
intent
in
(
constants
.
NIFTI_INTENT_POINTSET
,
constants
.
NIFTI_INTENT_TRIANGLE
):
constants
.
NIFTI_INTENT_TRIANGLE
):
raise
ValueError
(
'{} contains surface data'
.
format
(
filename
))
raise
ValueError
(
'{} contains surface data'
.
format
(
filename
))
# Just a single array - return it as-is.
# Just a single array - return it as-is.
# n.b. Storing (M, N) data in a single
# n.b. Storing (M, N) data in a single
# DataArray goes against the GIFTI spec,
# DataArray goes against the GIFTI spec,
# but hey, it happens.
# but hey, it happens.
if
len
(
gimg
.
darrays
)
==
1
:
if
len
(
darrays
)
==
1
:
vdata
=
gimg
.
darrays
[
0
].
data
vdata
=
darrays
[
0
].
data
return
gimg
,
vdata
.
reshape
(
vdata
.
shape
[
0
],
-
1
)
return
vdata
.
reshape
(
vdata
.
shape
[
0
],
-
1
)
# Otherwise extract and concatenate
# Otherwise extract and concatenate
# multiple 1-dimensional arrays
# multiple 1-dimensional arrays
vdata
=
[
d
.
data
for
d
in
gimg
.
darrays
]
vdata
=
[
d
.
data
for
d
in
darrays
]
if
any
([
len
(
d
.
shape
)
!=
1
for
d
in
vdata
]):
if
any
([
len
(
d
.
shape
)
!=
1
for
d
in
vdata
]):
raise
ValueError
(
'{} contains one or more non-vector '
raise
ValueError
(
'{} contains one or more non-vector '
...
@@ -257,7 +274,7 @@ def loadGiftiVertexData(filename):
...
@@ -257,7 +274,7 @@ def loadGiftiVertexData(filename):
vdata
=
np
.
vstack
(
vdata
).
T
vdata
=
np
.
vstack
(
vdata
).
T
vdata
=
vdata
.
reshape
(
vdata
.
shape
[
0
],
-
1
)
vdata
=
vdata
.
reshape
(
vdata
.
shape
[
0
],
-
1
)
return
gimg
,
vdata
return
vdata
def
relatedFiles
(
fname
,
ftypes
=
None
):
def
relatedFiles
(
fname
,
ftypes
=
None
):
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment