Source code for medpy.filter.label
# Copyright (C) 2013 Oskar Maier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# author Oskar Maier
# version r0.1.1
# since 2012-02-07
# status Development
# build-in modules
# third-party modules
import scipy
# own modules
from ..core.exceptions import ArgumentError
# code
[docs]def relabel_map(label_image, mapping, key=lambda x, y: x[y]):
r"""
Relabel an image using the supplied mapping.
The ``mapping`` can be any kind of subscriptable object. The respective region id is used
to access the new value from the ``mapping``. The ``key`` keyword parameter can be used to
supply another access function. The ``key`` function must have the signature
key(mapping, region-id) and return the new region-id to assign.
Parameters
----------
label_image : array_like
A nD label map.
mapping : dictionary or subscriptable object
A mapping object.
key : function
Can be used to defined the key-access to the ``mapping`` object.
Returns
-------
relabel_map : ndarray
A label map with new region ids.
Raises
------
ArgumentError
If a region id is missing in the supplied mapping
"""
label_image = scipy.array(label_image)
def _map(x):
try:
return key(mapping, x)
except Exception as e:
raise ArgumentError('No conversion for region id {} found in the supplied mapping. Error: {}'.format(x, e))
vmap = scipy.vectorize(_map, otypes=[label_image.dtype])
return vmap(label_image)
[docs]def relabel(label_image, start = 1):
r"""
Relabel the regions of a label image.
Re-processes the labels to make them consecutively and starting from start.
Parameters
----------
label_image : array_like
A nD label map.
start : integer
The id of the first label to assign
Returns
-------
relabel_map : ndarray
The relabelled label map.
See also
--------
relabel_non_zero
"""
label_image = scipy.asarray(label_image)
mapping = {}
rav = label_image.ravel()
for i in range(len(rav)):
if not rav[i] in mapping:
mapping[rav[i]] = start
start += 1
rav[i] = mapping[rav[i]]
return rav.reshape(label_image.shape)
[docs]def relabel_non_zero(label_image, start = 1):
r"""
Relabel the regions of a label image.
Re-processes the labels to make them consecutively and starting from start.
Keeps all zero (0) labels, as they are considered background.
Parameters
----------
label_image : array_like
A nD label map.
start : integer
The id of the first label to assign
Returns
-------
relabel_map : ndarray
The relabelled label map.
See also
--------
relabel
"""
if start <= 0: raise ArgumentError('The starting value can not be 0 or lower.')
l = list(scipy.unique(label_image))
if 0 in l: l.remove(0)
mapping = dict()
mapping[0] = 0
for key, item in zip(l, list(range(start, len(l) + start))):
mapping[key] = item
return relabel_map(label_image, mapping)
[docs]def fit_labels_to_mask(label_image, mask):
r"""
Reduces a label images by overlaying it with a binary mask and assign the labels
either to the mask or to the background. The resulting binary mask is the nearest
expression the label image can form of the supplied binary mask.
Parameters
----------
label_image : array_like
A nD label map.
mask : array_like
A mask image, i.e., a binary image with False for background and True for foreground.
Returns
-------
best_fit : ndarray
The best fit of the labels to the mask.
Raises
------
ValueError
If ``label_image`` and ``mask`` are not of the same shape.
"""
label_image = scipy.asarray(label_image)
mask = scipy.asarray(mask, dtype=scipy.bool_)
if label_image.shape != mask.shape:
raise ValueError('The input images must be of the same shape.')
# prepare collection dictionaries
labels = scipy.unique(label_image)
collection = {}
for label in labels:
collection[label] = [0, 0, []] # size, union, points
# iterate over the label images pixels and collect position, size and union
for x in range(label_image.shape[0]):
for y in range(label_image.shape[1]):
for z in range(label_image.shape[2]):
entry = collection[label_image[x,y,z]]
entry[0] += 1
if mask[x,y,z]: entry[1] += 1
entry[2].append((x,y,z))
# select labels that are more than half in the mask
for label in labels:
if collection[label][0] / 2. >= collection[label][1]:
del collection[label]
# image_result = numpy.zeros_like(mask) this is eq. to mask.copy().fill(0), which directly applied does not allow access to the rows and colums: Why?
image_result = mask.copy()
image_result.fill(False)
# add labels to result mask
for label, data in list(collection.items()):
for point in data[2]:
image_result[point] = True
return image_result