From e182931f1563f7ce335a7a09ec515b765d8cc7c7 Mon Sep 17 00:00:00 2001 From: Stefan van der Walt Date: Thu, 8 May 2014 17:49:47 +0200 Subject: [PATCH] Move label to measure module (with deprecation). Warn that background parameter will default to 0 in v0.12. --- TODO.txt | 9 +++++++ doc/source/api_changes.txt | 1 - skimage/measure/__init__.py | 4 ++- skimage/morphology/__init__.py | 3 +-- skimage/morphology/ccomp.pyx | 26 +++++++++++++++----- skimage/morphology/tests/test_ccomp.py | 34 +++++++++++++++----------- 6 files changed, 53 insertions(+), 24 deletions(-) diff --git a/TODO.txt b/TODO.txt index bec8efe6..47d4ec90 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,3 +1,12 @@ +Remember to list any API changes below in `doc/source/api_changes.txt`. + +Version 0.12 +------------ +- Change `label` to mark background as 0, not -1, which is consistent with + SciPy's labelling. +- Remove `skimage.morphology.label` from `skimage.morphology.__init__`--it now + lives in `skimage.measure.label`. + Version 0.11 ------------ * Remove deprecated `reverse_map` parameter of `skimage.transform.warp` diff --git a/doc/source/api_changes.txt b/doc/source/api_changes.txt index 527c9fb0..0271bec0 100644 --- a/doc/source/api_changes.txt +++ b/doc/source/api_changes.txt @@ -24,4 +24,3 @@ Version 0.3 - Remove ``as_grey``, ``dtype`` keyword from ImageCollection - Remove ``dtype`` from imread - Generalise ImageCollection to accept a load_func - diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index d76e7a67..f7c0656a 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -8,6 +8,7 @@ from ._moments import moments, moments_central, moments_normalized, moments_hu from .profile import profile_line from .fit import LineModel, CircleModel, EllipseModel, ransac from .block import block_reduce +from ..morphology.ccomp import label __all__ = ['find_contours', @@ -28,4 +29,5 @@ __all__ = ['find_contours', 'marching_cubes', 'mesh_surface_area', 'correct_mesh_orientation', - 'profile_line'] + 'profile_line', + 'label'] diff --git a/skimage/morphology/__init__.py b/skimage/morphology/__init__.py index bee5ac13..5d2406e8 100644 --- a/skimage/morphology/__init__.py +++ b/skimage/morphology/__init__.py @@ -4,14 +4,13 @@ from .grey import (erosion, dilation, opening, closing, white_tophat, black_tophat) from .selem import (square, rectangle, diamond, disk, cube, octahedron, ball, octagon, star) -from .ccomp import label +from ._label import label from .watershed import watershed from ._skeletonize import skeletonize, medial_axis from .convex_hull import convex_hull_image, convex_hull_object from .greyreconstruct import reconstruction from .misc import remove_small_objects - __all__ = ['binary_erosion', 'binary_dilation', 'binary_opening', diff --git a/skimage/morphology/ccomp.pyx b/skimage/morphology/ccomp.pyx index 91e2611c..2d2f5b13 100644 --- a/skimage/morphology/ccomp.pyx +++ b/skimage/morphology/ccomp.pyx @@ -4,6 +4,7 @@ #cython: wraparound=False import numpy as np +import warnings cimport numpy as cnp @@ -82,7 +83,7 @@ cdef inline void link_bg(DTYPE_t *forest, DTYPE_t n, DTYPE_t *background_node): # Connected components search as described in Fiorio et al. -def label(input, DTYPE_t neighbors=8, DTYPE_t background=-1, return_num=False): +def label(input, DTYPE_t neighbors=8, background=None, return_num=False): """Label connected regions of an integer array. Two pixels are connected when they are neighbors and have the same value. @@ -104,7 +105,10 @@ def label(input, DTYPE_t neighbors=8, DTYPE_t background=-1, return_num=False): Whether to use 4- or 8-connectivity. background : int Consider all pixels with this value as background pixels, and label - them as -1. + them as -1. (Note: background pixels will be labeled as 0 starting with + version 0.12). + return_num : bool + Whether to return the number of assigned labels. Returns ------- @@ -157,17 +161,27 @@ def label(input, DTYPE_t neighbors=8, DTYPE_t background=-1, return_num=False): cdef DTYPE_t i, j + cdef DTYPE_t background_val + + if background is None: + background_val = -1 + warnings.warn(DeprecationWarning( + 'The default value for `background` will change to 0 in v0.12' + )) + else: + background_val = background + cdef DTYPE_t background_node = -999 if neighbors != 4 and neighbors != 8: raise ValueError('Neighbors must be either 4 or 8.') # Initialize the first row - if data[0, 0] == background: + if data[0, 0] == background_val: link_bg(forest_p, 0, &background_node) for j in range(1, cols): - if data[0, j] == background: + if data[0, j] == background_val: link_bg(forest_p, j, &background_node) if data[0, j] == data[0, j-1]: @@ -175,7 +189,7 @@ def label(input, DTYPE_t neighbors=8, DTYPE_t background=-1, return_num=False): for i in range(1, rows): # Handle the first column - if data[i, 0] == background: + if data[i, 0] == background_val: link_bg(forest_p, i * cols, &background_node) if data[i, 0] == data[i-1, 0]: @@ -186,7 +200,7 @@ def label(input, DTYPE_t neighbors=8, DTYPE_t background=-1, return_num=False): join_trees(forest_p, i*cols, (i-1)*cols + 1) for j in range(1, cols): - if data[i, j] == background: + if data[i, j] == background_val: link_bg(forest_p, i * cols + j, &background_node) if neighbors == 8: diff --git a/skimage/morphology/tests/test_ccomp.py b/skimage/morphology/tests/test_ccomp.py index 1169be85..34de8fb9 100644 --- a/skimage/morphology/tests/test_ccomp.py +++ b/skimage/morphology/tests/test_ccomp.py @@ -2,7 +2,7 @@ import numpy as np from numpy.testing import assert_array_equal, run_module_suite from skimage.morphology import label - +from warnings import catch_warnings class TestConnectedComponents: def setup(self): @@ -25,7 +25,9 @@ class TestConnectedComponents: def test_random(self): x = (np.random.random((20, 30)) * 5).astype(np.int) - labels = label(x) + with catch_warnings(DeprecationWarning): + labels = label(x) + n = labels.max() for i in range(n): values = x[labels == i] @@ -35,27 +37,29 @@ class TestConnectedComponents: x = np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) - assert_array_equal(label(x), - x) + with catch_warnings(DeprecationWarning): + assert_array_equal(label(x), x) def test_4_vs_8(self): x = np.array([[0, 1], [1, 0]], dtype=int) - assert_array_equal(label(x, 4), - [[0, 1], - [2, 3]]) - assert_array_equal(label(x, 8), - [[0, 1], - [1, 0]]) + with catch_warnings(DeprecationWarning): + assert_array_equal(label(x, 4), + [[0, 1], + [2, 3]]) + assert_array_equal(label(x, 8), + [[0, 1], + [1, 0]]) def test_background(self): x = np.array([[1, 0, 0], [1, 1, 5], [0, 0, 0]]) - assert_array_equal(label(x), [[0, 1, 1], - [0, 0, 2], - [3, 3, 3]]) + with catch_warnings(DeprecationWarning): + assert_array_equal(label(x), [[0, 1, 1], + [0, 0, 2], + [3, 3, 3]]) assert_array_equal(label(x, background=0), [[0, -1, -1], @@ -87,7 +91,9 @@ class TestConnectedComponents: [0, 0, 6], [5, 5, 5]]) - assert_array_equal(label(x, return_num=True)[1], 4) + with catch_warnings(DeprecationWarning): + assert_array_equal(label(x, return_num=True)[1], 4) + assert_array_equal(label(x, background=0, return_num=True)[1], 3)