From c0c23968bf7cd893e28c9f771b0aa97ff1d48e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Scho=CC=88nberger?= Date: Sat, 14 Jul 2012 14:14:28 +0200 Subject: [PATCH] add perimeter measurement --- skimage/measure/__init__.py | 2 +- skimage/measure/_regionprops.py | 62 +++++++++++++++++++++-- skimage/measure/tests/test_regionprops.py | 4 ++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index 588ec74d..f5109698 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -1,3 +1,3 @@ from .find_contours import find_contours -from ._regionprops import regionprops +from ._regionprops import regionprops, perimeter from ._structural_similarity import structural_similarity diff --git a/skimage/measure/_regionprops.py b/skimage/measure/_regionprops.py index 6b8f6a3c..396c6bdd 100644 --- a/skimage/measure/_regionprops.py +++ b/skimage/measure/_regionprops.py @@ -10,6 +10,9 @@ from . import _moments __all__ = ['regionprops'] +STREL_4 = np.array([[0, 1, 0], + [1, 1, 1], + [0, 1, 0]]) STREL_8 = np.ones((3, 3), 'int8') PROPS = ( 'Area', @@ -36,7 +39,7 @@ PROPS = ( 'Moments', 'NormalizedMoments', 'Orientation', -# 'Perimeter', + 'Perimeter', # 'PixelIdxList', # 'PixelList', 'Solidity', @@ -122,6 +125,9 @@ def regionprops(label_image, properties=['Area', 'Centroid'], Angle between the X-axis and the major axis of the ellipse that has the same second-moments as the region. Ranging from `-pi/2` to `-pi/2` in counter-clockwise direction. + * Perimeter : float + Perimeter of object which approximates the contour as a line through + the centers of border pixels using a 4-connectivity. * Solidity : float Ratio of pixels in the region to pixels of the convex hull image. * WeightedCentralMoments : 3 x 3 ndarray @@ -210,8 +216,8 @@ def regionprops(label_image, properties=['Area', 'Centroid'], b = mu[1, 1] / mu[0, 0] c = mu[0, 2] / mu[0, 0] #: eigen values of inertia tensor - l1 = (a + c) / 2 + sqrt(4 * b**2 + (a - c)**2) / 2 - l2 = (a + c) / 2 - sqrt(4 * b**2 + (a - c)**2) / 2 + l1 = (a + c) / 2 + sqrt(4 * b ** 2 + (a - c) ** 2) / 2 + l2 = (a + c) / 2 - sqrt(4 * b ** 2 + (a - c) ** 2) / 2 # cached results which are used by several properties _filled_image = None @@ -297,6 +303,9 @@ def regionprops(label_image, properties=['Area', 'Centroid'], else: obj_props['Orientation'] = - 0.5 * atan(2 * b / (a - c)) + if 'Perimeter' in properties: + obj_props['Perimeter'] = perimeter(array, 4) + if 'Solidity' in properties: if _convex_image is None: _convex_image = convex_hull_image(array) @@ -350,3 +359,50 @@ def regionprops(label_image, properties=['Area', 'Centroid'], obj_props['WeightedNormalizedMoments'] = _wnu return props + + +def perimeter(image, neighbourhood=4): + """Calculate total perimeter of all objects in binary image. + + Parameters + ---------- + image : array + binary image + neighbourhood: 4 or 8, optional + neighbourhood connectivity for border pixel determination, default 4 + + Returns + ------- + perimeter : float + total perimeter of all objects in binary image + + References + ---------- + K. Benkrid, D. Crookes. Design and FPGA Implementation of a Perimeter + Estimator. The Queen's University of Belfast. + http://www.cs.qub.ac.uk/~d.crookes/webpubs/papers/perimeter.doc + """ + if neighbourhood == 4: + strel = STREL_4 + else: + strel = STREL_8 + eroded_image = ndimage.binary_erosion(image, strel) + border_image = image - eroded_image + + # perimeter contribution: corresponding values in convolved image + perimeter_weights = { + 1: (5, 7, 15, 17, 25, 27), + sqrt(2): (21, 33), + 1 + sqrt(2) / 2: (13, 23) + } + perimeter_image = ndimage.convolve(border_image, np.array([[10, 2, 10], + [ 2, 1, 2], + [10, 2, 10]])) + total_perimeter = 0 + for weight, values in perimeter_weights.items(): + num_values = 0 + for value in values: + num_values += np.sum(perimeter_image == value) + total_perimeter += num_values * weight + + return total_perimeter diff --git a/skimage/measure/tests/test_regionprops.py b/skimage/measure/tests/test_regionprops.py index b9b16dff..4408c3d1 100644 --- a/skimage/measure/tests/test_regionprops.py +++ b/skimage/measure/tests/test_regionprops.py @@ -194,6 +194,10 @@ def test_orientation(): # determined with MATLAB assert_almost_equal(orientation, 0.10446844651921) +def test_perimeter(): + perimeter = regionprops(SAMPLE, ['Perimeter'])[0]['Perimeter'] + assert_almost_equal(perimeter, 59.2132034355964) + def test_solidity(): solidity = regionprops(SAMPLE, ['Solidity'])[0]['Solidity'] # determined with MATLAB