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
William Clarke
fsl_mrs
Commits
0715bece
Commit
0715bece
authored
May 20, 2021
by
William Clarke
Browse files
Reorder functionality and mergin along singleton dimension added.
parent
6408e80a
Changes
3
Hide whitespace changes
Inline
Side-by-side
fsl_mrs/core/nifti_mrs.py
View file @
0715bece
...
...
@@ -106,12 +106,11 @@ class NIFTI_MRS(Image):
std_tags
=
[
'DIM_COIL'
,
'DIM_DYN'
,
'DIM_INDIRECT_0'
]
for
idx
in
range
(
3
):
curr_dim
=
idx
+
5
if
self
.
ndim
>=
curr_dim
:
curr_tag
=
f
'dim_
{
curr_dim
}
'
if
curr_tag
in
self
.
hdr_ext
:
self
.
dim_tags
[
idx
]
=
self
.
hdr_ext
[
curr_tag
]
else
:
self
.
dim_tags
[
idx
]
=
std_tags
[
idx
]
curr_tag
=
f
'dim_
{
curr_dim
}
'
if
curr_tag
in
self
.
hdr_ext
:
self
.
dim_tags
[
idx
]
=
self
.
hdr_ext
[
curr_tag
]
elif
curr_dim
<
self
.
ndim
:
self
.
dim_tags
[
idx
]
=
std_tags
[
idx
]
def
__getitem__
(
self
,
sliceobj
):
'''Apply conjugation at use. This swaps from the
...
...
@@ -171,6 +170,7 @@ class NIFTI_MRS(Image):
extension
=
Nifti1Extension
(
44
,
json_s
.
encode
(
'UTF-8'
))
self
.
header
.
extensions
.
clear
()
self
.
header
.
extensions
.
append
(
extension
)
self
.
_set_dim_tags
()
def
dim_position
(
self
,
dim_tag
):
'''Return position of dim if it exists.'''
...
...
fsl_mrs/tests/test_utils_proc_nifti_mrs_tools.py
View file @
0715bece
...
...
@@ -186,3 +186,47 @@ def test_merge():
assert
np
.
allclose
(
out
.
data
[:,
:,
:,
:,
:,
2
:],
nmrs_2
.
data
)
assert
out
.
hdr_ext
==
nmrs_1
.
hdr_ext
assert
np
.
allclose
(
out
.
getAffine
(
'voxel'
,
'world'
),
nmrs_1
.
getAffine
(
'voxel'
,
'world'
))
# Merge along squeezed singleton
nmrs_1_e
=
nmrs_tools
.
reorder
(
nmrs_1
,
[
'DIM_COIL'
,
'DIM_DYN'
,
'DIM_EDIT'
])
nmrs_2_e
=
nmrs_tools
.
reorder
(
nmrs_2
,
[
'DIM_COIL'
,
'DIM_DYN'
,
'DIM_EDIT'
])
out
=
nmrs_tools
.
merge
((
nmrs_1_e
,
nmrs_2_e
),
'DIM_EDIT'
)
assert
out
.
data
.
shape
==
(
1
,
1
,
1
,
4096
,
32
,
2
,
2
)
assert
out
.
hdr_ext
[
'dim_7'
]
==
'DIM_EDIT'
def
test_reorder
():
"""Test the reorder functionality
"""
nmrs
=
mrs_io
.
read_FID
(
test_data_split
)
# Error testing
# Miss existing tag
with
pytest
.
raises
(
nmrs_tools
.
NIfTI_MRSIncompatible
)
as
exc_info
:
nmrs_tools
.
reorder
(
nmrs
,
[
'DIM_COIL'
,
'DIM_EDIT'
])
assert
exc_info
.
type
is
nmrs_tools
.
NIfTI_MRSIncompatible
assert
exc_info
.
value
.
args
[
0
]
==
"The existing tag (DIM_DYN) does not appear"
\
" in the requested tag order (['DIM_COIL', 'DIM_EDIT'])."
# Functionality testing
# Swap order of dimensions
out
=
nmrs_tools
.
reorder
(
nmrs
,
[
'DIM_DYN'
,
'DIM_COIL'
])
assert
out
.
data
.
shape
==
(
1
,
1
,
1
,
4096
,
64
,
32
)
assert
np
.
allclose
(
np
.
swapaxes
(
nmrs
.
data
,
4
,
5
),
out
.
data
)
assert
out
.
hdr_ext
[
'dim_5'
]
==
'DIM_DYN'
assert
out
.
hdr_ext
[
'dim_6'
]
==
'DIM_COIL'
# # Add an additional singleton at end (not reported in shape)
out
=
nmrs_tools
.
reorder
(
nmrs
,
[
'DIM_COIL'
,
'DIM_DYN'
,
'DIM_EDIT'
])
assert
out
.
data
.
shape
==
(
1
,
1
,
1
,
4096
,
32
,
64
)
assert
out
.
hdr_ext
[
'dim_5'
]
==
'DIM_COIL'
assert
out
.
hdr_ext
[
'dim_6'
]
==
'DIM_DYN'
assert
out
.
hdr_ext
[
'dim_7'
]
==
'DIM_EDIT'
# Add an additional singleton at 5 (not reported in shape)
out
=
nmrs_tools
.
reorder
(
nmrs
,
[
'DIM_EDIT'
,
'DIM_COIL'
,
'DIM_DYN'
])
assert
out
.
data
.
shape
==
(
1
,
1
,
1
,
4096
,
1
,
32
,
64
)
assert
out
.
hdr_ext
[
'dim_5'
]
==
'DIM_EDIT'
assert
out
.
hdr_ext
[
'dim_6'
]
==
'DIM_COIL'
assert
out
.
hdr_ext
[
'dim_7'
]
==
'DIM_DYN'
fsl_mrs/utils/preproc/nifti_mrs_tools.py
View file @
0715bece
...
...
@@ -3,11 +3,18 @@
Author: Will Clarke <william.clarke@ndcn.ox.ac.uk>
Copyright (C) 2021 University of Oxford
"""
import
re
import
json
import
numpy
as
np
from
nibabel.nifti1
import
Nifti1Extension
from
fsl_mrs.core.nifti_mrs
import
NIFTI_MRS
,
NIFTIMRS_DimDoesntExist
class
NIfTI_MRSIncompatible
(
Exception
):
pass
def
split
(
nmrs
,
dimension
,
index_or_indicies
):
"""Splits, or extracts indices from, a specified dimension of a
NIFTI_MRS object. Output is two NIFTI_MRS objects. Header information preserved.
...
...
@@ -66,10 +73,6 @@ def split(nmrs, dimension, index_or_indicies):
return
nmrs_1
,
nmrs_2
class
NIfTI_MRSIncompatible
(
Exception
):
pass
def
merge
(
array_of_nmrs
,
dimension
):
"""Concatenate NIfTI-MRS objects along specified higher dimension
...
...
@@ -119,11 +122,86 @@ def merge(array_of_nmrs, dimension):
raise
NIfTI_MRSIncompatible
(
'The shape of all concatentated objects must match.'
f
' The shape (
{
nmrs
.
shape
}
) of the
{
idx
}
object does'
f
' not match that of the first (
{
array_of_nmrs
[
0
].
shape
}
).'
)
# Check dim tags for compatibility
if
not
check_tag
(
nmrs
):
raise
NIfTI_MRSIncompatible
(
'The tags of all concatentated objects must match.'
f
' The tags (
{
nmrs
.
dim_tags
}
) of the
{
idx
}
object does'
f
' not match that of the first (
{
array_of_nmrs
[
0
].
dim_tags
}
).'
)
# Check dim tags for compatibility
to_concat
.
append
(
nmrs
.
data
)
if
nmrs
.
ndim
==
dim_index
:
# If a squeezed singleton on the end.
to_concat
.
append
(
np
.
expand_dims
(
nmrs
.
data
,
-
1
))
else
:
to_concat
.
append
(
nmrs
.
data
)
return
NIFTI_MRS
(
np
.
concatenate
(
to_concat
,
axis
=
dim_index
),
header
=
array_of_nmrs
[
0
].
header
)
def
reorder
(
nmrs
,
dim_tag_list
):
"""Reorder the higher dimensions of a NIfTI-MRS object.
Can force a singleton dimension with new tag.
:param nmrs: NIFTI-MRS object to reorder.
:type nmrs: fsl_mrs.core.nifti_mrs.NIFTI_MRS
:param dim_tag_list: List of dimension tags in desired order
:type dim_tag_list: List of str
:return: Reordered NIfTI-MRS object.
:rtype: fsl_mrs.core.nifti_mrs.NIFTI_MRS
"""
# Check existing tags are in the list of desired tags
for
idx
,
tag
in
enumerate
(
nmrs
.
dim_tags
):
if
tag
not
in
dim_tag_list
\
and
tag
is
not
None
:
raise
NIfTI_MRSIncompatible
(
f
'The existing tag (
{
tag
}
) does not appear '
f
'in the requested tag order (
{
dim_tag_list
}
).'
)
# Create singleton dimensions if required
original_dims
=
nmrs
.
ndim
new_dim
=
sum
(
x
is
not
None
for
x
in
nmrs
.
dim_tags
)
+
4
dims_to_add
=
tuple
(
range
(
original_dims
,
new_dim
+
1
))
data_with_singleton
=
np
.
expand_dims
(
nmrs
.
data
,
dims_to_add
)
# Create list of source indicies
# Create list of destination indicies
# Keep track of singleton tags
source_indicies
=
[]
dest_indicies
=
[]
singleton_tags
=
{}
counter
=
0
for
idx
,
tag
in
enumerate
(
dim_tag_list
):
if
tag
is
not
None
:
if
tag
in
nmrs
.
dim_tags
:
source_indicies
.
append
(
nmrs
.
dim_tags
.
index
(
tag
)
+
4
)
else
:
source_indicies
.
append
(
nmrs
.
ndim
+
counter
)
counter
+=
1
singleton_tags
.
update
({(
idx
+
5
):
tag
})
dest_indicies
.
append
(
idx
+
4
)
# Sort header_ext dim_tags
dim_n
=
re
.
compile
(
r
'dim_[567].*'
)
new_hdr_dict
=
{}
for
key
in
nmrs
.
hdr_ext
:
if
dim_n
.
match
(
key
):
new_index
=
dest_indicies
[
source_indicies
.
index
(
int
(
key
[
4
])
-
1
)]
+
1
new_key
=
'dim_'
+
str
(
new_index
)
+
key
[
5
:]
new_hdr_dict
.
update
({
new_key
:
nmrs
.
hdr_ext
[
key
]})
else
:
new_hdr_dict
.
update
({
key
:
nmrs
.
hdr_ext
[
key
]})
# For any singleton dimensions we've added
for
dim
in
singleton_tags
:
new_hdr_dict
.
update
({
f
'dim_
{
dim
}
'
:
singleton_tags
[
dim
]})
new_header
=
nmrs
.
header
.
copy
()
json_s
=
json
.
dumps
(
new_hdr_dict
)
extension
=
Nifti1Extension
(
44
,
json_s
.
encode
(
'UTF-8'
))
new_header
.
extensions
.
clear
()
new_header
.
extensions
.
append
(
extension
)
new_nmrs
=
NIFTI_MRS
(
np
.
moveaxis
(
data_with_singleton
,
source_indicies
,
dest_indicies
),
header
=
new_header
)
return
new_nmrs
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