Skip to content

Commit 1366829

Browse files
authored
Merge pull request #37 from jnolan14/master
LabelRecoder invert method
2 parents ded5f1d + 441118e commit 1366829

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

surfa/core/labels.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import collections
22
import numpy as np
3+
import warnings
34
from copy import deepcopy
45
import surfa as sf
56

@@ -289,3 +290,74 @@ def __init__(self, mapping, target=None):
289290
"""
290291
self.mapping = dict(mapping)
291292
self.target = target
293+
294+
def invert(self, target_labels=None, strict=False):
295+
"""
296+
Invert the label mapping dictionary
297+
298+
Parameters
299+
----------
300+
target_labels : LabelLookup, optional
301+
LabelLookup that will be assigned as the target of the returned LabelRecoder
302+
If not assigned, the output volume using this recoder will not have a LabelMapping
303+
strict : bool, optional
304+
Enforce the inverted label recoding is 1-to-1
305+
306+
Returns
307+
-------
308+
LabelRecoder
309+
A LabelRecoder object with the k,v pairs of the original mapping swapped
310+
311+
If the input mapping is many-to-1, the function will raise a `KeyError` unless
312+
the `strict` param is set to `False`. In the case where the input mapping is
313+
many-to-1 and `strict` is set to `False`, the returned LabelRecoder will map
314+
to the minimum value of the 'many' labels. e.g {1:0, 2:0} the inverse will
315+
be {0:1}.
316+
317+
Raises
318+
------
319+
KeyError
320+
If `strict` is set to `True` and inverted label mapping is not 1-to-1
321+
322+
Examples
323+
--------
324+
Load an aseg volume, recode the labels to tissue types using the tissue_type_recoder,
325+
then invert the tissue_type_recoder and remap the labels back.
326+
Note that the tissue_type_recoder is not 1-to-1, so labels classes in the second
327+
remapped volume will be merged.
328+
329+
# load the aseg
330+
>>> aseg = sf.load_volume('aseg.mgz')
331+
332+
# create the tissue_type_recoder obj
333+
>>> lr = sf.freesurfer.tissue_type_recoder()
334+
335+
# remap the aseg labels
336+
>>> aseg_to_tissue = sf.labels.recode(aseg,lr)
337+
338+
# invert the label recoder and assign the standard cLUT as target labels
339+
>>> inv_lr = lr.invert(target_labels=sf.freesurfer.labels())
340+
341+
# re-remap the aseg labels
342+
>>> tissue_to_aseg = sf.labels.recode(aseg,inv_lr)
343+
"""
344+
# invert the mapping dictionary, handling many-to-1 mapping case
345+
inv_mapping = {}
346+
for k,v in self.mapping.items():
347+
if v not in inv_mapping.keys():
348+
inv_mapping[v] = [k]
349+
else:
350+
inv_mapping[v].append(k)
351+
352+
test = [len(x) == 1 for x in inv_mapping.values()]
353+
354+
# raise key error if many-to-1 and strict
355+
if False in test and strict:
356+
raise KeyError('Cannot strictly invert a many-to-1 LabelRecoder')
357+
elif False in test:
358+
warnings.warn('The label remapping is not 1-to-1, some classes will be merged.')
359+
360+
[x.sort() for x in inv_mapping.values()]
361+
inv_mapping = {k:v[0] for k,v in inv_mapping.items()}
362+
363+
return LabelRecoder(inv_mapping, target_labels)

surfa/freesurfer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ def tissue_type_recoder(extra=False, lesions=False):
284284
60: 3, # Right-VentralDC
285285
62: 4, # Right-Vessel
286286
63: 4, # Right-Choroid-Plexus
287+
72: 4, # 5th-Ventricle
287288
77: 6 if lesions else 3, # WM-Hypointensities
288289
78: 3, # Left-WM-Hypointensities
289290
79: 3, # Right-WM-Hypointensities

0 commit comments

Comments
 (0)