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
Package registry
Model registry
Operate
Environments
Terraform modules
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
Evan Edmond
fslpy
Commits
2263243c
Commit
2263243c
authored
7 years ago
by
Paul McCarthy
Browse files
Options
Downloads
Patches
Plain Diff
Label atlas image values no longer need to match the index of the label
into the AtlasDescription.labels list.
parent
cf99f6ab
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
fsl/data/atlases.py
+82
-40
82 additions, 40 deletions
fsl/data/atlases.py
with
82 additions
and
40 deletions
fsl/data/atlases.py
+
82
−
40
View file @
2263243c
...
@@ -314,17 +314,18 @@ class AtlasLabel(object):
...
@@ -314,17 +314,18 @@ class AtlasLabel(object):
An ``AtlasLabel`` instance contains the following attributes:
An ``AtlasLabel`` instance contains the following attributes:
========= ==============================================================
========= ==============================================================
==
``name`` Region name
``name`` Region name
``index`` For probabilistic atlases, the volume index into the 4D atlas
``index`` The index of this label into the list of all labels in the
image that corresponds to this region. For label atlases, the
``AtlasDescription`` that owns it. For probabilistic atlases,
value of voxels that are in this region. For summary images of
this is also the index into the 4D atlas image of the volume
probabilistic atlases, add 1 to this value to get the
that corresponds to this region.
corresponding voxel values.
``value`` For label atlases and summary images, the value of voxels that
are in this region.
``x`` X coordinate of the region in world space
``x`` X coordinate of the region in world space
``y`` Y coordinate of the region in world space
``y`` Y coordinate of the region in world space
``z`` Z coordinate of the region in world space
``z`` Z coordinate of the region in world space
========= ==============================================================
========= ==============================================================
==
.. note:: The ``x``, ``y`` and ``z`` label coordinates are pre-calculated
.. note:: The ``x``, ``y`` and ``z`` label coordinates are pre-calculated
centre-of-gravity coordinates, as listed in the atlas xml file.
centre-of-gravity coordinates, as listed in the atlas xml file.
...
@@ -333,9 +334,10 @@ class AtlasLabel(object):
...
@@ -333,9 +334,10 @@ class AtlasLabel(object):
XML file (typically MNI152 space).
XML file (typically MNI152 space).
"""
"""
def
__init__
(
self
,
name
,
index
,
x
,
y
,
z
):
def
__init__
(
self
,
name
,
index
,
value
,
x
,
y
,
z
):
self
.
name
=
name
self
.
name
=
name
self
.
index
=
index
self
.
index
=
index
self
.
value
=
value
self
.
x
=
x
self
.
x
=
x
self
.
y
=
y
self
.
y
=
y
self
.
z
=
z
self
.
z
=
z
...
@@ -383,8 +385,11 @@ class AtlasDescription(object):
...
@@ -383,8 +385,11 @@ class AtlasDescription(object):
# as relative to the location of this
# as relative to the location of this
# XML file.
# XML file.
<summaryimagefile> # Path to 3D summary file, with each
<summaryimagefile> # Path to 3D label summary file,
</summaryimagefile> # region having value (index + 1)
</summaryimagefile> # Every <image> must be accompanied
# by a <summaryimage> - for label
# atlases, they will typically refer
# to the same image file.
</images>
</images>
...
# More images - generally both
...
# More images - generally both
...
@@ -395,7 +400,10 @@ class AtlasDescription(object):
...
@@ -395,7 +400,10 @@ class AtlasDescription(object):
# index - For probabilistic atlases, index of corresponding volume in
# index - For probabilistic atlases, index of corresponding volume in
# 4D image file. For label images, the value of voxels which
# 4D image file. For label images, the value of voxels which
# are in the corresponding region.
# are in the corresponding region. For probabilistic atlases,
# it is assumed that the value for each region in the summary
# image(s) are equal to ``index + 1``.
#
#
#
# x |
# x |
# y |- XYZ *voxel* coordinates into the first image of the <images>
# y |- XYZ *voxel* coordinates into the first image of the <images>
...
@@ -487,6 +495,8 @@ class AtlasDescription(object):
...
@@ -487,6 +495,8 @@ class AtlasDescription(object):
atlasDir
=
op
.
dirname
(
self
.
specPath
)
atlasDir
=
op
.
dirname
(
self
.
specPath
)
for
image
in
images
:
for
image
in
images
:
# Every image must also have a summary image
imagefile
=
image
.
find
(
'
imagefile
'
)
.
text
imagefile
=
image
.
find
(
'
imagefile
'
)
.
text
summaryimagefile
=
image
.
find
(
'
summaryimagefile
'
).
text
summaryimagefile
=
image
.
find
(
'
summaryimagefile
'
).
text
...
@@ -505,6 +515,11 @@ class AtlasDescription(object):
...
@@ -505,6 +515,11 @@ class AtlasDescription(object):
labels
=
data
.
findall
(
'
label
'
)
labels
=
data
.
findall
(
'
label
'
)
self
.
labels
=
[]
self
.
labels
=
[]
# Refs to AtlasLabel objects
# indexed by their value.
# Used by the find method.
self
.
__labelsByValue
=
{}
# The xyz coordinates for each label are in terms
# The xyz coordinates for each label are in terms
# of the voxel space of the first images element
# of the voxel space of the first images element
# in the header. For convenience, we're going to
# in the header. For convenience, we're going to
...
@@ -519,11 +534,26 @@ class AtlasDescription(object):
...
@@ -519,11 +534,26 @@ class AtlasDescription(object):
x
=
float
(
label
.
attrib
[
'
x
'
])
x
=
float
(
label
.
attrib
[
'
x
'
])
y
=
float
(
label
.
attrib
[
'
y
'
])
y
=
float
(
label
.
attrib
[
'
y
'
])
z
=
float
(
label
.
attrib
[
'
z
'
])
z
=
float
(
label
.
attrib
[
'
z
'
])
al
=
AtlasLabel
(
name
,
index
,
x
,
y
,
z
)
# For label images, the index field
# contains the region value
if
self
.
atlasType
==
'
label
'
:
value
=
index
index
=
i
# For probablistic images, the index
# field specifies the volume in the
# 4D atlas corresponding to the region.
# It is assumed that the summary value
# for each region is index + 1
else
:
value
=
index
+
1
al
=
AtlasLabel
(
name
,
index
,
value
,
x
,
y
,
z
)
coords
[
i
]
=
(
x
,
y
,
z
)
coords
[
i
]
=
(
x
,
y
,
z
)
self
.
labels
.
append
(
al
)
self
.
labels
.
append
(
al
)
self
.
__labelsByValue
[
value
]
=
al
# Load the appropriate transformation matrix
# Load the appropriate transformation matrix
# and transform all those voxel coordinates
# and transform all those voxel coordinates
...
@@ -536,6 +566,20 @@ class AtlasDescription(object):
...
@@ -536,6 +566,20 @@ class AtlasDescription(object):
label
.
x
,
label
.
y
,
label
.
z
=
coords
[
i
]
label
.
x
,
label
.
y
,
label
.
z
=
coords
[
i
]
def
find
(
self
,
index
=
None
,
value
=
None
):
"""
Find an :class:`.AtlasLabel` either by ``index``, or by ``value``.
Exactly one of ``index`` or ``value`` may be specified - a
``ValueError`` is raised otherwise.
"""
if
(
index
is
None
and
value
is
None
)
or
\
(
index
is
not
None
and
value
is
not
None
):
raise
ValueError
(
'
Only one of index or value may be specified
'
)
if
index
is
not
None
:
return
self
.
labels
[
index
]
else
:
return
self
.
__labelsByValue
[
value
]
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
"""
Compares the ``atlasID`` of this ``AtlasDescription`` with another.
"""
Compares the ``atlasID`` of this ``AtlasDescription`` with another.
"""
"""
...
@@ -605,6 +649,13 @@ class Atlas(fslimage.Image):
...
@@ -605,6 +649,13 @@ class Atlas(fslimage.Image):
self
.
desc
=
atlasDesc
self
.
desc
=
atlasDesc
def
find
(
self
,
*
args
,
**
kwargs
):
"""
Find an ``AtlasLabel`` - see the :meth:`AtlasDescription.find`
method.
"""
return
self
.
desc
.
find
(
*
args
,
**
kwargs
)
class
MaskError
(
Exception
):
class
MaskError
(
Exception
):
"""
Exception raised by the :meth:`LabelAtlas.maskLabel` and
"""
Exception raised by the :meth:`LabelAtlas.maskLabel` and
:meth:`ProbabilisticAtlas.maskProportions` when a mask is provided which
:meth:`ProbabilisticAtlas.maskProportions` when a mask is provided which
...
@@ -671,9 +722,8 @@ class LabelAtlas(Atlas):
...
@@ -671,9 +722,8 @@ class LabelAtlas(Atlas):
:returns: The label at the given coordinates, or ``None`` if the
:returns: The label at the given coordinates, or ``None`` if the
coordinates are out of bounds.
coordinates are out of bounds.
.. note:: If this is a summary image of a probabilistic atlas, you need
.. note:: Use the :meth:`find` method to retrieve the ``AtlasLabel``
to subtract one from the result to get the region volume
associated with each returned value.
index into the probabilistic atlas.
"""
"""
if
not
voxel
:
if
not
voxel
:
...
@@ -703,15 +753,13 @@ class LabelAtlas(Atlas):
...
@@ -703,15 +753,13 @@ class LabelAtlas(Atlas):
:returns: A tuple containing:
:returns: A tuple containing:
- A sequence of all
labels
which are present in the mask
- A sequence of all
values
which are present in the mask
- A sequence containing the proportion, within the mask,
- A sequence containing the proportion, within the mask,
of each present
label
. The proportions are returned as
of each present
value
. The proportions are returned as
values between 0 and 100.
values between 0 and 100.
.. note:: If this is a summary image of a probabilistic atlas, you need
.. note:: Use the :meth:`find` method to retrieve the ``AtlasLabel``
to subtract one from the returned label values to get the
associated with each returned value.
corresponding region volume indices into the probabilistic
atlas.
"""
"""
# Make sure that the mask has the same
# Make sure that the mask has the same
...
@@ -726,44 +774,36 @@ class LabelAtlas(Atlas):
...
@@ -726,44 +774,36 @@ class LabelAtlas(Atlas):
# Extract the
label
s that are in
# Extract the
value
s that are in
# the mask, and their corresponding
# the mask, and their corresponding
# mask weights
# mask weights
boolmask
=
mask
>
0
boolmask
=
mask
>
0
vals
=
self
[
boolmask
]
vals
=
self
[
boolmask
]
weights
=
mask
[
boolmask
]
weights
=
mask
[
boolmask
]
weightsum
=
weights
.
sum
()
weightsum
=
weights
.
sum
()
got
Label
s
=
np
.
unique
(
vals
)
got
Value
s
=
np
.
unique
(
vals
)
label
s
=
[]
value
s
=
[]
props
=
[]
props
=
[]
# Only consider labels that
# Only consider labels that
# this atlas is aware of
# this atlas is aware of
for
label
in
self
.
desc
.
labels
:
for
label
in
self
.
desc
.
labels
:
if
label
.
value
in
gotValues
:
# For probabilistic images, the label index
# is the index of the volume corresponding
# to the region. We need to add 1 to this
# to get its value in the summary image.
if
self
.
desc
.
atlasType
==
'
label
'
:
label
=
label
.
index
else
:
label
=
label
.
index
+
1
if
label
in
gotLabels
:
# Figure out the number of all voxels
# Figure out the number of all voxels
# in the mask with this
label
, weighted
# in the mask with this
value
, weighted
# by the mask.
# by the mask.
prop
=
weights
[
vals
==
label
].
sum
()
prop
=
weights
[
vals
==
label
.
value
].
sum
()
# Normalise it to be a proportion
# Normalise it to be a proportion
# of all voxels in the mask. We
# of all voxels in the mask. We
# multiply by 100 because the FSL
# multiply by 100 because the FSL
# probabilistic atlases store their
# probabilistic atlases store their
# probabilities as percentages.
# probabilities as percentages.
label
s
.
append
(
label
)
value
s
.
append
(
label
.
value
)
props
.
append
(
100
*
prop
/
weightsum
)
props
.
append
(
100
*
prop
/
weightsum
)
return
label
s
,
props
return
value
s
,
props
class
ProbabilisticAtlas
(
Atlas
):
class
ProbabilisticAtlas
(
Atlas
):
...
@@ -839,11 +879,13 @@ class ProbabilisticAtlas(Atlas):
...
@@ -839,11 +879,13 @@ class ProbabilisticAtlas(Atlas):
loc
[
2
]
>=
self
.
shape
[
2
]:
loc
[
2
]
>=
self
.
shape
[
2
]:
return
[]
return
[]
# We only return labels for this atlas
props
=
self
[
loc
[
0
],
loc
[
1
],
loc
[
2
],
:]
props
=
self
[
loc
[
0
],
loc
[
1
],
loc
[
2
],
:]
props
=
[
props
[
l
.
index
]
for
l
in
self
.
desc
.
labels
]
return
props
# We only return labels for this atlas -
# the underlying image may have more
# volumes than this atlas has labels.
return
[
props
[
l
.
index
]
for
l
in
self
.
desc
.
labels
]
def
maskProportions
(
self
,
mask
):
def
maskProportions
(
self
,
mask
):
...
...
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