Skip to content

Commit

Permalink
ENH Add filter_labeled function
Browse files Browse the repository at this point in the history
This is a single call to filter out objects which do not match a set of
conditions (currently: bordering, min/max size; but the interface can be
easily expanded).
  • Loading branch information
luispedro committed Oct 13, 2015
1 parent e5a1b35 commit 0cc9b3c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
@@ -1,3 +1,6 @@
Version 1.4.0+
* Add filter_labeled function

Version 1.4.0 2015-07-08 by luispedro
* Add `short` argument to citation() function
* Add `max_iter` argument to thin() function
Expand Down
5 changes: 5 additions & 0 deletions docs/source/labeled.rst
Expand Up @@ -166,6 +166,11 @@ Now, we have ``24`` nuclei and ``relabeled`` goes from ``0`` (background) to ``2
imshow(relabeled)
show()

In mahotas after version ``1.4``, we can even make many of the same operations
with a single call to ``mh.labeled.filter_labeled``::

relabeled,n_left = mh.labeled.filter_labeled(labeled, remove_bordering=True, max_size=10000)


Borders
-------
Expand Down
43 changes: 43 additions & 0 deletions mahotas/labeled.py
Expand Up @@ -16,6 +16,7 @@
'borders',
'border',
'bwperim',
'filter_labeled',
'label',
'labeled_sum',
'labeled_max',
Expand Down Expand Up @@ -575,3 +576,45 @@ def bbox(f, as_slice=False):
if as_slice:
output = [tuple([slice(s,e) for s,e in r.reshape((-1,2))]) for r in output]
return output

def filter_labeled(labeled, remove_bordering=False, min_size=None, max_size=None):
'''Filter labeled regions based on a series of conditions
Parameters
----------
labeled : labeled array
remove_bordering : bool, optional
whether to remove regions that touch the border
min_size : int, optional
Minimum size (in pixels) of objects to keep (default is no minimum)
max_size : int, optional
Maximum size (in pixels) of objects to keep (default is no maximum)
Returns
-------
filtered : labeled array
nr : int
number of new labels
'''
from mahotas.labeled import remove_regions, labeled_size
import mahotas as mh
labeled = _as_labeled(labeled, labeled, 'filter_labeled')
if remove_bordering:
labeled = mh.labeled.remove_bordering(labeled)
labeled,nr = mh.labeled.relabel(labeled)
else:
nr = labeled.max()

to_keep = np.ones(nr+1, bool)

if min_size is not None or max_size is not None:
sizes = labeled_size(labeled)
if min_size:
to_keep &= (sizes >= min_size)
if max_size:
to_keep &= (sizes <= max_size)
to_keep[0] = True
to_remove = np.where(~to_keep)
labeled = remove_regions(labeled, to_remove)
labeled,nr = mh.labeled.relabel(labeled, inplace=True)
return labeled, nr
24 changes: 24 additions & 0 deletions mahotas/tests/test_labeled.py
Expand Up @@ -283,3 +283,27 @@ def nozeros_test(f):
f3 = np.array([f])
yield nozeros_test, f
yield nozeros_test, f3


def test_filter_labeled():

f = np.random.random(size=(256,256)) > .66
labeled, nr = mh.label(f)
no_change,no_nr = mh.labeled.filter_labeled(labeled)
assert no_nr == nr
assert np.all(no_change == labeled)

no_border, border_nr = mh.labeled.filter_labeled(labeled, remove_bordering=True)
assert nr > border_nr
assert not np.all(no_border == labeled)

min_size_3,nr3 = mh.labeled.filter_labeled(labeled, min_size=3)
assert nr > nr3
assert mh.labeled.labeled_size(min_size_3).min() == 3

max_size_3,_ = mh.labeled.filter_labeled(labeled, max_size=3)
assert mh.labeled.labeled_size(max_size_3)[1:].max() == 3


all_size_3,_ = mh.labeled.filter_labeled(labeled, max_size=3, min_size=3)
assert np.all(mh.labeled.labeled_size(all_size_3)[1:] == 3)

0 comments on commit 0cc9b3c

Please sign in to comment.