From 8170467356da16c0b97d62fe2a2c98a1c12c4799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Sun, 22 May 2016 14:05:00 +0200 Subject: [PATCH 1/5] DOC: add crossref label and regionprops --- skimage/measure/_ccomp.pyx | 4 ++++ skimage/measure/_regionprops.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/skimage/measure/_ccomp.pyx b/skimage/measure/_ccomp.pyx index 77d237eb..b348d6b9 100644 --- a/skimage/measure/_ccomp.pyx +++ b/skimage/measure/_ccomp.pyx @@ -405,6 +405,10 @@ def label(input, neighbors=None, background=0, return_num=False, Number of labels, which equals the maximum label index and is only returned if return_num is `True`. + See Also + -------- + regionprops + Examples -------- >>> import numpy as np diff --git a/skimage/measure/_regionprops.py b/skimage/measure/_regionprops.py index bbe512ff..2d4eff59 100644 --- a/skimage/measure/_regionprops.py +++ b/skimage/measure/_regionprops.py @@ -490,6 +490,10 @@ def regionprops(label_image, intensity_image=None, cache=True): for prop in region: print(prop, region[prop]) + See Also + -------- + label + References ---------- .. [1] Wilhelm Burger, Mark Burge. Principles of Digital Image Processing: From c99ba1344cf073c9244eb6e766cc304f2aa6e104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Wed, 25 May 2016 20:48:52 +0200 Subject: [PATCH 2/5] MAINT: remove unused import --- skimage/measure/_regionprops.py | 1 - 1 file changed, 1 deletion(-) diff --git a/skimage/measure/_regionprops.py b/skimage/measure/_regionprops.py index 2d4eff59..a7bb3c8a 100644 --- a/skimage/measure/_regionprops.py +++ b/skimage/measure/_regionprops.py @@ -9,7 +9,6 @@ from . import _moments from functools import wraps -from collections import defaultdict __all__ = ['regionprops', 'perimeter'] From 07f753d081b832e2d2871dd2a8b102b77bbecd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Wed, 25 May 2016 20:50:42 +0200 Subject: [PATCH 3/5] MAINT: PEP8 --- skimage/measure/_label.py | 1 + skimage/measure/_regionprops.py | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/skimage/measure/_label.py b/skimage/measure/_label.py index 9dcefed4..a7709562 100644 --- a/skimage/measure/_label.py +++ b/skimage/measure/_label.py @@ -1,5 +1,6 @@ from ._ccomp import label as _label + def label(input, neighbors=None, background=None, return_num=False, connectivity=None): return _label(input, neighbors, background, return_num, connectivity) diff --git a/skimage/measure/_regionprops.py b/skimage/measure/_regionprops.py index a7bb3c8a..cf05ef6e 100644 --- a/skimage/measure/_regionprops.py +++ b/skimage/measure/_regionprops.py @@ -94,7 +94,8 @@ class _RegionProperties(object): if intensity_image is not None: if not intensity_image.shape == label_image.shape: - raise ValueError('Label and intensity image must have the same shape.') + raise ValueError('Label and intensity image must have the' + 'same shape.') self.label = label @@ -282,7 +283,8 @@ class _RegionProperties(object): @_cached @only2d def weighted_moments(self): - return _moments.moments_central(self._intensity_image_double(), 0, 0, 3) + return _moments.moments_central(self._intensity_image_double(), + 0, 0, 3) @_cached @only2d From 9992a4480baff6e82c42853d9f9df5572574eeb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Wed, 25 May 2016 21:17:44 +0200 Subject: [PATCH 4/5] MAINT: move docstring and merge cython functions --- skimage/measure/_ccomp.pyx | 137 +++++-------------------------------- skimage/measure/_label.py | 95 ++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 124 deletions(-) diff --git a/skimage/measure/_ccomp.pyx b/skimage/measure/_ccomp.pyx index b348d6b9..56f87bfb 100644 --- a/skimage/measure/_ccomp.pyx +++ b/skimage/measure/_ccomp.pyx @@ -8,21 +8,6 @@ from .._shared.utils import warn cimport numpy as cnp -""" -See also: - - Christophe Fiorio and Jens Gustedt, - "Two linear time Union-Find strategies for image processing", - Theoretical Computer Science 154 (1996), pp. 165-181. - - Kensheng Wu, Ekow Otoo and Arie Shoshani, - "Optimizing connected component labeling algorithms", - Paper LBNL-56864, 2005, - Lawrence Berkeley National Laboratory - (University of California), - http://repositories.cdlib.org/lbnl/LBNL-56864 - -""" DTYPE = np.intp @@ -357,114 +342,19 @@ def undo_reshape_array(arr, swaps): return reshaped -# Connected components search as described in Fiorio et al. -def label(input, neighbors=None, background=0, return_num=False, - connectivity=None): - r"""Label connected regions of an integer array. - - Two pixels are connected when they are neighbors and have the same value. - In 2D, they can be neighbors either in a 1- or 2-connected sense. - The value refers to the maximum number of orthogonal hops to consider a - pixel/voxel a neighbor:: - - 1-connectivity 2-connectivity diagonal connection close-up - - [ ] [ ] [ ] [ ] [ ] - | \ | / | <- hop 2 - [ ]--[x]--[ ] [ ]--[x]--[ ] [x]--[ ] - | / | \ hop 1 - [ ] [ ] [ ] [ ] - - Parameters - ---------- - input : ndarray of dtype int - Image to label. - neighbors : {4, 8}, int, optional - Whether to use 4- or 8-"connectivity". - In 3D, 4-"connectivity" means connected pixels have to share face, - whereas with 8-"connectivity", they have to share only edge or vertex. - **Deprecated, use ``connectivity`` instead.** - background : int, optional - Consider all pixels with this value as background pixels, and label - them as 0. By default, 0-valued pixels are considered as background - pixels. - return_num : bool, optional - Whether to return the number of assigned labels. - connectivity : int, optional - Maximum number of orthogonal hops to consider a pixel/voxel - as a neighbor. - Accepted values are ranging from 1 to input.ndim. If ``None``, a full - connectivity of ``input.ndim`` is used. - - Returns - ------- - labels : ndarray of dtype int - Labeled array, where all connected regions are assigned the - same integer value. - num : int, optional - Number of labels, which equals the maximum label index and is only - returned if return_num is `True`. - - See Also - -------- - regionprops - - Examples - -------- - >>> import numpy as np - >>> x = np.eye(3).astype(int) - >>> print(x) - [[1 0 0] - [0 1 0] - [0 0 1]] - >>> from skimage.measure import label - >>> print(label(x, connectivity=1)) - [[1 0 0] - [0 2 0] - [0 0 3]] - - >>> print(label(x, connectivity=2)) - [[1 0 0] - [0 1 0] - [0 0 1]] - - >>> print(label(x, background=-1)) - [[1 2 2] - [2 1 2] - [2 2 1]] - - >>> x = np.array([[1, 0, 0], - ... [1, 1, 5], - ... [0, 0, 0]]) - - >>> print(label(x)) - [[1 0 0] - [1 1 2] - [0 0 0]] - """ +def label_cython(input, neighbors=None, background=None, return_num=False, + connectivity=None): + # Connected components search as described in Fiorio et al. # We have to ensure that the shape of the input can be handled by the # algorithm the input if it is the case input_corrected, swaps = reshape_array(input) - # Do the labelling - res, ctr = _label(input_corrected, neighbors, background, connectivity) - - res_orig = undo_reshape_array(res, swaps) - - if return_num: - return res_orig, ctr - else: - return res_orig - - -# Connected components search as described in Fiorio et al. -def _label(input, neighbors=None, background=None, connectivity=None): cdef cnp.ndarray[DTYPE_t, ndim=1] data cdef cnp.ndarray[DTYPE_t, ndim=1] forest # Having data a 2D array slows down access considerably using linear # indices even when using the data_p pointer :-( - data = np.copy(input.flatten().astype(DTYPE)) + data = np.copy(input_corrected.flatten().astype(DTYPE)) forest = np.arange(data.size, dtype=DTYPE) cdef DTYPE_t *forest_p = forest.data @@ -473,12 +363,12 @@ def _label(input, neighbors=None, background=None, connectivity=None): cdef shape_info shapeinfo cdef bginfo bg - get_shape_info(input.shape, &shapeinfo) + get_shape_info(input_corrected.shape, &shapeinfo) get_bginfo(background, &bg) if neighbors is None and connectivity is None: # use the full connectivity by default - connectivity = input.ndim + connectivity = input_corrected.ndim elif neighbors is not None: DeprecationWarning("The argument 'neighbors' is deprecated, use " "'connectivity' instead") @@ -486,15 +376,15 @@ def _label(input, neighbors=None, background=None, connectivity=None): if neighbors == 4: connectivity = 1 elif neighbors == 8: - connectivity = input.ndim + connectivity = input_corrected.ndim else: raise ValueError("Neighbors must be either 4 or 8, got '%d'.\n" % neighbors) - if not 1 <= connectivity <= input.ndim: + if not 1 <= connectivity <= input_corrected.ndim: raise ValueError( "Connectivity below 1 or above %d is illegal." - % input.ndim) + % input_corrected.ndim) scanBG(data_p, forest_p, &shapeinfo, &bg) # the data are treated as degenerated 3D arrays if needed @@ -509,9 +399,14 @@ def _label(input, neighbors=None, background=None, connectivity=None): if data.dtype == np.int32: data = data.view(np.int32) - res = data.reshape(input.shape) + res = data.reshape(input_corrected.shape) - return res, ctr + res_orig = undo_reshape_array(res, swaps) + + if return_num: + return res_orig, ctr + else: + return res_orig cdef DTYPE_t resolve_labels(DTYPE_t *data_p, DTYPE_t *forest_p, diff --git a/skimage/measure/_label.py b/skimage/measure/_label.py index a7709562..d3f82dcb 100644 --- a/skimage/measure/_label.py +++ b/skimage/measure/_label.py @@ -1,8 +1,97 @@ -from ._ccomp import label as _label +from ._ccomp import label_cython as clabel +""" + References + ---------- + .. [1] Christophe Fiorio and Jens Gustedt, "Two linear time Union-Find + strategies for image processing", Theoretical Computer Science + 154 (1996), pp. 165-181. + + .. [2] Kensheng Wu, Ekow Otoo and Arie Shoshani, "Optimizing connected + component labeling algorithms", Paper LBNL-56864, 2005, + Lawrence Berkeley National Laboratory (University of California), + http://repositories.cdlib.org/lbnl/LBNL-56864 +""" + def label(input, neighbors=None, background=None, return_num=False, connectivity=None): - return _label(input, neighbors, background, return_num, connectivity) + r"""Label connected regions of an integer array. -label.__doc__ = _label.__doc__ + Two pixels are connected when they are neighbors and have the same value. + In 2D, they can be neighbors either in a 1- or 2-connected sense. + The value refers to the maximum number of orthogonal hops to consider a + pixel/voxel a neighbor:: + + 1-connectivity 2-connectivity diagonal connection close-up + + [ ] [ ] [ ] [ ] [ ] + | \ | / | <- hop 2 + [ ]--[x]--[ ] [ ]--[x]--[ ] [x]--[ ] + | / | \ hop 1 + [ ] [ ] [ ] [ ] + + Parameters + ---------- + input : ndarray of dtype int + Image to label. + neighbors : {4, 8}, int, optional + Whether to use 4- or 8-"connectivity". + In 3D, 4-"connectivity" means connected pixels have to share face, + whereas with 8-"connectivity", they have to share only edge or vertex. + **Deprecated, use ``connectivity`` instead.** + background : int, optional + Consider all pixels with this value as background pixels, and label + them as 0. By default, 0-valued pixels are considered as background + pixels. + return_num : bool, optional + Whether to return the number of assigned labels. + connectivity : int, optional + Maximum number of orthogonal hops to consider a pixel/voxel + as a neighbor. + Accepted values are ranging from 1 to input.ndim. If ``None``, a full + connectivity of ``input.ndim`` is used. + + Returns + ------- + labels : ndarray of dtype int + Labeled array, where all connected regions are assigned the + same integer value. + num : int, optional + Number of labels, which equals the maximum label index and is only + returned if return_num is `True`. + + See Also + -------- + regionprops + + + Examples + -------- + >>> import numpy as np + >>> x = np.eye(3).astype(int) + >>> print(x) + [[1 0 0] + [0 1 0] + [0 0 1]] + >>> print(label(x, connectivity=1)) + [[1 0 0] + [0 2 0] + [0 0 3]] + >>> print(label(x, connectivity=2)) + [[1 0 0] + [0 1 0] + [0 0 1]] + >>> print(label(x, background=-1)) + [[1 2 2] + [2 1 2] + [2 2 1]] + >>> x = np.array([[1, 0, 0], + ... [1, 1, 5], + ... [0, 0, 0]]) + >>> print(label(x)) + [[1 0 0] + [1 1 2] + [0 0 0]] + """ + return clabel(input, neighbors, background, return_num, connectivity) From ffc88e58e1dc644a6f7680585c40ecc0f7154ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Sun, 29 May 2016 15:49:28 +0200 Subject: [PATCH 5/5] DOC: clarify bbox #2116 --- skimage/measure/_regionprops.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/skimage/measure/_regionprops.py b/skimage/measure/_regionprops.py index cf05ef6e..08f6ed45 100644 --- a/skimage/measure/_regionprops.py +++ b/skimage/measure/_regionprops.py @@ -371,7 +371,9 @@ def regionprops(label_image, intensity_image=None, cache=True): **area** : int Number of pixels of region. **bbox** : tuple - Bounding box ``(min_row, min_col, max_row, max_col)`` + Bounding box ``(min_row, min_col, max_row, max_col)``. + Pixels belonging to the bounding box are in the half-open interval + ``[min_row; max_row)`` and ``[min_col; max_col)``. **centroid** : array Centroid coordinate tuple ``(row, col)``. **convex_area** : int